package api
import (
"path/filepath"
"testing"
"craftdesign.group/quarry/internal/artifact"
"craftdesign.group/quarry/internal/index"
"craftdesign.group/quarry/internal/oltp"
)
const (
redTrunkTip = "c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1"
redFeatureTip = "f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1"
)
func redTrunkIndex(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() })
if err := ix.FoldNow([]index.Parsed{
{Hash: redTrunkTip, Art: &artifact.Artifact{Type: artifact.Manifest, Date: "2026-01-01T08:00:00", User: "ada", Comment: "trunk",
Tags: []artifact.Tag{{Name: "*branch", Target: "*", Value: "trunk"}}}},
{Hash: redFeatureTip, Art: &artifact.Artifact{Type: artifact.Manifest, Date: "2026-01-01T09:00:00", User: "ada", Comment: "work",
Tags: []artifact.Tag{{Name: "*branch", Target: "*", Value: "feature"}}}},
}); err != nil {
t.Fatal(err)
}
return ix
}
// A failed run on the default branch tells the repository's owners —
// the deed holder and the default branch's owners, once each — on the
// landing family, keyed per check-in and pipeline so a re-run of the
// same pipeline on the same check-in collapses onto the first trigger.
// A failure on any other branch tells nobody.
func TestRedTrunkNotifiesTheOwnersOncePerCheckinAndPipeline(t *testing.T) {
fn := &fakeNotify{}
d := Deps{
Notify: fn,
Repos: NewRepos(map[string]*Repo{"alpha": {Index: redTrunkIndex(t)}}),
Owners: oneOwner("dan"),
Protect: stubProtect{rules: []oltp.Protection{
{Branch: "trunk", Owners: []string{"alice", "dan"}},
}},
}
d.NotifyRedTrunk("alpha", redTrunkTip, "ci/race.json", "run1")
evs := waitNotify(fn, 2)
got := map[string]NotifyEvent{}
for _, e := range evs {
if e.Workflow != "quarry-landing" {
t.Fatalf("FAIL: workflow = %q, want quarry-landing", e.Workflow)
}
if _, dup := got[e.To]; dup {
t.Fatalf("FAIL: %s was told twice", e.To)
}
got[e.To] = e
}
if len(got) != 2 || got["alice"].To == "" || got["dan"].To == "" {
t.Fatalf("FAIL: recipients = %v, want alice and dan", got)
}
e := got["dan"]
if want := "ci:red:alpha:" + redTrunkTip + ":ci/race.json:dan"; e.TxnID != want {
t.Errorf("FAIL: TxnID = %q, want %q", e.TxnID, want)
}
if e.Payload["repo"] != "alpha" || e.Payload["link"] != "/r/alpha/ci/run/run1" {
t.Errorf("FAIL: payload repo/link = %v/%v", e.Payload["repo"], e.Payload["link"])
}
fn2 := &fakeNotify{}
d.Notify = fn2
d.NotifyRedTrunk("alpha", redFeatureTip, "ci/race.json", "run2")
if evs := waitNotify(fn2, 0); len(evs) != 0 {
t.Fatalf("FAIL: a failure off the default branch told %+v", evs)
}
d.NotifyRedTrunk("nope", redTrunkTip, "ci/race.json", "run3")
if evs := waitNotify(fn2, 0); len(evs) != 0 {
t.Fatalf("FAIL: an unknown repository told %+v", evs)
}
t.Log("ok: red trunk tells the owners once each; other branches tell nobody")
}