Cover mid-stream push failures in bootstrap · Entire
Cover mid-stream push failures in bootstrap
7b26009→main·
Soph·3mo ago·2 files·+133 added/-1 removed
Sessions
a01557bd71c2View transcript
Changes
2
- docs
- Mrewrite-issue-list.md+2/-1
- internal/syncer
- Mintegration_test.go+131
446 unmodified lines
446 unmodified lines
- `fetchToStoreV2` now also has direct coverage for cancellation after response parsing has started.
- V1 and v2 fetch paths now also have direct parser-level coverage for malformed sideband framing after a valid response prelude, both for returned streaming readers and for v2 fetch-to-store cleanup.
- Syncer integration coverage now also includes both v1 and v2 fetch failure and cancellation after a valid fetch response has already started streaming, using the in-memory smart-HTTP harness rather than only protocol-unit stubs.
- The remaining gap is now mostly around rarer transport interruption shapes on push/stream teardown rather than missing started-stream fetch coverage.
- Bootstrap integration coverage now also includes receive-pack cancellation and dropped-connection failures after the target has already started consuming a streamed push body.
- The remaining gap is now mostly around rarer teardown/reporting variants rather than missing started-stream fetch or push interruption coverage.
### 22. No benchmark coverage for the expensive paths
Mdocs/rewrite-issue-list.md+2/-1
388 unmodified lines
388 unmodified lines
}
}
func TestBootstrap_IntegrationPushCanceledMidStreamFails(t *testing.T) {
sourceRepo, sourceFS := newSourceRepo(t)
makeLargeCommits(t, sourceRepo, sourceFS, 2, 200_000)
targetRepo, err := git.Init(memory.NewStorage())
if err != nil {
t.Fatalf("init target repo: %v", err)
}
started := make(chan struct{}, 1)
release := make(chan struct{})
sourceServer := newSmartHTTPRepoServerV2(t, sourceRepo)
targetServer := newSmartHTTPRepoServer(t, targetRepo)
targetServer.receivePackRaw = func(w http.ResponseWriter, r *http.Request) bool {
defer r.Body.Close()
buf := make([]byte, 32)
n, err := r.Body.Read(buf)
if n == 0 && err != nil {
t.Fatalf("expected streamed push body bytes before cancellation, got err=%v", err)
}
select {
case started <- struct{}{}:
default:
}
<-release
_, _ = r.Body.Read(buf)
return true
}
defer sourceServer.Close()
defer targetServer.Close()
ctx, cancel := context.WithCancel(context.Background())
done := make(chan error, 1)
go func() {
_, err := Bootstrap(ctx, Config{
Source: Endpoint{URL: sourceServer.RepoURL()},
Target: Endpoint{URL: targetServer.RepoURL()},
})
done <- err
}()
select {
case <-started:
case <-time.After(2 * time.Second):
t.Fatal("expected receive-pack body consumption before cancellation")
}
cancel()
close(release)
select {
case err = <-done:
case <-time.After(2 * time.Second):
t.Fatal("expected bootstrap to return after cancellation")
}
if err == nil {
t.Fatal("expected cancellation error")
}
if !errors.Is(err, context.Canceled) {
t.Fatalf("expected context.Canceled, got %v", err)
}
}
func TestBootstrap_IntegrationPushConnectionDroppedMidStreamFails(t *testing.T) {
sourceRepo, sourceFS := newSourceRepo(t)
makeLargeCommits(t, sourceRepo, sourceFS, 2, 200_000)
targetRepo, err := git.Init(memory.NewStorage())
if err != nil {
t.Fatalf("init target repo: %v", err)
}
started := make(chan struct{}, 1)
sourceServer := newSmartHTTPRepoServerV2(t, sourceRepo)
targetServer := newSmartHTTPRepoServer(t, targetRepo)
targetServer.receivePackRaw = func(w http.ResponseWriter, r *http.Request) bool {
defer r.Body.Close()
buf := make([]byte, 32)
n, err := r.Body.Read(buf)
if n == 0 && err != nil {
t.Fatalf("expected streamed push body bytes before disconnect, got err=%v", err)
}
select {
case started <- struct{}{}:
default:
}
hj, ok := w.(http.Hijacker)
if !ok {
t.Fatal("expected hijacker")
}
conn, _, err := hj.Hijack()
if err != nil {
t.Fatalf("hijack receive-pack connection: %v", err)
}
_ = conn.Close()
return true
}
defer sourceServer.Close()
defer targetServer.Close()
done := make(chan error, 1)
go func() {
_, err := Bootstrap(context.Background(), Config{
Source: Endpoint{URL: sourceServer.RepoURL()},
Target: Endpoint{URL: targetServer.RepoURL()},
})
done <- err
}()
select {
case <-started:
case <-time.After(2 * time.Second):
t.Fatal("expected receive-pack body consumption before disconnect")
}
select {
case err = <-done:
case <-time.After(2 * time.Second):
t.Fatal("expected bootstrap to return after dropped connection")
}
if err == nil {
t.Fatal("expected push failure after dropped connection")
}
}
func TestRun_IntegrationPlanSuggestsBootstrapOnEmptyTarget(t *testing.T) {
sourceRepo, sourceFS := newSourceRepo(t)
makeCommits(t, sourceRepo, sourceFS, 2)
1224 unmodified lines
receivePackHook func(*packp.UpdateRequests, bool) *packp.ReportStatus
uploadPackRaw func(http.ResponseWriter, *http.Request, []byte) bool
uploadPackV2FetchRaw func(http.ResponseWriter, v2TestCommandRequest, []byte) bool
receivePackRaw func(http.ResponseWriter, *http.Request) bool
mu sync.Mutex
metrics []exchangeMetric
335 unmodified lines
}
func (s *smartHTTPRepoServer) handleReceivePack(w http.ResponseWriter, r *http.Request) {
if s.receivePackRaw != nil && s.receivePackRaw(w, r) {
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)