# Add materialized object handling examples

`359d4e9`→[main](/content/gh/entireio/git-sync/commits/main/index.html) ·  Soph · 3mo ago · 1 file · +132 added/-0 removed

## Sessions

c00c3abb8037 View transcript

## Changes

1

- internal/strategy/materialized

- materialized_test.go +132

```go
package materialized

import (
	"context"
	"testing"

"github.com/go-git/go-git/v6/plumbing"
	"github.com/go-git/go-git/v6/plumbing/object"
	"github.com/go-git/go-git/v6/plumbing/storer"

"github.com/soph/git-sync/internal/convert"
	"github.com/soph/git-sync/internal/gitproto"
	"github.com/soph/git-sync/internal/planner"
	"github.com/soph/git-sync/internal/syncertest"
)

func TestPlansToPushPlans(t *testing.T) {
	// ... (function contents)
}

func TestCollectObjectClosureForBranchUpdateExample(t *testing.T) {
	repo, fs := syncertest.NewMemoryRepo(t)
	syncertest.MakeCommits(t, repo, fs, 1)

head, err := repo.Reference(plumbing.NewBranchReferenceName("master"), true)
	if err != nil {
		t.Fatalf("resolve head: %v", err)
	}

exec := executor{
		params: Params{
			Store: repo.Storer,
			PushPlans: []planner.BranchPlan{{
				TargetRef:  plumbing.NewBranchReferenceName("master"),
				SourceHash: head.Hash(),
				Action:     planner.ActionCreate,
				Kind:       planner.RefKindBranch,
			},},
		},
	}

hashes, err := exec.collectObjectClosure()
	if err != nil {
		t.Fatalf("collectObjectClosure: %v", err)
	}
	if len(hashes) < 3 {
		t.Fatalf("expected commit/tree/blob closure, got %d objects: %v", len(hashes), hashes)
	}
	if !containsHash(hashes, head.Hash()) {
		t.Fatalf("expected closure to include commit %s", head.Hash())
	}
}

func TestCollectObjectClosureStopsAtTargetHaveExample(t *testing.T) {
	repo, fs := syncertest.NewMemoryRepo(t)
	syncertest.MakeCommits(t, repo, fs, 2)

head, err := repo.Reference(plumbing.NewBranchReferenceName("master"), true)
	if err != nil {
		t.Fatalf("resolve head: %v", err)
	}
	headCommit, err := object.GetCommit(repo.Storer, head.Hash())
	if err != nil {
		t.Fatalf("load head commit: %v", err)
	}
	if len(headCommit.ParentHashes) != 1 {
		t.Fatalf("expected single-parent history, got %d parents", len(headCommit.ParentHashes))
	}
	parent := headCommit.ParentHashes[0]

exec := executor{
		params: Params{
			Store: repo.Storer,
			TargetRefs: map[plumbing.ReferenceName]plumbing.Hash{
				plumbing.NewBranchReferenceName("master"): parent,
			},
			PushPlans: []planner.BranchPlan{{
				TargetRef:  plumbing.NewBranchReferenceName("master"),
				TargetHash: parent,
				SourceHash: head.Hash(),
				Action:     planner.ActionUpdate,
				Kind:       planner.RefKindBranch,
			},},
		},
	}

hashes, err := exec.collectObjectClosure()
	if err != nil {
		t.Fatalf("collectObjectClosure: %v", err)
	}
	if len(hashes) == 0 {
		t.Fatal("expected new objects for branch update")
	}
	if containsHash(hashes, parent) {
		t.Fatalf("expected closure to stop at target have %s, got %v", parent, hashes)
	}
	if !containsHash(hashes, head.Hash()) {
		t.Fatalf("expected closure to include new tip %s", head.Hash())
	}
}

func TestExecuteDeleteOnlyIsRefOnlyExample(t *testing.T) {
	var gotCmds []gitproto.PushCommand
	var gotHashes []plumbing.Hash

err := Execute(context.Background(), Params{
		PushPlans: []planner.BranchPlan{{
			TargetRef:  plumbing.NewBranchReferenceName("old"),
			TargetHash: plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
			Action:     planner.ActionDelete,
			Kind:       planner.RefKindBranch,
		}},
		TargetPusher: fakeTargetPusher{
			pushObjects: func(_ context.Context, cmds []gitproto.PushCommand, _ storer.Storer, hashes []plumbing.Hash) error {
				gotCmds = append([]gitproto.PushCommand(nil), cmds...)
				gotHashes = append([]plumbing.Hash(nil), hashes...)
				return nil
			},
		},
	})
	if err != nil {
		t.Fatalf("Execute() error = %v", err)
	}
	if len(gotCmds) != 1 || !gotCmds[0].Delete {
		t.Fatalf("expected single delete command, got %+v", gotCmds)
	}
	if len(gotHashes) != 0 {
		t.Fatalf("expected delete-only materialized push to need no objects, got %v", gotHashes)
	}
}

type fakeTargetPusher struct {
	pushObjects func(context.Context, []gitproto.PushCommand, storer.Storer, []plumbing.Hash) error
}

func (f fakeTargetPusher) PushObjects(ctx context.Context, cmds []gitproto.PushCommand, store storer.Storer, hashes []plumbing.Hash) error {
	return f.pushObjects(ctx, cmds, store, hashes)
}

func containsHash(hashes []plumbing.Hash, want plumbing.Hash) bool {
	for _, h := range hashes {
		if h == want {
			return true
		}
	}
	return false
}
```
