Artifact ce3c86cb79ccad053fa2bd7196c4f4fb81f5a0b1e41ff15e56a8ae80524e7311:
- File
internal/api/praise_test.go
— part of check-in
[f1a6be9a77]
at
2026-08-24 19:59:53
on branch praise
— Praise: vocabulary, storage, ops
Any signed-in account may praise any repository it can SEE — no capability letter, because the read gate has already decided whether the repository exists for this caller and past that gate praising is not a privilege anyone needs granting.
Per account, not per contributor: someone who has never authored an artifact can still say a repository is worth attention, which is why this cannot hang off the contributor pages.
praise.list filters by the VIEWER, never the owner. Praise is public; the existence of a private repository is not, and this is where the two meet.
UI deferred: the button belongs in the repo stats strip, which is on the unlanded clone-counts branch. (user: dmestas, size: 4515) [annotate] [blame] [check-ins using] [more...]
package api import ( "context" "encoding/json" "sync" "testing" "craftdesign.group/quarry/internal/ops" ) // remarshalT re-decodes an op's output into its typed form. func remarshalT(t *testing.T, in, out any) { t.Helper() b, err := json.Marshal(in) if err != nil { t.Fatal(err) } if err := json.Unmarshal(b, out); err != nil { t.Fatal(err) } } type fakePraise struct { mu sync.Mutex set map[string]map[string]bool // repo -> account -> praised } func newFakePraise() *fakePraise { return &fakePraise{set: map[string]map[string]bool{}} } func (f *fakePraise) SetPraise(repo, account string, on bool) (bool, error) { f.mu.Lock() defer f.mu.Unlock() if f.set[repo] == nil { f.set[repo] = map[string]bool{} } if on { f.set[repo][account] = true } else { delete(f.set[repo], account) } return on, nil } func (f *fakePraise) Praised(repo, account string) bool { return f.set[repo][account] } func (f *fakePraise) PraiseCount(repo string) int { return len(f.set[repo]) } func (f *fakePraise) PraisedBy(account string) ([]string, error) { var out []string for _, repo := range []string{"alpha", "beta", "secret"} { if f.set[repo][account] { out = append(out, repo) } } return out, nil } // The rule: any signed-in account may praise any repository it can see. // No capability letter is involved, so an account with no grant at all // must succeed. func TestPraiseNeedsOnlyASignedInAccount(t *testing.T) { r := ops.NewRegistry() repos := testRepos(wikiIndex(t)) mustRepo(t, repos, "test").Code = "c1" if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Praise: newFakePraise()}); err != nil { t.Fatal(err) } ctx := ops.WithUser(context.Background(), "grantless") out, err := r.Invoke(ctx, "praise.set", praiseSetIn{Repo: "test", On: true}) if err != nil { t.Fatalf("a signed-in account with no grant could not praise: %v", err) } var got praiseSetOut remarshalT(t, out, &got) if !got.Praised || got.Count != 1 { t.Errorf("praised=%v count=%d, want true 1", got.Praised, got.Count) } } // Praise must be attributable, so anonymous is refused rather than // pooling every stranger into one shared praise. func TestAnonymousCannotPraise(t *testing.T) { r := ops.NewRegistry() repos := testRepos(wikiIndex(t)) mustRepo(t, repos, "test").Code = "c1" if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Praise: newFakePraise()}); err != nil { t.Fatal(err) } if _, err := r.Invoke(context.Background(), "praise.set", praiseSetIn{Repo: "test", On: true}); err == nil { t.Error("anonymous praise was accepted") } } // On is a desired state, not a toggle: a retried request must land where // the reader clicked rather than on the opposite of it. func TestPraiseIsIdempotent(t *testing.T) { r := ops.NewRegistry() repos := testRepos(wikiIndex(t)) mustRepo(t, repos, "test").Code = "c1" if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Praise: newFakePraise()}); err != nil { t.Fatal(err) } ctx := ops.WithUser(context.Background(), "dan") for i := 0; i < 3; i++ { out, err := r.Invoke(ctx, "praise.set", praiseSetIn{Repo: "test", On: true}) if err != nil { t.Fatal(err) } var got praiseSetOut remarshalT(t, out, &got) if !got.Praised || got.Count != 1 { t.Fatalf("attempt %d: praised=%v count=%d", i, got.Praised, got.Count) } } } // A listing is filtered by the VIEWER. Praise is public; the existence // of a private repository is not. func TestPraiseListHidesWhatTheViewerCannotRead(t *testing.T) { r := ops.NewRegistry() ix := wikiIndex(t) repos := NewRepos(map[string]*Repo{ "alpha": {Index: ix, Code: "c-alpha"}, "beta": {Index: ix, Code: "c-beta"}, // Registered, and deliberately unreadable to the viewer below. "secret": {Index: ix, Code: "c-secret"}, }) fp := newFakePraise() for _, n := range []string{"alpha", "beta", "secret"} { fp.SetPraise(n, "dan", true) } if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Praise: fp, CanRead: func(_ context.Context, repo string) bool { return repo != "secret" }, }); err != nil { t.Fatal(err) } out, err := r.Invoke(context.Background(), "praise.list", praiseListIn{User: "dan"}) if err != nil { t.Fatal(err) } var got praiseListOut remarshalT(t, out, &got) for _, repo := range got.Repos { if repo == "secret" { t.Fatalf("a private repository leaked through a praise listing: %v", got.Repos) } } if len(got.Repos) != 2 { t.Errorf("listed %v, want the two readable ones", got.Repos) } }