Artifact 8ea9d98c79346f291b857cbc469027b32dbdc53d88b74193417d6820d19a6248:
- File
internal/notify/notify_test.go
— part of check-in
[e33f1c4e8c]
at
2026-08-17 00:19:10
on branch trunk
— notify: authenticate triggers, and embed the inbox
Two things, one of them a live bug. notify's /v1 routes sit behind an API-key middleware and quarry's client sent no Authorization header, so every trigger it fired would have been answered 401. It went unnoticed because --notify was never configured and a trigger failure is logged rather than raised. --notify-key (or QUARRY_NOTIFY_KEY) supplies it, and serve says so at startup when it is missing rather than leaving the answer to be discovered in the log.
The inbox is notify's, embedded (0001 §5): GET /v1/messages?channel=in_app for the signed-in account, rendered with unread emphasised. quarry models no notification state — it displays what notify owns.
The wire field names are notify's Go field names: its domain.Message carries db tags but no json tags, so the encoder falls back to the identifiers. A test pins that, since decoding lowercase would silently produce empty subjects.
An outage is not emptiness: a failed fetch says notifications are unavailable instead of showing an empty list, which would be a lie about whether anyone had written to you. (user: dmestas, size: 1901) [annotate] [blame] [check-ins using]
package notify import ( "context" "encoding/json" "io" "net/http" "net/http/httptest" "testing" ) // The client POSTs the Novu-shaped trigger to /v1/events/trigger. func TestTriggerShape(t *testing.T) { var got map[string]any srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/v1/events/trigger" || r.Method != "POST" { t.Errorf("unexpected %s %s", r.Method, r.URL.Path) } b, _ := io.ReadAll(r.Body) json.Unmarshal(b, &got) w.WriteHeader(201) })) defer srv.Close() c := New(srv.URL, "") err := c.Trigger(context.Background(), "quarry-mention", Recipient{SubscriberID: "dan"}, map[string]any{"repo": "r1", "text": "hi @dan"}, "txn-1") if err != nil { t.Fatal(err) } if got["name"] != "quarry-mention" || got["transactionId"] != "txn-1" { t.Fatalf("trigger body = %+v", got) } to := got["to"].(map[string]any) if to["subscriberId"] != "dan" { t.Fatalf("recipient = %+v", to) } if p := got["payload"].(map[string]any); p["repo"] != "r1" { t.Fatalf("payload = %+v", p) } } // A disabled client (empty base) no-ops without a call. func TestDisabledClientNoOps(t *testing.T) { if err := New("", "").Trigger(context.Background(), "x", Recipient{}, nil, ""); err != nil { t.Fatalf("disabled client should no-op: %v", err) } var nilClient *Client if err := nilClient.Trigger(context.Background(), "x", Recipient{}, nil, ""); err != nil { t.Fatalf("nil client should no-op: %v", err) } } // A non-2xx response surfaces as an error (best-effort callers log it). func TestTriggerErrorStatus(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(500) })) defer srv.Close() if err := New(srv.URL, "").Trigger(context.Background(), "x", Recipient{SubscriberID: "u"}, nil, ""); err == nil { t.Fatal("want error on 500") } }