test(gopher): add resume coverage for typeInformation

This commit is contained in:
2026-06-30 11:55:52 +02:00
parent d3b6451472
commit 3384e2b344
+100
View File
@@ -494,3 +494,103 @@ func TestGopherResumeIgnoredWhenWriterSet(t *testing.T) {
t.Error("Output file should not be created when Writer is set") t.Error("Output file should not be created when Writer is set")
} }
} }
// TestGopherResumeInformation verifies that resume machinery works for the
// informational (type i) response path, which is also routed through
// downloadText. Informational lines are passed through verbatim (no
// metadata strip), so the resume offset matches the raw line length
// including trailing CR/LF.
func TestGopherResumeInformation(t *testing.T) {
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer listener.Close()
port := listener.Addr().(*net.TCPAddr).Port
cancelReady := make(chan struct{})
connReady := make(chan struct{})
go func() {
for i := 0; i < 2; i++ {
conn, lerr := listener.Accept()
if lerr != nil {
return
}
r := bufio.NewReader(conn)
r.ReadString('\n')
if i == 0 {
// First half: send two info lines, then wait
// for the client to cancel before closing.
conn.Write([]byte("iFirst line.\r\n"))
conn.Write([]byte("iSecond line.\r\n"))
<-cancelReady
conn.Close()
connReady <- struct{}{}
} else {
// Second half: full body.
conn.Write([]byte("iFirst line.\r\n"))
conn.Write([]byte("iSecond line.\r\n"))
conn.Write([]byte(".\r\n"))
conn.Close()
}
}
}()
tmp := t.TempDir()
outPath := tmp + "/info.txt"
proto := NewProtocol()
u, _ := url.Parse("gopher://127.0.0.1:" + strconv.Itoa(port) + "/info")
progress := make(chan int64, 1)
ctx1, cancel1 := context.WithCancel(context.Background())
errCh := make(chan error, 1)
go func() {
_, dlErr := proto.Download(ctx1, &core.DownloadRequest{
URL: u,
Output: outPath,
ProgressCallback: func(current, total int64, speed float64) {
select {
case progress <- current:
default:
}
},
})
errCh <- dlErr
}()
<-progress
cancel1()
cancelReady <- struct{}{}
<-connReady
if dlErr := <-errCh; dlErr == nil {
t.Fatal("expected error from cancelled context")
}
// Resume should append the missing bytes. For informational lines
// we do not strip metadata, so the output preserves the server CR/LF.
result, resErr := proto.Download(context.Background(), &core.DownloadRequest{
URL: u,
Output: outPath,
Resume: true,
})
if resErr != nil {
t.Fatalf("resume download failed: %v", resErr)
}
if !result.Resumed {
t.Error("expected Resumed=true")
}
if result.ContentType != "text/plain" {
t.Errorf("ContentType = %q, want text/plain", result.ContentType)
}
data, _ := os.ReadFile(outPath)
// Informational lines are passed through verbatim: the 'i' item-type
// prefix and CR/LF framing from the server survive into the output.
want := "iFirst line.\r\niSecond line.\r\n"
if string(data) != want {
t.Errorf("content = %q, want %q", string(data), want)
}
if output.FileExists(outPath + output.ResumeMetaFileSuffix) {
t.Error("expected .goget.meta to be deleted after successful resume")
}
}