Skip to content
quarry Artifact [62de7b08bd]
Login

Artifact [62de7b08bd]

Artifact 62de7b08bd6a6dd6321bdf1a25b5a10c3bcf3b9162f22c0a249be30b0936cd71:


package api

import (
	"context"
	"path/filepath"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/artifact"
	"craftdesign.group/quarry/internal/index"

	"craftdesign.group/quarry/internal/ops"
)

func TestRegisterAllAndVersionOp(t *testing.T) {
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "1.2.3-test"}); err != nil {
		t.Fatal(err)
	}
	got, err := r.Invoke(context.Background(), "meta.version", versionIn{})
	if err != nil {
		t.Fatal(err)
	}
	if got.(versionOut).Version != "1.2.3-test" {
		t.Fatalf("got %+v", got)
	}
}

func TestRegisteredOpsAppearInSpec(t *testing.T) {
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v"}); err != nil {
		t.Fatal(err)
	}
	spec, err := ops.Spec(r, "quarry", "v")
	if err != nil {
		t.Fatal(err)
	}
	if spec.Paths["/api/v1/version"].Get == nil {
		t.Fatal("meta.version missing from generated spec")
	}
}

func wikiIndex(t *testing.T) *index.Index {
	t.Helper()
	ix, err := index.Open(filepath.Join(t.TempDir(), "index.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	batch := []index.Parsed{
		{Hash: "aaa1", Art: &artifact.Artifact{Type: artifact.Wiki, WikiTitle: "Design",
			Date: "2026-08-15T10:00:00", User: "dan", Mimetype: "text/x-markdown",
			Body: []byte("# Design\n\ndetails\n")}},
		{Hash: "aaa2", Art: &artifact.Artifact{Type: artifact.Wiki, WikiTitle: "Home",
			Date: "2026-08-15T10:00:01", User: "dan", Mimetype: "text/x-markdown",
			Body: []byte("See [[Design]] and [[Missing]].\n")}},
		{Hash: "aaa3", Art: &artifact.Artifact{Type: artifact.Wiki, WikiTitle: "Home",
			Date: "2026-08-15T11:00:00", User: "eve", Mimetype: "text/x-markdown",
			Body: []byte("Revised. See [[Design]].\n")}},
	}
	if err := ix.Fold(batch); err != nil {
		t.Fatal(err)
	}
	return ix
}

func TestWikiOps(t *testing.T) {
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Index: wikiIndex(t)}); err != nil {
		t.Fatal(err)
	}

	got, err := r.Invoke(context.Background(), "wiki.list", wikiListIn{})
	if err != nil {
		t.Fatal(err)
	}
	list := got.(wikiListOut)
	if list.Count != 2 || list.Pages[0].Title != "Design" || list.Pages[1].Title != "Home" {
		t.Fatalf("list = %+v", list)
	}
	if list.Pages[1].User != "eve" {
		t.Fatalf("latest edit not surfaced: %+v", list.Pages[1])
	}

	got, err = r.Invoke(context.Background(), "wiki.get", wikiGetIn{Name: "Home"})
	if err != nil {
		t.Fatal(err)
	}
	page := got.(wikiGetOut)
	if !strings.Contains(page.HTML, `<a href="/wiki/Design">Design</a>`) {
		t.Fatalf("existing page not resolved:\n%s", page.HTML)
	}
	if !strings.Contains(page.Source, "Revised") {
		t.Fatalf("stale edit served: %+v", page)
	}

	if _, err := r.Invoke(context.Background(), "wiki.get", wikiGetIn{Name: "Missing"}); err == nil {
		t.Fatal("want error for missing page")
	}
}

func TestWikiGetUnresolvedRefStaysText(t *testing.T) {
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Index: wikiIndex(t)}); err != nil {
		t.Fatal(err)
	}
	// The older Home revision links [[Missing]]; current revision does
	// not — fetch Design's referrer instead via a fresh page write.
	got, err := r.Invoke(context.Background(), "wiki.get", wikiGetIn{Name: "Design"})
	if err != nil {
		t.Fatal(err)
	}
	if strings.Contains(got.(wikiGetOut).HTML, "/wiki/Missing") {
		t.Fatal("nonexistent page linked")
	}
}

func TestCheckinGetAndHashResolution(t *testing.T) {
	ix := wikiIndex(t)
	h1 := strings.Repeat("ab", 32)
	h2 := "abcd" + strings.Repeat("ef", 30)
	if err := ix.Fold([]index.Parsed{
		{Hash: h1, Art: &artifact.Artifact{Type: artifact.Manifest,
			Date: "2026-08-15T09:00:00", User: "dan", Comment: "first"}},
		{Hash: h2, Art: &artifact.Artifact{Type: artifact.Manifest,
			Date: "2026-08-15T09:30:00", User: "dan", Comment: "second", Parents: []string{h1}}},
		{Hash: "bbb1", Art: &artifact.Artifact{Type: artifact.Wiki, WikiTitle: "Refs",
			Date: "2026-08-15T12:00:00", User: "dan", Mimetype: "text/x-markdown",
			Body: []byte("Fixed in " + h2[:12] + ". Ambiguous: ab.\n")}},
	}); err != nil {
		t.Fatal(err)
	}
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Index: ix}); err != nil {
		t.Fatal(err)
	}

	// Prefix lookup: unique resolves, ambiguous does not.
	got, err := r.Invoke(context.Background(), "checkin.get", checkinGetIn{Hash: h2[:12]})
	if err != nil {
		t.Fatal(err)
	}
	ci := got.(checkinGetOut)
	if ci.Hash != h2 || len(ci.Parents) != 1 || ci.Parents[0] != h1 {
		t.Fatalf("checkin = %+v", ci)
	}
	if _, err := r.Invoke(context.Background(), "checkin.get", checkinGetIn{Hash: "abcdzz"}); err == nil {
		t.Fatal("want error for unknown hash")
	}

	// Wiki body hash references resolve through the same lookup.
	got, err = r.Invoke(context.Background(), "wiki.get", wikiGetIn{Name: "Refs"})
	if err != nil {
		t.Fatal(err)
	}
	html := got.(wikiGetOut).HTML
	if !strings.Contains(html, `<a href="/checkin/`+h2+`">`+h2[:12]+`</a>`) {
		t.Fatalf("hash ref not resolved:\n%s", html)
	}
}