Skip to content
quarry Artifact [2550539064]
Login

Artifact [2550539064]

Artifact 25505390642adf48f4f35f6557629217fba06f06560071170d4e73543fc985f5:


package main

import (
	"context"
	"errors"
	"strings"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/errlog"
	"craftdesign.group/quarry/internal/notify"
	"craftdesign.group/quarry/internal/oltp"
)

type fakePlane struct {
	subs    []string
	emails  []string
	topics  map[string]string
	added   map[string][]string
	removed map[string][]string
	failSub string
	prefs   map[string]notify.SubscriberPreferences
	setp    map[string][]map[string]map[string]bool
}

func newFakePlane() *fakePlane {
	return &fakePlane{topics: map[string]string{},
		added: map[string][]string{}, removed: map[string][]string{}}
}

func (f *fakePlane) EnsureSubscriber(_ context.Context, account, email string) error {
	if account == f.failSub {
		return errors.New("notify is not holding this one")
	}
	f.subs = append(f.subs, account)
	f.emails = append(f.emails, email)
	return nil
}

func (f *fakePlane) EnsureTopic(_ context.Context, key, name string) error {
	f.topics[key] = name
	return nil
}

func (f *fakePlane) AddTopicMember(_ context.Context, key, account string) error {
	f.added[key] = append(f.added[key], account)
	return nil
}

func (f *fakePlane) RemoveTopicMember(_ context.Context, key, account string) error {
	f.removed[key] = append(f.removed[key], account)
	return nil
}

func (f *fakePlane) Preferences(_ context.Context, account string) (notify.SubscriberPreferences, error) {
	return f.prefs[account], nil
}

func (f *fakePlane) SetPreferences(_ context.Context, account string, wf map[string]map[string]bool, _ map[string]*notify.DigestWindow) error {
	if f.setp == nil {
		f.setp = map[string][]map[string]map[string]bool{}
	}
	f.setp[account] = append(f.setp[account], wf)
	return nil
}

type fakeBook struct {
	accounts []oltp.Account
	grants   map[string]map[string]oltp.Role
	repos    []string
}

func (b fakeBook) Repos() ([]oltp.Repo, error) {
	out := make([]oltp.Repo, 0, len(b.repos))
	for _, n := range b.repos {
		out = append(out, oltp.Repo{Name: n})
	}
	return out, nil
}

func (b fakeBook) Accounts() ([]oltp.Account, error) { return b.accounts, nil }

func (b fakeBook) GrantsFor(account string) (map[string]oltp.Role, error) {
	return b.grants[account], nil
}

func has(list []string, want string) bool {
	for _, s := range list {
		if s == want {
			return true
		}
	}
	return false
}

