Artifact 947c58c59043cc8e7e94ec51caea0b5eb83f1578f006daa340384af63df70a69:
- File
internal/manifest/required_content_test.go
— part of check-in
[c25e714b08]
at
2026-10-21 11:18:48
on branch feat/submanifest-reader
— fix(manifest): bound MergeParentFiles' required-content check by the caller's context
The fallback that explains a parent whose tree the store does not hold ran under context.Background, so a cancelled commit still paid for it. Commit passes its context; snapshot, which has no deadline, says so explicitly. (user: [email protected], size: 5435) [annotate] [blame] [check-ins using] [more...]
package manifest import ( "context" "database/sql" "errors" "fmt" "strings" "testing" "github.com/danmestas/go-libfossil/db" "github.com/danmestas/go-libfossil/internal/cone" "github.com/danmestas/go-libfossil/internal/content" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" ) type requiredExpansionCounter struct { db.Querier loads map[string]int } func (q *requiredExpansionCounter) QueryRow(query string, args ...any) *sql.Row { if strings.HasPrefix(query, "SELECT content, size FROM blob") { q.loads[fmt.Sprint(args[0])]++ } return q.Querier.QueryRow(query, args...) } // Visibility and relationship validation must share expanded structural bytes: // a dense parent cannot pay for the entire S tree twice in a single preflight. func TestRequireParentContentExpandsEachArtifactOnce(t *testing.T) { r := sha3Repo(t) for key, value := range map[string]string{ SettingEnableSubmanifests: "on", SettingSubmanifestK: "1", } { if err := r.SetConfig(key, value); err != nil { t.Fatal(err) } } var files []File for _, card := range sparseBoundaryCandidates(t) { files = append(files, File{Name: card.Name, Content: []byte(card.Name)}) } rid, parent := commit(t, r, CheckinOpts{Files: files}) if len(parent.S) < 2 { t.Fatal("fixture requires a dense structural tree") } q := &requiredExpansionCounter{Querier: r.DB(), loads: make(map[string]int)} if err := RequireParentContent(context.Background(), q, []libfossil.FslID{rid}); err != nil { t.Fatal(err) } if len(q.loads) < 3 { t.Fatalf("did not observe root and sibling expansion reads: %+v", q.loads) } for artifact, count := range q.loads { if count != 1 { t.Fatalf("artifact %s expanded %d times in one preflight", artifact, count) } } } func TestRequireParentContentElidedSibling(t *testing.T) { files := sparseBoundaryCandidates(t) old := append(files[:1:1], files[2:]...) tree := mustBuildTree(t, old, 1) r, rid, _, _ := sparseBoundaryParent(t, files, old, tree) err := RequireParentContent(context.Background(), r.DB(), []libfossil.FslID{rid}) var required *RequiredContentError if !errors.As(err, &required) { t.Fatalf("required-content refusal: %v", err) } if len(required.Roots) != 1 || len(required.Artifacts) != 1 { t.Fatalf("incomplete recovery instruction: %+v", required) } if required.Artifacts[0] != tree.S[1].UUID || required.Elided < 2 { t.Fatalf("incorrect recovery instruction: %+v", required) } if !strings.Contains(err.Error(), "elided") || !strings.Contains(err.Error(), "no configured peer") { t.Fatalf("incorrect absence diagnostic: %v", err) } if strings.Contains(err.Error(), "missing") || strings.Contains(err.Error(), "corrupt") { t.Fatalf("elision described as damage: %v", err) } var before int if err := r.DB().QueryRow("SELECT count(*) FROM blob").Scan(&before); err != nil { t.Fatal(err) } _, _, err = Checkin(r, CheckinOpts{ Files: []File{{Name: "new", Content: []byte("new bytes")}}, Parent: rid, User: "test", }) if !errors.As(err, &required) { t.Fatalf("local-only writer did not refuse structurally incomplete parent: %v", err) } var after int if err := r.DB().QueryRow("SELECT count(*) FROM blob").Scan(&after); err != nil { t.Fatal(err) } if after != before { t.Fatalf("refusal leaked new blobs: before=%d after=%d", before, after) } } func TestMergeParentFilesCarriesElidedPayload(t *testing.T) { r := sha3Repo(t) parentRID, parent := commit(t, r, CheckinOpts{Files: []File{ {Name: "inside/a", Content: []byte("inside")}, {Name: "outside/a", Content: []byte("outside")}, }}) c, err := cone.New([]string{"inside"}, nil) if err != nil { t.Fatal(err) } if err := content.SetStoreCone(r.DB(), c); err != nil { t.Fatal(err) } outsideUUID := parent.F[1].UUID elideWriterNode(t, r, outsideUUID) files, err := MergeParentFiles(context.Background(), r, parentRID, []File{{Name: "inside/a", Content: []byte("edited")}}) if err != nil { t.Fatal(err) } if len(files) != 2 || files[1].UUID != outsideUUID || files[1].Content != nil { t.Fatalf("unchanged outside entry was not carried verbatim: %+v", files) } _, _, err = Checkin(r, CheckinOpts{Files: files, Parent: parentRID, User: "test"}) if err != nil { t.Fatal(err) } if _, held := content.AvailableByUUID(r.DB(), outsideUUID); held { t.Fatal("metadata-only carry fetched outside payload") } } // Retaining bytes does not authorize consuming a shunned structural node. func TestRequireParentContentHeldShunnedChild(t *testing.T) { files := sparseBoundaryCandidates(t) old := append(files[:1:1], files[2:]...) tree := mustBuildTree(t, old, 1) r, rid, _, _ := sparseBoundaryParent(t, files, old, tree) held := tree.S[0].UUID if _, ok := content.AvailableByUUID(r.DB(), held); !ok { t.Fatal("fixture first subtree is not held") } if _, err := r.DB().Exec("INSERT INTO shun(uuid) VALUES(?)", held); err != nil { t.Fatal(err) } err := RequireParentContent(context.Background(), r.DB(), []libfossil.FslID{rid}) if err == nil || !strings.Contains(err.Error(), "shunned") { t.Fatalf("held shunned structural content was not refused: %v", err) } } func TestRequireParentContentCancellation(t *testing.T) { r := sha3Repo(t) ctx, cancel := context.WithCancel(context.Background()) cancel() if err := RequireParentContent(ctx, r.DB(), nil); !errors.Is(err, context.Canceled) { t.Fatalf("cancelled preflight: %v", err) } }