Artifact 6899494fee61eed0445e9072fca76bba406300164731b7d886d37f9a52e643a0:
- File
internal/sync/horizon_pragma_test.go
— part of check-in
[dc33bca3a6]
at
2026-10-22 16:12:54
on branch feat/horizon-cones
— feat(sync): serve and take the structural horizon
The origin now answers pragma horizon-structural (draft-fossil-horizon-00 §6.1, §6.2): it keeps only the manifests and nodes the held set reaches, labels every boundary hash at the head of each reply (§6.2.2), mints the seed for C and sends it, pragma ahead of its file card, when the client offers another name (§6.2.3), and advertises the structural level only then; a request it cannot place or seed is served as content. It refuses a seed offered to it and withholds a gimme'd manifest below the horizon.
A structural store's requests carry horizon-structural and the seed it holds. It routes the announced card to seed.Hold after checking its name and shape, never storing or announcing it, records the labels, and applies the seed after each reply and after the closing link. A first reply that does not serve structural with a seed, or a seed failing provenance, makes it a content-horizon store for good, reported in the result, and the manifests below the horizon are fetched (§5.1, §5.2.4, §6.3). (user: [email protected], size: 2762) [annotate] [blame] [check-ins using] [more...]
package sync import ( "bytes" "strings" "testing" "github.com/danmestas/go-libfossil/internal/cone" "github.com/danmestas/go-libfossil/internal/xfer" ) const testHorizonHash = "0123456789abcdef0123456789abcdef01234567" func testHorizonCone(t *testing.T, depth cone.HorizonDepth, include ...string) *cone.Cone { t.Helper() h, err := cone.NewHorizon(testHorizonHash, cone.RuleLeaves, depth) if err != nil { t.Fatal(err) } c, err := cone.NewWithHorizon(include, nil, h) if err != nil { t.Fatal(err) } return c } func pragmaLines(t *testing.T, cards []xfer.Card) []string { t.Helper() var lines []string for _, card := range cards { var buf bytes.Buffer if err := xfer.EncodeCard(&buf, card); err != nil { t.Fatal(err) } lines = append(lines, strings.TrimSuffix(buf.String(), "\n")) } return lines } // draft-fossil-horizon-00 §6.1, §6.2.3: one horizon pragma after the // path-cone pragmas, spelled as zit spells it; a structural horizon adds // horizon-structural and the offered seed, and the origin reads the depth // back. func TestHorizonPragmaWire(t *testing.T) { for _, tc := range []struct { depth cone.HorizonDepth include []string want []string }{ {cone.DepthContent, nil, []string{"pragma horizon " + testHorizonHash + " leaves"}}, {cone.DepthStructural, nil, []string{"pragma horizon " + testHorizonHash + " leaves", "pragma horizon-structural", "pragma horizon-seed -"}}, {cone.DepthContent, []string{"src"}, []string{"pragma cone src", "pragma horizon " + testHorizonHash + " leaves"}}, } { c := testHorizonCone(t, tc.depth, tc.include...) cards := conePragmas(c, noSeed) if got := pragmaLines(t, cards); strings.Join(got, "\n") != strings.Join(tc.want, "\n") { t.Fatalf("pragmas = %q, want %q", got, tc.want) } round, err := requestCone(cards) if err != nil { t.Fatal(err) } h, ok := round.Horizon() if !ok || h.Hash() != testHorizonHash || h.Rule() != cone.RuleLeaves || h.Depth() != tc.depth { t.Fatalf("request horizon = %v, %v", h, ok) } if strings.Join(round.Include(), ",") != strings.Join(tc.include, ",") { t.Fatalf("request paths = %q, want %q", round.Include(), tc.include) } } } // A malformed horizon pragma is ignored, as zit ignores one: the request is // then served as if it carried none (§6.3 from the server's side). func TestHorizonPragmaMalformedIgnored(t *testing.T) { for _, values := range [][]string{ {testHorizonHash}, {testHorizonHash, "leaves", "extra"}, {"0123", "leaves"}, {testHorizonHash, "ancestors"}, } { c, err := requestCone([]xfer.Card{&xfer.PragmaCard{Name: "horizon", Values: values}}) if err != nil || c != nil { t.Fatalf("horizon %q: cone=%v err=%v, want ignored", values, c, err) } } }