8e6d97710b
Provider.Send now accepts context.Context for timeout/cancellation. HTTPProvider and NtfyProvider use NewRequestWithContext so HTTP alerts respect the 30s deadline. triggerAlert logs send failures and config load errors instead of silently swallowing them.
215 lines
6.6 KiB
Go
215 lines
6.6 KiB
Go
package alert
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"go-upkeep/internal/models"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestHTTPProviderDiscord(t *testing.T) {
|
|
var received map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := GetProvider(models.AlertConfig{Type: "discord", Settings: map[string]string{"url": srv.URL}})
|
|
if err := p.Send(context.Background(), "Test Title", "Test Body"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
|
|
if received["content"] != "**Test Title**\nTest Body" {
|
|
t.Errorf("unexpected payload: %s", received["content"])
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderSlack(t *testing.T) {
|
|
var received map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := GetProvider(models.AlertConfig{Type: "slack", Settings: map[string]string{"url": srv.URL}})
|
|
if err := p.Send(context.Background(), "Alert", "Message"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
|
|
if received["text"] != "*Alert*\nMessage" {
|
|
t.Errorf("unexpected payload: %s", received["text"])
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderWebhook(t *testing.T) {
|
|
var received map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := GetProvider(models.AlertConfig{Type: "webhook", Settings: map[string]string{"url": srv.URL}})
|
|
if err := p.Send(context.Background(), "Title", "Body"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
|
|
if received["title"] != "Title" || received["message"] != "Body" || received["status"] != "alert" {
|
|
t.Errorf("unexpected webhook payload: %v", received)
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderErrorOnHTTP4xx(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(403)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := GetProvider(models.AlertConfig{Type: "discord", Settings: map[string]string{"url": srv.URL}})
|
|
if err := p.Send(context.Background(), "Test", "Test"); err == nil {
|
|
t.Fatal("expected error on 403 response")
|
|
}
|
|
}
|
|
|
|
func TestNtfyProvider(t *testing.T) {
|
|
var title, body string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
title = r.Header.Get("Title")
|
|
buf := make([]byte, 1024)
|
|
n, _ := r.Body.Read(buf)
|
|
body = string(buf[:n])
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := GetProvider(models.AlertConfig{Type: "ntfy", Settings: map[string]string{
|
|
"url": srv.URL,
|
|
"topic": "test",
|
|
}})
|
|
if err := p.Send(context.Background(), "Alert Title", "Alert Body"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
|
|
if title != "Alert Title" {
|
|
t.Errorf("expected title 'Alert Title', got '%s'", title)
|
|
}
|
|
if body != "Alert Body" {
|
|
t.Errorf("expected body 'Alert Body', got '%s'", body)
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderTelegram(t *testing.T) {
|
|
var received map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := &HTTPProvider{URL: srv.URL, Payload: telegramPayload("12345")}
|
|
if err := p.Send(context.Background(), "Alert", "Down"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if received["chat_id"] != "12345" {
|
|
t.Errorf("expected chat_id '12345', got '%s'", received["chat_id"])
|
|
}
|
|
if received["text"] != "*Alert*\nDown" {
|
|
t.Errorf("unexpected text: %s", received["text"])
|
|
}
|
|
if received["parse_mode"] != "Markdown" {
|
|
t.Errorf("expected parse_mode 'Markdown', got '%s'", received["parse_mode"])
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderPagerDuty(t *testing.T) {
|
|
var received map[string]any
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := &HTTPProvider{URL: srv.URL, Payload: pagerdutyPayload("test-key", "critical")}
|
|
if err := p.Send(context.Background(), "Alert", "Down"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if received["routing_key"] != "test-key" {
|
|
t.Errorf("expected routing_key 'test-key', got '%v'", received["routing_key"])
|
|
}
|
|
if received["event_action"] != "trigger" {
|
|
t.Errorf("expected event_action 'trigger', got '%v'", received["event_action"])
|
|
}
|
|
payload := received["payload"].(map[string]any)
|
|
if payload["summary"] != "Alert: Down" {
|
|
t.Errorf("unexpected summary: %v", payload["summary"])
|
|
}
|
|
if payload["severity"] != "critical" {
|
|
t.Errorf("expected severity 'critical', got '%v'", payload["severity"])
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderPushover(t *testing.T) {
|
|
var received map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := &HTTPProvider{URL: srv.URL, Payload: pushoverPayload("app-tok", "user-key")}
|
|
if err := p.Send(context.Background(), "Alert", "Down"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if received["token"] != "app-tok" {
|
|
t.Errorf("expected token 'app-tok', got '%s'", received["token"])
|
|
}
|
|
if received["user"] != "user-key" {
|
|
t.Errorf("expected user 'user-key', got '%s'", received["user"])
|
|
}
|
|
if received["title"] != "Alert" || received["message"] != "Down" {
|
|
t.Errorf("unexpected payload: %v", received)
|
|
}
|
|
}
|
|
|
|
func TestHTTPProviderGotify(t *testing.T) {
|
|
var received map[string]any
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewDecoder(r.Body).Decode(&received)
|
|
w.WriteHeader(200)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := &HTTPProvider{URL: srv.URL, Payload: gotifyPayload("8")}
|
|
if err := p.Send(context.Background(), "Alert", "Down"); err != nil {
|
|
t.Fatalf("Send: %v", err)
|
|
}
|
|
if received["title"] != "Alert" || received["message"] != "Down" {
|
|
t.Errorf("unexpected payload: %v", received)
|
|
}
|
|
if pri, ok := received["priority"].(float64); !ok || pri != 8 {
|
|
t.Errorf("expected priority 8, got %v", received["priority"])
|
|
}
|
|
}
|
|
|
|
func TestGetProviderNewTypes(t *testing.T) {
|
|
for _, typ := range []string{"telegram", "pagerduty", "pushover", "gotify"} {
|
|
p := GetProvider(models.AlertConfig{Type: typ, Settings: map[string]string{
|
|
"token": "x", "chat_id": "1", "routing_key": "k", "user": "u", "url": "http://localhost",
|
|
}})
|
|
if p == nil {
|
|
t.Errorf("GetProvider(%q) returned nil", typ)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetProviderUnknown(t *testing.T) {
|
|
p := GetProvider(models.AlertConfig{Type: "unknown"})
|
|
if p != nil {
|
|
t.Error("expected nil for unknown provider type")
|
|
}
|
|
}
|