# Add batched bootstrap resume edge-case coverage

`4b7a223`→[main](/content/gh/entireio/git-sync/commits/main/index.html)·

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

## Sessions

e391e5e1f4c9View transcript

### Changes

- docs
  - Mrewrite-issue-list.md+3/-1
- internal/syncer
  - Mintegration\_test.go+121

```
414 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.
- Basic context cancellation coverage now exists, but in-flight cancellation and some harder batch-failure/cutover paths still need stronger coverage.
- Basic context cancellation coverage now exists.
- Batched bootstrap resume mismatch and final-tip cutover paths now have direct integration coverage.
- Some harder batch-failure injection and partial cutover failure paths still remain.

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

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

```
32 unmodified lines

```go
package syncer

import (
	"github.com/soph/git-sync/internal/auth"
	"github.com/soph/git-sync/internal/gitproto"
	"github.com/soph/git-sync/internal/planner"
	bstrap "github.com/soph/git-sync/internal/strategy/bootstrap"
)

const testBranch = "master"

func TestBootstrap_IntegrationBatchedResumeMismatchFails(t *testing.T) {
	sourceRepo, sourceFS := newSourceRepo(t)
	makeLargeCommits(t, sourceRepo, sourceFS, 5, 200_000)

unrelatedRepo, unrelatedFS := newSourceRepo(t)
	makeCommits(t, unrelatedRepo, unrelatedFS, 1)
	unrelatedHead, err := unrelatedRepo.Reference(plumbing.NewBranchReferenceName(testBranch), true)
	if err != nil {
		t.Fatalf("resolve unrelated head: %v", err)
	}

targetRepo, err := git.Init(memory.NewStorage(), nil)
	if err != nil {
		t.Fatalf("init target repo: %v", err)
	}
	if err := copyRefsAndObjects(unrelatedRepo.Storer, targetRepo.Storer, nil); err != nil {
		t.Fatalf("copy unrelated objects: %v", err)
	}
	targetHead := unrelatedHead
	tempRef := planner.BootstrapTempRef(plumbing.NewBranchReferenceName(testBranch))
	if err := targetRepo.Storer.SetReference(plumbing.NewHashReference(tempRef, targetHead.Hash())); err != nil {
		t.Fatalf("set temp ref: %v", err)
	}

sourceServer := newSmartHTTPRepoServerV2(t, sourceRepo)
	targetServer := newSmartHTTPRepoServer(t, targetRepo)
	defer sourceServer.Close()
	defer targetServer.Close()

cfg := Config{
		Source:            Endpoint{URL: sourceServer.RepoURL()},
		Target:            Endpoint{URL: targetServer.RepoURL()},
		ProtocolMode:      protocolModeAuto,
		BatchMaxPackBytes: 350_000,
	}

s, err := newSession(context.Background(), cfg, false)
	if err != nil {
		t.Fatalf("new session: %v", err)
	}
	desired, _, err := planner.BuildDesiredRefs(s.sourceRefMap, planConfig(cfg))
	if err != nil {
		t.Fatalf("build desired refs: %v", err)
	}
	ref := desired[plumbing.NewBranchReferenceName(testBranch)]
	checkpoints, err := bstrap.PlanCheckpoints(context.Background(), bstrap.Params{
		SourceConn:    s.sourceConn,
		SourceService: s.sourceService,
		BatchMaxPack:  cfg.BatchMaxPackBytes,
	}, ref)
	if err != nil {
		t.Fatalf("plan checkpoints: %v", err)
	}
	if len(checkpoints) == 0 {
		t.Fatal("expected checkpoints for batched bootstrap")
	}
	for _, checkpoint := range checkpoints {
		if checkpoint == targetHead.Hash() {
			t.Fatalf("expected unrelated temp ref hash, got checkpoint collision at %s", checkpoint)
		}
	}

_, err = Bootstrap(context.Background(), cfg)
	if err == nil {
		t.Fatal("expected batched bootstrap resume mismatch to fail")
	}
	if !strings.Contains(err.Error(), "does not match any planned checkpoint") {
		t.Fatalf("unexpected error: %v", err)
	}
}

func TestBootstrap_IntegrationBatchedResumeAtFinalTipCutsOver(t *testing.T) {
	sourceRepo, sourceFS := newSourceRepo(t)
	makeLargeCommits(t, sourceRepo, sourceFS, 5, 200_000)
	sourceHead, err := sourceRepo.Reference(plumbing.NewBranchReferenceName(testBranch), true)
	if err != nil {
		t.Fatalf("resolve source head: %v", err)
	}

targetRepo, err := git.Init(memory.NewStorage(), nil)
	if err != nil {
		t.Fatalf("init target repo: %v", err)
	}
	if err := copyRefsAndObjects(sourceRepo.Storer, targetRepo.Storer, nil); err != nil {
		t.Fatalf("copy source objects: %v", err)
	}
	tempRef := planner.BootstrapTempRef(plumbing.NewBranchReferenceName(testBranch))
	if err := targetRepo.Storer.SetReference(plumbing.NewHashReference(tempRef, sourceHead.Hash())); err != nil {
		t.Fatalf("set temp ref: %v", err)
	}

result, err := Bootstrap(context.Background(), Config{
		Source:            Endpoint{URL: sourceServer.RepoURL()},
		Target:            Endpoint{URL: targetServer.RepoURL()},
		ProtocolMode:      protocolModeAuto,
		BatchMaxPackBytes: 350_000,
	})
	if err != nil {
		t.Fatalf("batched bootstrap final-tip cutover failed: %v", err)
	}
	if !result.Relay || result.RelayMode != "bootstrap-batch" {
		t.Fatalf("expected batched bootstrap result, got %+v", result)
	}
	targetHead, err := targetRepo.Reference(plumbing.NewBranchReferenceName(testBranch), true)
	if err != nil {
		t.Fatalf("resolve target head: %v", err)
	}
	if targetHead.Hash() != sourceHead.Hash() {
		t.Fatalf("expected target head %s, got %s", sourceHead.Hash(), targetHead.Hash())
	}
	if _, err := targetRepo.Reference(tempRef, true); err == nil {
		t.Fatalf("expected temp ref %s to be deleted", tempRef)
	}
}

func TestBootstrap_IntegrationBranchMapping(t *testing.T) {
	sourceRepo, sourceFS := newSourceRepo(t)
	makeCommits(t, sourceRepo, sourceFS, 3)
```
