first commit
This commit is contained in:
88
httpdl/single_test.go
Normal file
88
httpdl/single_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package httpdl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/hanbok/got/download"
|
||||
)
|
||||
|
||||
// TestSingleShortBody verifies that a single-stream transfer whose body ends
|
||||
// before the declared Content-Length is reported as an error (a retryable short
|
||||
// read) rather than a false success (item [1]). A proxy that closes early must
|
||||
// not leave the download marked Complete.
|
||||
func TestSingleShortBody(t *testing.T) {
|
||||
const declared = 1000
|
||||
// Hijack the connection so we can declare a long Content-Length but write
|
||||
// only a few bytes and then close — exactly the early-close a re-chunking
|
||||
// proxy produces. httptest's normal writer would otherwise flag the mismatch
|
||||
// on its own terms; hijacking gives us full control of the wire bytes.
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
hj, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
t.Errorf("server does not support hijacking")
|
||||
return
|
||||
}
|
||||
conn, _, err := hj.Hijack()
|
||||
if err != nil {
|
||||
t.Errorf("hijack: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
fmt.Fprintf(conn, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n", declared)
|
||||
conn.Write([]byte("short")) // only 5 of the promised 1000 bytes
|
||||
// closing the connection now is the early EOF
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
dir := t.TempDir()
|
||||
out := filepath.Join(dir, "file.bin")
|
||||
|
||||
d := New([]string{srv.URL + "/file.bin"}, Config{
|
||||
Dir: dir,
|
||||
Out: "file.bin",
|
||||
MaxConnPerServer: 1,
|
||||
Tries: 1, // a single attempt so the retryable short read surfaces, not loops
|
||||
UserAgent: "got-test",
|
||||
})
|
||||
|
||||
err := d.single(context.Background(), out)
|
||||
if err == nil {
|
||||
t.Fatal("single() returned nil for a body shorter than Content-Length; want an error")
|
||||
}
|
||||
if d.Stat().Status == download.Complete {
|
||||
t.Fatalf("status = Complete after a short body; want not Complete")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSingleCompleteFullBody is the positive control: a body that matches its
|
||||
// Content-Length succeeds. This guards against the short-body check rejecting a
|
||||
// legitimately complete stream.
|
||||
func TestSingleCompleteFullBody(t *testing.T) {
|
||||
const body = "the whole thing"
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Length", fmt.Sprint(len(body)))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(body))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
dir := t.TempDir()
|
||||
out := filepath.Join(dir, "file.bin")
|
||||
|
||||
d := New([]string{srv.URL + "/file.bin"}, Config{
|
||||
Dir: dir,
|
||||
Out: "file.bin",
|
||||
MaxConnPerServer: 1,
|
||||
Tries: 1,
|
||||
UserAgent: "got-test",
|
||||
})
|
||||
|
||||
if err := d.single(context.Background(), out); err != nil {
|
||||
t.Fatalf("single() of a full body returned %v; want nil", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user