// The sweep makes notify match the forge: every account is a subscriber,
// the admin group holds today's admins and nobody else, and a grant is a
// membership of that repository's topic — whether or not the write that
// created it ever provisioned anything.
func TestReconcileMatchesAccountsAndGrants(t *testing.T) {
	np := newFakePlane()
	book := fakeBook{
		accounts: []oltp.Account{
			{Name: "dmestas", Admin: true},
			{Name: "lou"},
			{Name: "ghost", Admin: true, Disabled: "2026-09-01T00:00:00"},
		},
		grants: map[string]map[string]oltp.Role{
			"lou":   {"quarry": oltp.Read, "Synthetic": oltp.Read},
			"ghost": {"quarry": oltp.Read},
		},
		// quarry itself is granted to nobody: its only members are site
		// admins, which is exactly the shape that had no topic.
		repos: []string{"quarry", "Synthetic", "fossil"},
	}
	sync, err := reconcileNotify(context.Background(), np, book)
	if err != nil {
		t.Fatalf("FAIL: %v", err)
	}
	for _, name := range []string{"dmestas", "lou", "ghost"} {
		if !has(np.subs, name) {
			t.Errorf("FAIL: %s was not ensured as a subscriber", name)
		}
	}
	if !has(np.added[adminsTopic], "dmestas") {
		t.Error("FAIL: the admin did not join the admin group")
	}
	if !has(np.removed[adminsTopic], "lou") {
		t.Error("FAIL: a non-admin was left in the admin group")
	}
	if !has(np.removed[adminsTopic], "ghost") || has(np.added[adminsTopic], "ghost") {
		t.Error("FAIL: a disabled admin still receives fleet alerts")
	}
	if _, ok := np.topics[adminsTopic]; !ok {
		t.Error("FAIL: the admin group topic was never created")
	}
	// A grant is a membership, and the key is the repository's, never
	// the raw name: notify's keys are lowercase and punctuation-free,
	// so "Synthetic" and "synthetic" must not become two topics.
	if _, ok := np.topics[repoTopicKey("quarry")]; !ok {
		t.Error("FAIL: the repository's activity topic was never created")
	}
	if !has(np.added[repoTopicKey("quarry")], "lou") {
		t.Error("FAIL: a granted account did not join the repository topic")
	}
	if !has(np.added[repoTopicKey("Synthetic")], "lou") {
		t.Error("FAIL: the second grant was skipped")
	}
	// A shut account keeps its rows in the forge; it must not keep its
	// notifications.
	if has(np.added[repoTopicKey("quarry")], "ghost") {
		t.Error("FAIL: a disabled account was subscribed to repository activity")
	}
	// A repository nobody was granted still has somewhere to deliver.
	if _, ok := np.topics[repoTopicKey("fossil")]; !ok {
		t.Error("FAIL: a repository with no grants got no topic")
	}
	// The site admin holds every repository, so they are in every topic.
	for _, repo := range []string{"quarry", "Synthetic", "fossil"} {
		if !has(np.added[repoTopicKey(repo)], "dmestas") {
			t.Errorf("FAIL: the site admin is not in %s's topic", repo)
		}
	}
	if sync.Subscribers != 3 || sync.Members != 6 {
		t.Errorf("FAIL: counted %d subscribers and %d memberships, want 3 and 6",
			sync.Subscribers, sync.Members)
	}
	t.Log("ok: subscribers, the admin group and every grant's topic are current")
}

// One account notify cannot hold must not cost the others their alerts.
func TestReconcileKeepsGoingPastOneFailure(t *testing.T) {
	np := newFakePlane()
	np.failSub = "lou"
	book := fakeBook{
		accounts: []oltp.Account{{Name: "lou"}, {Name: "dmestas", Admin: true}},
		repos:    []string{"quarry"},
	}
	sync, err := reconcileNotify(context.Background(), np, book)
	if err == nil {
		t.Error("FAIL: the failure was swallowed")
	}
	if !has(np.added[adminsTopic], "dmestas") || sync.Subscribers != 1 {
		t.Error("FAIL: the sweep stopped at the first failure")
	}
	if has(np.added[adminsTopic], "lou") || has(np.removed[adminsTopic], "lou") {
		t.Error("FAIL: an account notify does not hold was added to a topic anyway")
	}
	t.Log("ok: a failed account is reported and the rest are still provisioned")
}

type fakeAttention struct {
	sent map[string][]api.AttentionEvent
}

func (f *fakeAttention) Attend(account string, e api.AttentionEvent) (uint64, error) {
	if f.sent == nil {
		f.sent = map[string][]api.AttentionEvent{}
	}
	f.sent[account] = append(f.sent[account], e)
	return uint64(len(f.sent[account])), nil
}

func (f *fakeAttention) TailAttention(string, uint64) (<-chan api.AttentionEvent, func()) {
	return nil, func() {}
}
func (f *fakeAttention) AttentionPending(string, uint64) (int, error) { return 0, nil }
func (f *fakeAttention) AttentionTip(string) (uint64, error)          { return 0, nil }
func (f *fakeAttention) MarkAttentionRead(string, uint64) error       { return nil }
func (f *fakeAttention) AttentionReadSeq(string) uint64               { return 0 }
func (f *fakeAttention) RecentAttention(string, int) ([]api.AttentionEvent, error) {
	return nil, nil
}

