Skip to content
quarry Artifact [067b0afde8]
Login

Artifact [067b0afde8]

Artifact 067b0afde8608760d1c12bc04f650bf3837d39e82badae24c98f072980c169ac:


package index

import (
	"fmt"
	"path/filepath"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/artifact"
)

// Behind walks ancestry, and ancestry on a real trunk is a ladder:
// branches keep merging trunk in, so every old check-in is reachable
// along many paths of many lengths. The walk must cost the number of
// ancestors, not the number of paths — a ladder a thousand rungs tall
// answers in milliseconds, and answers the same number a hand count
// gives.
func TestBehindCostsAncestorsNotPaths(t *testing.T) {
	ix, err := Open(filepath.Join(t.TempDir(), "index.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer ix.Close()
	h := func(i int, side string) string { return fmt.Sprintf("%s%039d", side, i)[:40] }
	when := func(i int) string {
		return time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(i) * time.Minute).Format("2006-01-02T15:04:05")
	}
	feat := []artifact.Tag{{Name: "*branch", Target: "*", Value: "feat"}, {Name: "*sym-feat", Target: "*"}}
	var batch []Parsed
	ci := func(hash string, i int, parents []string, tags []artifact.Tag) {
		batch = append(batch, Parsed{Hash: hash, Art: &artifact.Artifact{Type: artifact.Manifest,
			Date: when(i), User: "dan", Comment: hash[:6], Parents: parents, Tags: tags}})
	}
	// Rung 0 on both rails, then each rung: trunk moves, and the branch
	// merges that trunk check-in in.
	const rungs = 1000
	ci(h(0, "a"), 0, nil, nil)
	ci(h(0, "b"), 1, []string{h(0, "a")}, feat)
	for i := 1; i <= rungs; i++ {
		ci(h(i, "a"), 2*i, []string{h(i-1, "a")}, nil)
		ci(h(i, "b"), 2*i+1, []string{h(i-1, "b"), h(i, "a")}, feat)
	}
	// Three trunk check-ins the branch has not merged.
	for i := 1; i <= 3; i++ {
		ci(h(rungs+i, "a"), 2*rungs+10+i, []string{h(rungs+i-1, "a")}, nil)
	}
	if err := ix.FoldNow(batch); err != nil {
		t.Fatal(err)
	}
	start := time.Now()
	behind, err := ix.Behind("feat", "trunk")
	if err != nil {
		t.Fatal(err)
	}
	if behind != 3 {
		t.Fatalf("behind = %d, want 3", behind)
	}
	if took := time.Since(start); took > 1500*time.Millisecond {
		t.Fatalf("Behind took %v on a %d-rung ladder; the walk is counting paths", took, rungs)
	}
}