Cover v2 fetch cancellation behavior · Entire

Cover v2 fetch cancellation behavior

579d626main·

Soph·3mo ago·2 files·+53 added/-1 removed

Sessions

fea91c44dc0dView transcript

[?
Can you take a look at the go code (wasm) in /Users/soph/Work/entire/devenv/entire-io-worktree1 based a bit on that I wonder if something like this can be build:Codex·GPT-5.4·1 step](/content/gh/entireio/git-sync/session/019d6d29-8cf7-7fe3-adc9-8c3e4d9d5603#timeline-fea91c44dc0d/index.html)

Changes

2

431 unmodified lines

432
433
434
435
435
436
437
438

431 unmodified lines

Current rewrite note:
- Some of these are now covered, including empty source repo, tag force-retarget, duplicate/conflicting mappings, and tag creation when target objects already exist.
- Batched lightweight-tag creation without an extra pack is now covered directly.
- Basic context cancellation coverage now exists.
- Basic context cancellation coverage now exists for probe and both v1/v2 source fetch paths.
- Batched bootstrap resume mismatch and final-tip cutover paths now have direct integration coverage.
- Batched bootstrap reruns now also cover the "target ref already created, temp ref cleanup still pending" recovery path.
- Injected temp-ref delete failure during batched cutover is now covered end-to-end, including successful recovery on retry.

Mdocs/rewrite-issue-list.md+1/-1

303 unmodified lines

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361

303 unmodified lines

}
}

func TestFetchPackV2ContextCanceled(t *testing.T) {
    started := make(chan struct{}, 1)
    ep, err := transport.NewEndpoint("https://example.com/repo.git")
    if err != nil {
        t.Fatalf("parse endpoint: %v", err)
    }
    conn := NewConn(ep, "source", nil, roundTripperFunc(func(req *http.Request) (*http.Response, error) {
        started <- struct{}{}
        <-req.Context().Done()
        return nil, req.Context().Err()
    }))

caps := &V2Capabilities{
        Caps: map[string]string{
            "fetch": "",
        },
    }
    desired := map[plumbing.ReferenceName]DesiredRef{
        plumbing.NewBranchReferenceName("main"): {
            SourceRef:  plumbing.NewBranchReferenceName("main"),
            TargetRef:  plumbing.NewBranchReferenceName("main"),
            SourceHash: plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
        },
    }

ctx, cancel := context.WithCancel(context.Background())
    done := make(chan error, 1)
    go func() {
        _, err := fetchPackV2(ctx, conn, caps, desired, nil)
        done <- err
    }()

select {
    case <-started:
    case <-time.After(2 * time.Second):
        t.Fatal("request did not reach server before timeout")
    }
    cancel()

select {
    case err = <-done:
    case <-time.After(2 * time.Second):
        t.Fatal("fetchPackV2 did not 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 TestFetchPackV1ClosesBodyOnDecodeError(t *testing.T) {
    ep, err := transport.NewEndpoint("https://example.com/repo.git")
    if err != nil {