// A fault reaches the admins through the forge's own inbox, which does
// not depend on notify being present or able to deliver.
func TestAdminAlertReachesEveryAdminsInbox(t *testing.T) {
	att := &fakeAttention{}
	book := fakeBook{accounts: []oltp.Account{
		{Name: "dmestas", Admin: true},
		{Name: "lou"},
		{Name: "ghost", Admin: true, Disabled: "2026-09-01T00:00:00"},
	}}
	first := time.Date(2026, 9, 8, 1, 30, 0, 0, time.UTC)
	alertAdmins(book, att, errlog.Entry{Surface: "ingest", Repo: "quarry",
		Message: "ingest lane is full", First: first})

	got := att.sent["dmestas"]
	if len(got) != 1 {
		t.Fatalf("FAIL: the admin got %d rows, want 1", len(got))
	}
	if got[0].Kind != "error" || got[0].Repo != "quarry" {
		t.Errorf("FAIL: the row does not describe the fault: %+v", got[0])
	}
	if !strings.Contains(got[0].Summary, "ingest lane is full") {
		t.Error("FAIL: the row does not carry what went wrong")
	}
	if got[0].Link == "" {
		t.Error("FAIL: the row does not lead anywhere")
	}
	// The idempotency key is what pairs this row with notify's twin, so
	// one fault is one line in the inbox rather than two.
	if got[0].TxnID != "err:"+first.Format(time.RFC3339Nano) {
		t.Errorf("FAIL: the row does not pair with its notify twin: %q", got[0].TxnID)
	}
	if len(att.sent["lou"]) != 0 {
		t.Error("FAIL: a fleet alert reached a non-admin")
	}
	if len(att.sent["ghost"]) != 0 {
		t.Error("FAIL: a disabled admin is still alerted")
	}
	t.Log("ok: every serving admin gets the fault in their forge inbox")
}

// Email is off until chosen. The sweep answers "no" for every family a
// person has not answered, and never touches a cell they set — on or
// off — nor anything but the email cell.
func TestEmailIsOffUntilChosen(t *testing.T) {
	np := newFakePlane()
	np.prefs = map[string]notify.SubscriberPreferences{
		"lou": {Workflows: map[string]map[string]bool{
			"quarry-mention":     {"email": true, "push": false},
			"quarry-forum-reply": {"email": false},
		}},
	}
	book := fakeBook{accounts: []oltp.Account{{Name: "dmestas", Admin: true}, {Name: "lou"}},
		repos: []string{"quarry"}}
	sync, err := reconcileNotify(context.Background(), np, book)
	if err != nil {
		t.Fatalf("FAIL: %v", err)
	}
	fresh := np.setp["dmestas"]
	if len(fresh) != 1 || len(fresh[0]) != len(notify.EmailFamilies()) {
		t.Fatalf("FAIL: a fresh account got %+v, want one write covering every family", fresh)
	}
	for wf, cells := range fresh[0] {
		if len(cells) != 1 || cells["email"] != false {
			t.Errorf("FAIL: %s was written as %v, want only email:false", wf, cells)
		}
	}
	chosen := np.setp["lou"]
	if len(chosen) != 1 {
		t.Fatalf("FAIL: an account with choices got %d writes, want 1", len(chosen))
	}
	if _, touched := chosen[0]["quarry-mention"]; touched {
		t.Error("FAIL: an email somebody switched ON was overwritten")
	}
	if _, touched := chosen[0]["quarry-forum-reply"]; touched {
		t.Error("FAIL: an email somebody switched OFF was rewritten")
	}
	if len(chosen[0]) != 2 {
		t.Errorf("FAIL: lou's unanswered families were %v, want the two remaining", chosen[0])
	}
	if sync.Quieted != len(notify.EmailFamilies())+2 {
		t.Errorf("FAIL: quieted %d", sync.Quieted)
	}
	// Second start: everything is answered, nothing is written.
	np2 := newFakePlane()
	np2.prefs = map[string]notify.SubscriberPreferences{}
	for _, a := range book.accounts {
		wf := map[string]map[string]bool{}
		for _, f := range notify.EmailFamilies() {
			wf[f] = map[string]bool{"email": false}
		}
		np2.prefs[a.Name] = notify.SubscriberPreferences{Workflows: wf}
	}
	sync, _ = reconcileNotify(context.Background(), np2, book)
	if len(np2.setp) != 0 || sync.Quieted != 0 {
		t.Errorf("FAIL: a second start wrote preferences again: %+v", np2.setp)
	}
	t.Log("ok: email is answered no for the unanswered, and only for them")
}