55 "encoding/json"
66 "net/http"
77 "net/http/httptest"
8+ "sync/atomic"
89 "testing"
910 "time"
1011
@@ -16,107 +17,109 @@ import (
1617func TestAlertNotifier_Notify (t * testing.T ) {
1718 t .Parallel ()
1819
19- tests := []struct {
20- name string
21- handler func (w http.ResponseWriter , r * http.Request )
22- notifierOpts []alert.NotifierOption
23- wantErr bool
24- errContains string
25- }{
26- {
27- name : "successful notification" ,
28- handler : func (w http.ResponseWriter , r * http.Request ) {
29- // Verify request
30- assert .Equal (t , "application/json" , r .Header .Get ("Content-Type" ))
31-
32- // Read and verify request body
33- var body map [string ]interface {}
34- err := json .NewDecoder (r .Body ).Decode (& body )
35- require .NoError (t , err )
36-
37- assert .Equal (t , "alert.consecutive_failure" , body ["topic" ])
38- data := body ["data" ].(map [string ]interface {})
39- assert .Equal (t , float64 (10 ), data ["max_consecutive_failures" ])
40- assert .Equal (t , float64 (5 ), data ["consecutive_failures" ])
41- assert .Equal (t , true , data ["will_disable" ])
42-
43- // Log raw JSON for debugging
44- rawJSON , _ := json .Marshal (body )
45- t .Logf ("Raw JSON: %s" , string (rawJSON ))
46-
47- w .WriteHeader (http .StatusOK )
48- },
49- },
50- {
51- name : "server error" ,
52- handler : func (w http.ResponseWriter , r * http.Request ) {
53- w .WriteHeader (http .StatusInternalServerError )
54- },
55- wantErr : true ,
56- errContains : "alert callback failed with status 500" ,
57- },
58- {
59- name : "invalid response status" ,
60- handler : func (w http.ResponseWriter , r * http.Request ) {
61- w .WriteHeader (http .StatusBadRequest )
62- },
63- wantErr : true ,
64- errContains : "alert callback failed with status 400" ,
65- },
66- {
67- name : "timeout exceeded" ,
68- handler : func (w http.ResponseWriter , r * http.Request ) {
69- time .Sleep (100 * time .Millisecond )
70- w .WriteHeader (http .StatusOK )
71- },
72- notifierOpts : []alert.NotifierOption {alert .NotifierWithTimeout (50 * time .Millisecond )},
73- wantErr : true ,
74- errContains : "context deadline exceeded" ,
75- },
76- {
77- name : "successful notification with bearer token" ,
78- handler : func (w http.ResponseWriter , r * http.Request ) {
79- assert .Equal (t , "Bearer test-token" , r .Header .Get ("Authorization" ))
80- w .WriteHeader (http .StatusOK )
20+ t .Run ("successful notification" , func (t * testing.T ) {
21+ t .Parallel ()
22+ var called atomic.Bool
23+
24+ ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
25+ called .Store (true )
26+ // Verify request
27+ assert .Equal (t , "application/json" , r .Header .Get ("Content-Type" ))
28+
29+ // Read and verify request body
30+ var body map [string ]any
31+ err := json .NewDecoder (r .Body ).Decode (& body )
32+ require .NoError (t , err )
33+
34+ assert .Equal (t , "alert.consecutive_failure" , body ["topic" ])
35+ data := body ["data" ].(map [string ]any )
36+ assert .Equal (t , float64 (10 ), data ["max_consecutive_failures" ])
37+ assert .Equal (t , float64 (5 ), data ["consecutive_failures" ])
38+ assert .Equal (t , true , data ["will_disable" ])
39+
40+ w .WriteHeader (http .StatusOK )
41+ }))
42+ defer ts .Close ()
43+
44+ notifier := alert .NewHTTPAlertNotifier (ts .URL )
45+ dest := & alert.AlertDestination {ID : "dest_123" , TenantID : "tenant_123" }
46+ testAlert := alert .NewConsecutiveFailureAlert (alert.ConsecutiveFailureData {
47+ MaxConsecutiveFailures : 10 ,
48+ ConsecutiveFailures : 5 ,
49+ WillDisable : true ,
50+ Destination : dest ,
51+ AttemptResponse : map [string ]any {
52+ "status" : "error" ,
53+ "data" : map [string ]any {"code" : "ETIMEDOUT" },
8154 },
82- notifierOpts : []alert.NotifierOption {alert .NotifierWithBearerToken ("test-token" )},
83- },
84- }
85-
86- for _ , tt := range tests {
87- tt := tt
88- t .Run (tt .name , func (t * testing.T ) {
89- t .Parallel ()
90-
91- // Create test server
92- ts := httptest .NewServer (http .HandlerFunc (tt .handler ))
93- defer ts .Close ()
94-
95- // Create notifier
96- notifier := alert .NewHTTPAlertNotifier (ts .URL , tt .notifierOpts ... )
97-
98- // Create test alert
99- dest := & alert.AlertDestination {ID : "dest_123" , TenantID : "tenant_123" }
100- testAlert := alert .NewConsecutiveFailureAlert (alert.ConsecutiveFailureData {
101- MaxConsecutiveFailures : 10 ,
102- ConsecutiveFailures : 5 ,
103- WillDisable : true ,
104- Destination : dest ,
105- AttemptResponse : map [string ]interface {}{
106- "status" : "error" ,
107- "data" : map [string ]any {"code" : "ETIMEDOUT" },
108- },
109- })
110-
111- // Send alert
112- err := notifier .Notify (context .Background (), testAlert )
113-
114- if tt .wantErr {
115- require .Error (t , err )
116- assert .ErrorContains (t , err , tt .errContains )
117- } else {
118- require .NoError (t , err )
119- }
12055 })
121- }
56+
57+ err := notifier .Notify (context .Background (), testAlert )
58+ require .NoError (t , err )
59+ assert .True (t , called .Load (), "handler should have been called" )
60+ })
61+
62+ t .Run ("successful notification with bearer token" , func (t * testing.T ) {
63+ t .Parallel ()
64+ var called atomic.Bool
65+
66+ ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
67+ called .Store (true )
68+ assert .Equal (t , "Bearer test-token" , r .Header .Get ("Authorization" ))
69+ w .WriteHeader (http .StatusOK )
70+ }))
71+ defer ts .Close ()
72+
73+ notifier := alert .NewHTTPAlertNotifier (ts .URL , alert .NotifierWithBearerToken ("test-token" ))
74+ dest := & alert.AlertDestination {ID : "dest_123" , TenantID : "tenant_123" }
75+ testAlert := alert .NewConsecutiveFailureAlert (alert.ConsecutiveFailureData {
76+ MaxConsecutiveFailures : 10 ,
77+ ConsecutiveFailures : 5 ,
78+ WillDisable : true ,
79+ Destination : dest ,
80+ })
81+
82+ err := notifier .Notify (context .Background (), testAlert )
83+ require .NoError (t , err )
84+ assert .True (t , called .Load (), "handler should have been called" )
85+ })
86+
87+ t .Run ("server error returns error" , func (t * testing.T ) {
88+ t .Parallel ()
89+
90+ ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
91+ w .WriteHeader (http .StatusInternalServerError )
92+ }))
93+ defer ts .Close ()
94+
95+ notifier := alert .NewHTTPAlertNotifier (ts .URL )
96+ dest := & alert.AlertDestination {ID : "dest_123" , TenantID : "tenant_123" }
97+ testAlert := alert .NewConsecutiveFailureAlert (alert.ConsecutiveFailureData {
98+ Destination : dest ,
99+ })
100+
101+ err := notifier .Notify (context .Background (), testAlert )
102+ require .Error (t , err )
103+ assert .Contains (t , err .Error (), "status 500" )
104+ })
105+
106+ t .Run ("timeout returns error" , func (t * testing.T ) {
107+ t .Parallel ()
108+
109+ ts := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
110+ time .Sleep (100 * time .Millisecond )
111+ w .WriteHeader (http .StatusOK )
112+ }))
113+ defer ts .Close ()
114+
115+ notifier := alert .NewHTTPAlertNotifier (ts .URL , alert .NotifierWithTimeout (50 * time .Millisecond ))
116+ dest := & alert.AlertDestination {ID : "dest_123" , TenantID : "tenant_123" }
117+ testAlert := alert .NewConsecutiveFailureAlert (alert.ConsecutiveFailureData {
118+ Destination : dest ,
119+ })
120+
121+ err := notifier .Notify (context .Background (), testAlert )
122+ require .Error (t , err )
123+ assert .Contains (t , err .Error (), "failed to send alert" )
124+ })
122125}
0 commit comments