Add test notification functionality for Apprise
- Add support for testing Apprise notifications via /api/notifications/test endpoint - Users can now test their Apprise configuration (both CLI and HTTP modes) using method="apprise" - Added comprehensive unit tests for both CLI and HTTP modes - Tests verify correct behavior when Apprise is enabled/disabled - Tests validate that notifications are properly sent through Apprise channels Related to #584
This commit is contained in:
parent
6404b6a5fc
commit
02864f54dd
2 changed files with 147 additions and 0 deletions
|
|
@ -2013,6 +2013,24 @@ func (n *NotificationManager) SendTestNotification(method string) error {
|
|||
}
|
||||
n.sendWebhook(*webhookToTest, testAlert)
|
||||
return nil
|
||||
case "apprise":
|
||||
n.mu.RLock()
|
||||
appriseConfig := n.appriseConfig
|
||||
n.mu.RUnlock()
|
||||
|
||||
log.Info().
|
||||
Bool("enabled", appriseConfig.Enabled).
|
||||
Str("mode", string(appriseConfig.Mode)).
|
||||
Int("targetCount", len(appriseConfig.Targets)).
|
||||
Msg("Testing Apprise notification")
|
||||
|
||||
if !appriseConfig.Enabled {
|
||||
return fmt.Errorf("apprise notifications are not enabled")
|
||||
}
|
||||
|
||||
// Use sendGroupedApprise with a single test alert
|
||||
n.sendGroupedApprise(appriseConfig, []*alerts.Alert{testAlert})
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown notification method: %s", method)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,3 +493,132 @@ func TestRenderWebhookURL_InvalidTemplate(t *testing.T) {
|
|||
t.Fatalf("expected error for invalid URL template, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendTestNotificationApprise(t *testing.T) {
|
||||
nm := NewNotificationManager("")
|
||||
nm.SetEmailConfig(EmailConfig{Enabled: false})
|
||||
|
||||
// Test 1: Apprise not enabled should return error
|
||||
nm.SetAppriseConfig(AppriseConfig{
|
||||
Enabled: false,
|
||||
Targets: []string{"discord://token"},
|
||||
})
|
||||
|
||||
err := nm.SendTestNotification("apprise")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error when Apprise is disabled, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "not enabled") {
|
||||
t.Fatalf("expected 'not enabled' error, got: %v", err)
|
||||
}
|
||||
|
||||
// Test 2: Apprise enabled with CLI mode should invoke executor
|
||||
done := make(chan struct{})
|
||||
var capturedArgs []string
|
||||
|
||||
nm.appriseExec = func(ctx context.Context, path string, args []string) ([]byte, error) {
|
||||
if path != "apprise" {
|
||||
t.Fatalf("expected CLI path 'apprise', got %q", path)
|
||||
}
|
||||
capturedArgs = append([]string(nil), args...)
|
||||
close(done)
|
||||
return []byte("success"), nil
|
||||
}
|
||||
|
||||
nm.SetAppriseConfig(AppriseConfig{
|
||||
Enabled: true,
|
||||
Targets: []string{"discord://token"},
|
||||
TimeoutSeconds: 10,
|
||||
})
|
||||
|
||||
err = nm.SendTestNotification("apprise")
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error when testing Apprise, got: %v", err)
|
||||
}
|
||||
|
||||
// Wait for the executor to be called
|
||||
select {
|
||||
case <-done:
|
||||
// Success - executor was called
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatalf("timeout waiting for Apprise executor to be called")
|
||||
}
|
||||
|
||||
// Verify the arguments contain the target
|
||||
foundTarget := false
|
||||
for _, arg := range capturedArgs {
|
||||
if arg == "discord://token" {
|
||||
foundTarget = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundTarget {
|
||||
t.Fatalf("expected target 'discord://token' in args, got: %v", capturedArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendTestNotificationAppriseHTTP(t *testing.T) {
|
||||
nm := NewNotificationManager("")
|
||||
nm.SetEmailConfig(EmailConfig{Enabled: false})
|
||||
|
||||
type apprisePayload struct {
|
||||
Body string `json:"body"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
URLs []string `json:"urls"`
|
||||
}
|
||||
|
||||
requests := make(chan apprisePayload, 1)
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var payload apprisePayload
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
requests <- payload
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"ok": true}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
nm.SetAppriseConfig(AppriseConfig{
|
||||
Enabled: true,
|
||||
Mode: AppriseModeHTTP,
|
||||
ServerURL: server.URL,
|
||||
ConfigKey: "test-key",
|
||||
TimeoutSeconds: 10,
|
||||
})
|
||||
|
||||
err := nm.SendTestNotification("apprise")
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error when testing Apprise HTTP, got: %v", err)
|
||||
}
|
||||
|
||||
// Wait for the HTTP request
|
||||
select {
|
||||
case payload := <-requests:
|
||||
// Verify the payload contains test alert information
|
||||
if payload.Title == "" {
|
||||
t.Fatalf("expected non-empty title in Apprise payload")
|
||||
}
|
||||
if payload.Body == "" {
|
||||
t.Fatalf("expected non-empty body in Apprise payload")
|
||||
}
|
||||
if !strings.Contains(payload.Body, "test alert") && !strings.Contains(payload.Body, "Test Resource") {
|
||||
t.Fatalf("expected test alert content in body, got: %s", payload.Body)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatalf("timeout waiting for Apprise HTTP request")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue