Skip to content
quarry Artifact [7f32fd825c]
Login

Artifact [7f32fd825c]

Artifact 7f32fd825c060f4835309bf729976b41c135b3efabf47bf9bf941cee6feaed32:


package api

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

	"craftdesign.group/quarry/internal/artifact"
	"craftdesign.group/quarry/internal/index"
	"craftdesign.group/quarry/internal/oltp"
	"craftdesign.group/quarry/internal/ops"
)

// A ticket filed on this forge is found by search before it is ever
// promoted to an artifact. The index has never heard of it, so a search
// for words in its title found nothing — every recent ticket on a forge
// that files locally. A title match leads; a word only in the body
// still finds it, after the index's hits. A scope that is not tickets
// leaves it out, and the fleet search finds it too.
func TestSearchFindsTicketsFiledHere(t *testing.T) {
	ix, err := index.Open(filepath.Join(t.TempDir(), "i.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	stored := "aaaa000000000000000000000000000000000000000000000000000000000001"
	if err := ix.FoldNow([]index.Parsed{{Hash: stored, Art: &artifact.Artifact{Type: artifact.Ticket,
		TicketID: stored, Date: "2026-09-01T10:00:00", User: "dan",
		Fields: []artifact.Field{{Name: "title", Value: "merge view in the old tracker"}, {Name: "status", Value: "Open"}}}}}); err != nil {
		t.Fatal(err)
	}
	db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Repos: NewRepos(map[string]*Repo{"q": {Index: ix}}),
		Local: db, Idem: db, Numbers: db}); err != nil {
		t.Fatal(err)
	}
	ctx := ops.WithUser(context.Background(), "dan")
	file := func(title, comment string) string {
		out, err := r.Invoke(ctx, "ticket.intake", ticketIntakeIn{Repo: "q", Title: title, Comment: comment})
		if err != nil {
			t.Fatal(err)
		}
		return out.(ticketIntakeOut).ID
	}
	panes := file("A conflicting landing shows its merge in three panes", "Meld-style view.")
	body := file("Resolve in the browser", "Builds on the three panes view.")

	search := func(q, kind string) []index.SearchResult {
		out, err := r.Invoke(ctx, "search.query", searchIn{Repo: "q", Q: q, Kind: kind, Limit: 50})
		if err != nil {
			t.Fatal(err)
		}
		return out.(searchOut).Results
	}
	got := search("three panes", "")
	if len(got) != 2 || got[0].Ref != panes || got[1].Ref != body {
		t.Fatalf("FAIL: three panes found %v, want the titled ticket then the one that says it in its body", refs(got))
	}
	if got[0].Number == 0 || got[0].Label == "" {
		t.Errorf("FAIL: a local hit carries no number or title: %+v", got[0])
	}
	if !strings.Contains(got[1].Snippet, "⟦three⟧") {
		t.Errorf("FAIL: a body hit's snippet does not mark the word: %q", got[1].Snippet)
	}
	if got := search("merge", "ticket"); len(got) != 2 || got[0].Ref != panes || got[1].Ref != stored {
		t.Errorf("FAIL: merge found %v, want the local title match ahead of the stored ticket", refs(got))
	}
	if got := search("three panes", "checkin"); len(got) != 0 {
		t.Errorf("FAIL: a check-in search offered tickets: %v", refs(got))
	}
	out, err := r.Invoke(ctx, "search.all", searchAllIn{Q: "three panes", Limit: 50})
	if err != nil {
		t.Fatal(err)
	}
	all := out.(searchAllOut)
	if len(all.Results) != 2 || all.Results[0].Ref != panes || len(all.ByRepo) != 1 || all.ByRepo[0].Count != 2 {
		t.Errorf("FAIL: the fleet search found %d (%v), counted %v", len(all.Results), all.Results, all.ByRepo)
	}
}

func refs(rs []index.SearchResult) []string {
	var out []string
	for _, r := range rs {
		out = append(out, r.Ref[:min(8, len(r.Ref))])
	}
	return out
}