Cover mid-stream v2 fetch cancellation · Entire

Cover mid-stream v2 fetch cancellation

d0f0dfamain·

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

Sessions

52544e8d948cView transcript

Changes

2

434 unmodified lines

435
436
437
438
438
439
440
441
442

434 unmodified lines

- 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.
- Injected checkpoint pack failure after partial batched progress is now covered end-to-end, including successful resume on retry.
- Some harder transport-interruption and malformed mid-stream failure paths still remain.
- `fetchToStoreV2` now also has direct coverage for cancellation after response parsing has started.
- Some harder transport-interruption and malformed mid-stream failure paths still remain, but the remaining gap is narrower than the original list.

### 22. No benchmark coverage for the expensive paths

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

162 unmodified lines

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
275 unmodified lines

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536

162 unmodified lines

func (f closerFunc) Close() error { return f() }

type blockingPacketBody struct {
    ctx         context.Context
    startedRead chan<- struct{}
    first       []byte
    stage       int
    closed      bool
}

func (b *blockingPacketBody) Read(p []byte) (int, error) {
    switch b.stage {
    case 0:
        b.stage = 1
        return copy(p, b.first), nil
    default:
        select {
        case b.startedRead <- struct{}:{}
        default:
        }
        <-b.ctx.Done()
        return 0, b.ctx.Err()
    }
}

func (b *blockingPacketBody) Close() error {
    b.closed = true
    return nil
}

func TestDecodeV2LSRefs(t *testing.T) {
    // Build a valid ls-refs response:
    // Each line: "<hash> <refname>\n"
275 unmodified lines

}

func TestFetchToStoreV2ContextCanceledMidStream(t *testing.T) {
    startedRead := make(chan struct{}, 1)
    ep, err := transport.NewEndpoint("https://example.com/repo.git")
    if err != nil {
        t.Fatalf("parse endpoint: %v", err)
    }

ctx, cancel := context.WithCancel(context.Background())
    conn := NewConn(ep, "source", nil, roundTripperFunc(func(req *http.Request) (*http.Response, error) {
        body := &blockingPacketBody{
            ctx:         req.Context(),
            startedRead: startedRead,
            first:       []byte(FormatPktLine("packfile\n")),
        }
        return &http.Response{
            StatusCode: http.StatusOK,
            Request:    req,
            Body:       body,
        }, nil
    }))

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"),
        },
    }

done := make(chan error, 1)
    go func() {
        done <- fetchToStoreV2(ctx, memory.NewStorage(), conn, caps, desired, nil)
    })

select {
    case <-startedRead:
    case <-time.After(2 * time.Second):
        t.Fatal("response body was not consumed before timeout")
    }
    cancel()

select {
    case err = <-done:
    case <-time.After(2 * time.Second):
        t.Fatal("fetchToStoreV2 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 {