43e72b0d5b
CI / Build (windows/amd64) (pull_request) Successful in 30s
CI / Build (linux/amd64) (pull_request) Successful in 23s
CI / Build (linux/arm64) (pull_request) Successful in 22s
CI / Lint (pull_request) Successful in 1m19s
CI / Test (linux/amd64) (pull_request) Successful in 1m42s
Raise / ack / resolve all rendered with the same title and body on ntfy and SMTP, so a recovery looked identical to the original alert. Webhook was already fine because the JSON envelope carries 'event'. ntfy: Title '[raised · warning] dev backup_failed' (was '[warning] …') Tags 'raised,warning,backup_failed' (was 'warning,backup_failed') Body 'Resolved · <message>' / 'Acknowledged · <message>' on those events SMTP: Subject '[restic-manager] [raised · warning] dev: backup_failed' Plus: cmd/_fake_alert now accepts the ref as a positional argument (go run ./cmd/_fake_alert steve-001) instead of silently ignoring unknown positional args. Refuses ambiguous '-ref X positional Y'.
98 lines
2.4 KiB
Go
98 lines
2.4 KiB
Go
package notification
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNtfySendsHeadersAndBody(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
gotTitle string
|
|
gotPri string
|
|
gotTags string
|
|
gotClick string
|
|
gotAuth string
|
|
gotContentType string
|
|
gotBody string
|
|
)
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotTitle = r.Header.Get("Title")
|
|
gotPri = r.Header.Get("Priority")
|
|
gotTags = r.Header.Get("Tags")
|
|
gotClick = r.Header.Get("Click")
|
|
gotAuth = r.Header.Get("Authorization")
|
|
gotContentType = r.Header.Get("Content-Type")
|
|
b, _ := io.ReadAll(r.Body)
|
|
gotBody = string(b)
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
cfg := NtfyConfig{
|
|
ServerURL: srv.URL,
|
|
Topic: "alerts",
|
|
AccessToken: "tk1",
|
|
}
|
|
ch := NewNtfyChannel(cfg, "") // no default priority; critical must still be "5"
|
|
|
|
p := Payload{
|
|
Event: EventRaised,
|
|
AlertID: "01HZ",
|
|
Severity: "critical",
|
|
Kind: "check_failed",
|
|
HostName: "alfa-01",
|
|
Message: "errors found",
|
|
RaisedAt: time.Now(),
|
|
Link: "https://rm.example/a",
|
|
}
|
|
|
|
code, _, err := ch.Send(t.Context(), p)
|
|
if err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if code != http.StatusOK {
|
|
t.Fatalf("want 200, got %d", code)
|
|
}
|
|
|
|
if want := "[raised · critical] alfa-01 check_failed"; gotTitle != want {
|
|
t.Errorf("Title: got %q want %q", gotTitle, want)
|
|
}
|
|
if gotPri != "5" {
|
|
t.Errorf("Priority: got %q want \"5\"", gotPri)
|
|
}
|
|
if want := "raised,critical,check_failed"; gotTags != want {
|
|
t.Errorf("Tags: got %q want %q", gotTags, want)
|
|
}
|
|
if gotClick != "https://rm.example/a" {
|
|
t.Errorf("Click: got %q want %q", gotClick, "https://rm.example/a")
|
|
}
|
|
if want := "Bearer tk1"; gotAuth != want {
|
|
t.Errorf("Authorization: got %q want %q", gotAuth, want)
|
|
}
|
|
if gotContentType != "text/plain" {
|
|
t.Errorf("Content-Type: got %q want %q", gotContentType, "text/plain")
|
|
}
|
|
if gotBody != "errors found" {
|
|
t.Errorf("body: got %q want %q", gotBody, "errors found")
|
|
}
|
|
}
|
|
|
|
func TestNtfyDefaultPriorityRespected(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// info + defaultPri="min" → "min"
|
|
if got := priorityForSeverity("info", "min"); got != "min" {
|
|
t.Errorf("info+min: got %q want \"min\"", got)
|
|
}
|
|
// critical → "5" regardless of default
|
|
if got := priorityForSeverity("critical", "min"); got != "5" {
|
|
t.Errorf("critical+min: got %q want \"5\"", got)
|
|
}
|
|
}
|