Artifact 9d6bed5b279bb8d3c85bf566f1e0c1c717c8199aa52d73037ee4fbb0d521d22d:
- File
internal/content/sparse_test.go
— part of check-in
[524c749185]
at
2026-10-20 00:25:58
on branch feat/submanifest-reader
— feat(content): store cone and the three absence classes of the sparse store
The store cone (draft-fossil-sparse-cone-00 §5) is kept in a storecone table that exists only while a cone is set. fossil rebuild drops tables it does not know, so losing the cone reads as dense and the store heals toward dense (§5.2). A cone that does not parse also reads as dense.
LoadAbsences sorts every phantom into transit, shunned or elided by zit's rules. A phantom is elided when F cards name it only outside the store cone and no held delta uses it as a base. (user: [email protected], size: 7209) [annotate] [blame] [check-ins using]
package content import ( "testing" "github.com/danmestas/go-libfossil/db" "github.com/danmestas/go-libfossil/internal/blob" "github.com/danmestas/go-libfossil/internal/cone" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" "github.com/danmestas/go-libfossil/internal/hash" ) func mustCone(t *testing.T, include, exclude []string) *cone.Cone { t.Helper() c, err := cone.New(include, exclude) if err != nil { t.Fatal(err) } return c } func TestStoreConeAbsentIsDense(t *testing.T) { d := setupTestDB(t) got, err := StoreCone(d) if err != nil || got != nil { t.Fatalf("StoreCone = %v, %v; want nil, nil", got, err) } } func TestStoreConeRoundTrip(t *testing.T) { d := setupTestDB(t) want := mustCone(t, []string{"src", "README"}, []string{"src/vendor"}) if err := SetStoreCone(d, want); err != nil { t.Fatal(err) } got, err := StoreCone(d) if err != nil { t.Fatal(err) } if got == nil || !got.Equal(want) { t.Fatalf("StoreCone = %v, want %v", got, want) } // Replacing it keeps one row. next := mustCone(t, []string{"docs"}, nil) if err := SetStoreCone(d, next); err != nil { t.Fatal(err) } if got, _ := StoreCone(d); got == nil || !got.Equal(next) { t.Fatalf("after replace StoreCone = %v, want %v", got, next) } // nil returns the store to dense and leaves no table behind, so a // repository that was sparse once is shaped like any dense one. if err := SetStoreCone(d, nil); err != nil { t.Fatal(err) } if got, err := StoreCone(d); err != nil || got != nil { t.Fatalf("after clear StoreCone = %v, %v; want nil, nil", got, err) } var n int if err := d.QueryRow("SELECT count(*) FROM sqlite_master WHERE name='storecone'").Scan(&n); err != nil { t.Fatal(err) } if n != 0 { t.Fatal("storecone table left behind by SetStoreCone(nil)") } } // A cone this implementation cannot read is policy loss (§3.1, §5.2): the // store reads as dense, never as an error. func TestStoreConeUnreadableIsDense(t *testing.T) { d := setupTestDB(t) if err := SetStoreCone(d, mustCone(t, []string{"src"}, nil)); err != nil { t.Fatal(err) } // The first is a later version's lead-in: 0x00, then a version byte this // implementation does not know. for _, bad := range [][]byte{{0, 9, 1, 0, 3, 0, 's', 'r', 'c'}, {}, []byte("src")} { if _, err := d.Exec("UPDATE storecone SET cone=?", bad); err != nil { t.Fatal(err) } got, err := StoreCone(d) if err != nil || got != nil { t.Fatalf("StoreCone over %q = %v, %v; want nil, nil", bad, got, err) } } } // absenceFixture is a store with one held blob and phantoms in every class. type absenceFixture struct { d *db.DB held, out, in, both, none, shunned, source libfossil.FslID renamed libfossil.FslID } func newAbsenceFixture(t *testing.T) *absenceFixture { t.Helper() d := setupTestDB(t) f := &absenceFixture{d: d} phantom := func(name string) libfossil.FslID { rid, err := blob.StorePhantom(d, hash.SHA1([]byte(name))) if err != nil { t.Fatal(err) } return rid } var err error if f.held, _, err = blob.Store(d, []byte("held content")); err != nil { t.Fatal(err) } f.out, f.in, f.both = phantom("out"), phantom("in"), phantom("both") f.none, f.shunned, f.source = phantom("none"), phantom("shunned"), phantom("source") f.renamed = phantom("renamed") if _, err := d.Exec("INSERT INTO shun(uuid, mtime) VALUES(?, 0)", hash.SHA1([]byte("shunned"))); err != nil { t.Fatal(err) } // The held blob is a delta over source, so source cannot be elided: // the held artifact is unreadable without it. if _, err := d.Exec("INSERT INTO delta(rid, srcid) VALUES(?, ?)", f.held, f.source); err != nil { t.Fatal(err) } fnid := map[string]int64{} for i, name := range []string{"src/a.c", "tools/t.c", "tools/u.c", "docs/d.txt", "src/b.c"} { fnid[name] = int64(i + 1) if _, err := d.Exec("INSERT INTO filename(fnid, name) VALUES(?, ?)", fnid[name], name); err != nil { t.Fatal(err) } } link := func(fid, pid libfossil.FslID, name, prior string) { t.Helper() if _, err := d.Exec("INSERT INTO mlink(mid, fid, pmid, pid, fnid, pfnid, mperm) VALUES(100, ?, 0, ?, ?, ?, 0)", fid, pid, fnid[name], fnid[prior]); err != nil { t.Fatal(err) } } link(f.out, 0, "tools/t.c", "") link(f.in, 0, "src/a.c", "") link(f.both, 0, "tools/u.c", "") link(f.both, 0, "src/b.c", "") link(f.shunned, 0, "tools/t.c", "") link(f.source, 0, "tools/t.c", "") // renamed is named only as the parent version of a rename out of // src/b.c: the parent's F card put it in the cone. link(f.held, f.renamed, "docs/d.txt", "src/b.c") return f } func TestAbsencesDense(t *testing.T) { f := newAbsenceFixture(t) a, err := LoadAbsences(f.d) if err != nil { t.Fatal(err) } if a.Cone() != nil { t.Fatal("dense store has a cone") } for rid, want := range map[libfossil.FslID]Absence{ f.held: Held, f.out: Transit, f.in: Transit, f.both: Transit, f.none: Transit, f.shunned: Shunned, f.source: Transit, f.renamed: Transit, } { if got := a.Class(rid); got != want { t.Errorf("dense Class(%d) = %v, want %v", rid, got, want) } } if a.Count(Elided) != 0 || a.Count(Transit) != 6 || a.Count(Shunned) != 1 { t.Errorf("dense counts transit=%d shunned=%d elided=%d", a.Count(Transit), a.Count(Shunned), a.Count(Elided)) } } func TestAbsencesSparse(t *testing.T) { f := newAbsenceFixture(t) if err := SetStoreCone(f.d, mustCone(t, []string{"src"}, nil)); err != nil { t.Fatal(err) } a, err := LoadAbsences(f.d) if err != nil { t.Fatal(err) } for rid, want := range map[libfossil.FslID]Absence{ f.held: Held, f.out: Elided, // named only outside the cone f.in: Transit, // named inside it f.both: Transit, // an in-cone name keeps it wanted f.none: Transit, // named by no F card: nothing proves it out of cone f.shunned: Shunned, f.source: Transit, // a held delta's base f.renamed: Transit, // named in the cone by the parent's F card } { if got := a.Class(rid); got != want { t.Errorf("Class(%d) = %v, want %v", rid, got, want) } } if a.Count(Elided) != 1 || a.Count(Transit) != 5 { t.Errorf("counts transit=%d elided=%d", a.Count(Transit), a.Count(Elided)) } // Elision is recomputed from the cone, never stored: widening makes the // phantom wanted again, and losing the cone makes every one wanted. if err := SetStoreCone(f.d, mustCone(t, []string{"src", "tools"}, nil)); err != nil { t.Fatal(err) } if a, err = LoadAbsences(f.d); err != nil { t.Fatal(err) } if got := a.Class(f.out); got != Transit { t.Errorf("after widening Class(out) = %v, want transit", got) } if err := SetStoreCone(f.d, mustCone(t, []string{"docs"}, nil)); err != nil { t.Fatal(err) } if a, err = LoadAbsences(f.d); err != nil { t.Fatal(err) } if got := a.Class(f.in); got != Elided { t.Errorf("after narrowing Class(in) = %v, want elided", got) } if _, err := f.d.Exec("DROP TABLE storecone"); err != nil { t.Fatal(err) } if a, err = LoadAbsences(f.d); err != nil { t.Fatal(err) } if a.Count(Elided) != 0 { t.Errorf("after losing the cone %d phantoms are elided", a.Count(Elided)) } }