Artifact 077898ab166e40bdab9b00d900c01ae11d4c783327c29534a51ce8ab5ad7be11:
- File
conformance/horizon_annotate_test.go
— part of check-in
[52f026832e]
at
2026-10-28 22:23:23
on branch main
— fix(horizon): label only absences below C; annotate fetches what it walks
Review follow-ups on the demand fetch for reads below the horizon:
- A read is refused as below the horizon, and demand-fetched, only when its check-in lies outside the held set K; an unheld payload above C, such as one outside the store cone's paths, keeps its own error and is not fetched. - Annotate no longer refuses without a peer: on a content-horizon store it reports the lines it cannot attribute past C at the horizon, marked BelowHorizon, as a structural store does. AnnotateContext fetches each version as the walk reaches it, so nothing the walk does not read is fetched, up to 200 payloads; past that it returns the partial result. - diffWholeCheckin reports a failed structure classification, and the read paths take the caller's context through to the fetch. - Tests: misclassification above C, annotate over-fetch, the partial result over the limit, and a structural peer withholding the payload. (user: [email protected], size: 3437) [annotate] [blame] [check-ins using] [more...]
package conformance import ( "context" "path/filepath" "testing" "github.com/danmestas/go-libfossil/internal/annotate" "github.com/danmestas/go-libfossil/internal/cone" "github.com/danmestas/go-libfossil/internal/repo" "github.com/danmestas/go-libfossil/internal/sync" ) var horizonStructAnnotate = Case{ID: "horizon.5.5.annotate-crossing", Req: "HZ-5.5-1"} func TestHorizonAnnotateCrossing(t *testing.T) { check(t, horizonStructAnnotate, func(t *testing.T) error { return hzAnnotateCrossing(t) }) } // hzAnnotateCrossing: annotating back past C (draft-fossil-horizon-00 §5.5). // The origin's f gains a line at each of c1, c2 = C and c3, and g is // unchanged since c1. In a clone at C's structural horizon the lines whose // origin lies at or below C -- f's first two, g's -- are reported as // originating at the horizon, and f's c3 line keeps c3. A clone at C's // content horizon holds every manifest (§4.1): g, whose blob K names, is // attributed to c1 as the origin attributes it, while f, whose c1 blob it // does not hold, is reported at the horizon as in the structural clone. func hzAnnotateCrossing(t *testing.T) error { origin := newSCSyncRepo(t, map[string]string{"f": "old\n", "g": "shared\n"}) c2 := origin.commit(t, map[string]string{"f": "old\nmid\n", "g": "shared\n"}, origin.c1) c3 := origin.commit(t, map[string]string{"f": "old\nmid\nnew\n", "g": "shared\n"}, c2) c, tip, below := hzUUID(t, origin.r, c2), hzUUID(t, origin.r, c3), hzUUID(t, origin.r, origin.c1) clone := func(depth cone.HorizonDepth) (*repo.Repo, error) { h, err := cone.NewHorizon(c, cone.RuleDescendants, depth) if err != nil { return nil, err } sc, err := cone.NewWithHorizon(nil, nil, h) if err != nil { return nil, err } r, _, err := sync.Clone(context.Background(), filepath.Join(t.TempDir(), "clone.fossil"), &scSyncPeer{r: origin.r}, sync.CloneOpts{StoreCone: sc, PullPhantoms: true}) if err != nil { return nil, err } t.Cleanup(func() { r.Close() }) return r, nil } type want struct { uuid string below bool } run := func(r *repo.Repo, file string, wants []want) error { rid, err := hzRID(r, tip) if err != nil { return err } lines, err := annotate.Annotate(r, annotate.Options{FilePath: file, StartRID: rid}) if err != nil { return err } if len(lines) != len(wants) { return expectf("%s: %d lines, want %d", file, len(lines), len(wants)) } for i, w := range wants { if lines[i].Version.UUID != w.uuid || lines[i].BelowHorizon != w.below { return expectf("%s line %d %q: %.10s below=%v, want %.10s below=%v", file, i, lines[i].Text, lines[i].Version.UUID, lines[i].BelowHorizon, w.uuid, w.below) } } return nil } structural, err := clone(cone.DepthStructural) if err != nil { return err } if err := run(structural, "f", []want{{c, true}, {c, true}, {tip, false}}); err != nil { return err } if err := run(structural, "g", []want{{c, true}}); err != nil { return err } content, err := clone(cone.DepthContent) if err != nil { return err } if err := run(content, "g", []want{{below, false}}); err != nil { return err } // f's version at c1 is a blob below the horizon, which only a demand // fetch brings (§4.4): without one the walk stops at C as a structural // store's does, and the lines it cannot attribute are reported there. return run(content, "f", []want{{c, true}, {c, true}, {tip, false}}) }