Files
br ca6cdcca63 software steht so weit.
jetzt build + docker build und testen
2026-10-02 13:25:34 +02:00

134 lines
3.7 KiB
Go

package notify
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
)
type received struct {
mu sync.Mutex
reqs []*http.Request
body []string
}
func (r *received) handler(status int) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
b, _ := io.ReadAll(req.Body)
r.mu.Lock()
r.reqs = append(r.reqs, req)
r.body = append(r.body, string(b))
r.mu.Unlock()
w.WriteHeader(status)
}
}
var msg = Message{
Title: "Vertrag kunde läuft ab",
Body: "Noch *14 Tage* bis 2026-12-15.",
Severity: Critical,
}
func TestSlack(t *testing.T) {
var got received
srv := httptest.NewServer(got.handler(200))
defer srv.Close()
if err := (Slack{URL: srv.URL}).Send(context.Background(), msg); err != nil {
t.Fatal(err)
}
if ct := got.reqs[0].Header.Get("Content-Type"); ct != "application/json" {
t.Errorf("Content-Type %q", ct)
}
var payload map[string]string
if err := json.Unmarshal([]byte(got.body[0]), &payload); err != nil {
t.Fatal(err)
}
text := payload["text"]
if !strings.Contains(text, "*Vertrag kunde läuft ab*") || !strings.Contains(text, "Noch *14 Tage*") || !strings.Contains(text, ":rotating_light:") {
t.Errorf("text = %q", text)
}
}
func TestNtfy(t *testing.T) {
var got received
srv := httptest.NewServer(got.handler(200))
defer srv.Close()
if err := (Ntfy{URL: srv.URL + "/sultan", Token: "tk_geheim"}).Send(context.Background(), msg); err != nil {
t.Fatal(err)
}
r := got.reqs[0]
if r.URL.Path != "/sultan" || got.body[0] != msg.Body {
t.Errorf("Pfad %q, Body %q", r.URL.Path, got.body[0])
}
for h, want := range map[string]string{
"Title": "Vertrag kunde läuft ab",
"Priority": "urgent",
"Tags": "rotating_light",
"Markdown": "yes",
"Authorization": "Bearer tk_geheim",
} {
if r.Header.Get(h) != want {
t.Errorf("%s = %q, erwartet %q", h, r.Header.Get(h), want)
}
}
}
func TestSeverityMapping(t *testing.T) {
for sev, want := range map[Severity][2]string{
Info: {"default", "information_source"},
Warning: {"high", "warning"},
Critical: {"urgent", "rotating_light"},
} {
var got received
srv := httptest.NewServer(got.handler(200))
(Ntfy{URL: srv.URL}).Send(context.Background(), Message{Title: "x", Body: "y", Severity: sev})
srv.Close()
if got.reqs[0].Header.Get("Priority") != want[0] || got.reqs[0].Header.Get("Tags") != want[1] {
t.Errorf("%v: Priority %q Tags %q", sev, got.reqs[0].Header.Get("Priority"), got.reqs[0].Header.Get("Tags"))
}
if got.reqs[0].Header.Get("Authorization") != "" {
t.Error("Authorization ohne Token gesetzt")
}
}
}
func TestErrors(t *testing.T) {
var got received
bad := httptest.NewServer(got.handler(500))
defer bad.Close()
for _, target := range []Target{Slack{URL: bad.URL}, Ntfy{URL: bad.URL}, Slack{URL: "http://127.0.0.1:1"}} {
if err := target.Send(context.Background(), msg); err == nil {
t.Errorf("%T: erwartet Fehler", target)
}
}
}
// Multi sendet an alle Ziele; ein Fehler bei einem Ziel hält die anderen nicht auf.
func TestMulti(t *testing.T) {
var a, b received
okA := httptest.NewServer(a.handler(200))
okB := httptest.NewServer(b.handler(200))
bad := httptest.NewServer((&received{}).handler(500))
defer okA.Close()
defer okB.Close()
defer bad.Close()
m := Multi{Slack{URL: okA.URL}, Ntfy{URL: bad.URL}, Ntfy{URL: okB.URL}}
err := m.Send(context.Background(), msg)
if err == nil {
t.Error("Fehler eines Ziels nicht gemeldet")
}
if len(a.reqs) != 1 || len(b.reqs) != 1 {
t.Errorf("nicht alle Ziele erreicht: %d/%d", len(a.reqs), len(b.reqs))
}
if !errors.Is(Multi{}.Send(context.Background(), msg), ErrNoTargets) {
t.Error("leeres Multi: erwartet ErrNoTargets")
}
}