package service
import (
"context"
"testing"
)
// The accessor every surface above this layer reads a space through: one call,
// the addressing rule applied, the bodies alongside, and the link graph filled
// in. web/ used to scan the git tree itself and mcpsrv/ used to convert this
// package's documents back into git ones; both are gone because this exists.
func TestArchiveReturnsDocumentsBodiesAndLinks(t *testing.T) {
svc, root := newService(t)
sp := newSpace(t, root, 1)
ctx := context.Background()
head := commitFiles(t, sp, sp.ApprovedBranch(), 1, map[string][]byte{
"specs/0007-storage.md": mdDoc("SPEC-0007", "Storage model", "Supersedes [[SPEC-0003]]."),
"specs/0003-old.md": mdDoc("SPEC-0003", "Older sketch", "The first attempt."),
"notes/plain.md": []byte("# Just a note\n\nNo frontmatter at all.\n"),
})
arc, bodies, err := svc.Archive(ctx, sp, ApprovedRev)
if err != nil {
t.Fatalf("Archive: %v", err)
}
// The revision is resolved before anything is read, so the archive names
// the commit it describes and a caller can pin to it.
if arc.Rev != head.String() {
t.Errorf("archive Rev = %s, want the resolved approved head %s", arc.Rev, head)
}
if arc.Space != sp.Ref {
t.Errorf("archive space = %s, want %s", arc.Space, sp.Ref)
}
if len(arc.All()) != 3 || len(bodies) != 3 {
t.Fatalf("archive holds %d documents and %d bodies, want 3 of each", len(arc.All()), len(bodies))
}
// The addressing rule: a well-formed unique id addresses the document, and
// a document without one is addressed by its path.
page, ok := arc.Page("SPEC-0007")
if !ok || page.Path != "specs/0007-storage.md" {
t.Fatalf("SPEC-0007 = %+v, ok=%v", page, ok)
}
if _, ok := arc.Page("notes/plain"); !ok {
t.Error("a document with no frontmatter must be addressed by its path")
}
// Bodies are the whole document, keyed the way the archive keys pages.
if body, ok := bodies[page.Path]; !ok || !contains(body, "Supersedes") {
t.Errorf("body of %s = %q", page.Path, body)
}
// The link graph: filled here, so Backlinks answers rather than always
// returning nothing.
if len(page.Links) != 1 || page.Links[0] != "SPEC-0003" {
t.Errorf("links of SPEC-0007 = %v, want [SPEC-0003]", page.Links)
}
if page.WordCount == 0 {
t.Error("word count is filled by the same pass and must not be zero")
}
back := arc.Backlinks("SPEC-0003")
if len(back) != 1 || back[0].ID != "SPEC-0007" {
t.Fatalf("Backlinks(SPEC-0003) = %v, want SPEC-0007", back)
}
}
// A pinned revision and the approved head are the same call with a different
// revision string, and the read contract still applies: a branch name is not a
// revision this method will serve.
func TestArchiveHonoursTheReadContract(t *testing.T) {
svc, root := newService(t)
sp := newSpace(t, root, 1)
ctx := context.Background()
first := commitFiles(t, sp, sp.ApprovedBranch(), 1, map[string][]byte{
"specs/0007-storage.md": mdDoc("SPEC-0007", "Storage model", "first"),
})
commitFiles(t, sp, sp.ApprovedBranch(), 2, map[string][]byte{
"specs/0007-storage.md": mdDoc("SPEC-0007", "Storage model", "second"),
})
_, bodies, err := svc.Archive(ctx, sp, first.String())
if err != nil {
t.Fatalf("pinned Archive: %v", err)
}
if !contains(bodies["specs/0007-storage.md"], "first") {
t.Errorf("pinned archive returned %q, want the pinned revision", bodies["specs/0007-storage.md"])
}
cutBranch(t, sp, "proposals/1", sp.ApprovedBranch())
if _, _, err := svc.Archive(ctx, sp, "proposals/1"); err == nil {
t.Fatal("Archive served a branch name; the read plane takes object names only")
}
}
// ArchiveFrom is the same construction over documents a caller already holds,
// and it refuses a document whose blob id is not an object name rather than
// keying the render cache on a zero hash.
func TestArchiveFromRefusesAMalformedBlobID(t *testing.T) {
_, _, err := ArchiveFrom(fxSpace, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", []Document{
{Path: "specs/0007-storage.md", Blob: "not-a-sha", Data: mdDoc("SPEC-0007", "Storage model", "body")},
})
if err == nil {
t.Fatal("ArchiveFrom accepted a malformed blob id")
}
}