package notify_test import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "git.ryuvia.com/niklas/terdut-server/internal/notify" ) func TestRegistry_NilAndEmptyAreEmpty(t *testing.T) { var nilReg *notify.Registry for name, r := range map[string]*notify.Registry{"nil": nilReg, "empty": notify.NewRegistry()} { if !r.Empty() || r.Has("ntfy") || len(r.List()) != 0 { t.Errorf("%s registry should be empty", name) } if _, ok := r.Get("ntfy"); ok { t.Errorf("%s registry should have no ntfy", name) } } } func TestRegistry_ListIsOrderedByType(t *testing.T) { r := notify.NewRegistry(notify.NewNtfy("http://x", ""), fakeProvider{"email"}) list := r.List() if len(list) != 2 || list[0].Type() != "email" || list[1].Type() != "ntfy" { t.Errorf("expected providers ordered by type, got %v", list) } } type fakeProvider struct{ typ string } func (f fakeProvider) Type() string { return f.typ } func (f fakeProvider) Label() string { return f.typ } func (f fakeProvider) AddressLabel() string { return "" } func (f fakeProvider) AddressHint() string { return "" } func (f fakeProvider) Capabilities() notify.Capabilities { return notify.Capabilities{} } func (f fakeProvider) Validate(a string) (string, error) { return a, nil } func (f fakeProvider) Send(context.Context, notify.Message) error { return nil } func TestNtfy_ValidateTopic(t *testing.T) { n := notify.NewNtfy("http://x", "") for _, bad := range []string{"", " ", "a b", "a/b", "a?b", "a#b"} { if _, err := n.Validate(bad); err == nil { t.Errorf("topic %q should be rejected", bad) } } if got, err := n.Validate(" my-topic "); err != nil || got != "my-topic" { t.Errorf("a good topic should be trimmed and accepted, got %q, %v", got, err) } } func TestNtfy_SendEncodesTheMessage(t *testing.T) { var got map[string]any var auth string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { auth = r.Header.Get("Authorization") _ = json.NewDecoder(r.Body).Decode(&got) })) defer srv.Close() n := notify.NewNtfy(srv.URL+"/", "tok") err := n.Send(context.Background(), notify.Message{ Address: "t", Kind: notify.KindTriggered, Title: "T", Body: "B", Level: 4, ClickURL: "https://x/incidents/1", AckURL: "https://x/ack", }) if err != nil { t.Fatal(err) } if auth != "Bearer tok" { t.Errorf("expected the bearer token, got %q", auth) } if got["topic"] != "t" || got["title"] != "T" || got["message"] != "B" || got["priority"] != float64(5) { t.Errorf("unexpected body %v", got) } actions, _ := got["actions"].([]any) if len(actions) != 1 || actions[0].(map[string]any)["url"] != "https://x/ack" { t.Errorf("expected the Acknowledge action, got %v", got["actions"]) } } func TestNtfy_ResolvedIsQuietAndTestHasNoPriority(t *testing.T) { var got map[string]any srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { got = nil _ = json.NewDecoder(r.Body).Decode(&got) })) defer srv.Close() n := notify.NewNtfy(srv.URL, "") _ = n.Send(context.Background(), notify.Message{Address: "t", Kind: notify.KindResolved, Level: 4}) if got["priority"] != float64(2) { t.Errorf("a resolved page should be low priority whatever the severity, got %v", got["priority"]) } _ = n.Send(context.Background(), notify.Message{Address: "t", Kind: notify.KindTest}) if _, ok := got["priority"]; ok { t.Errorf("a test should carry no priority, got %v", got["priority"]) } } func TestNtfy_SendReportsARejection(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusForbidden) })) defer srv.Close() if err := notify.NewNtfy(srv.URL, "").Send(context.Background(), notify.Message{Address: "t"}); err == nil { t.Error("a 403 from ntfy must be an error so the notifier retries") } }