@@ -201,3 +201,137 @@ func TestDeleteCheckViaDashboard(t *testing.T) {
201201 t .Fatalf ("GetCheck() error = %v, want ErrNotFound" , err )
202202 }
203203}
204+
205+ func TestTriggerCheckAPI (t * testing.T ) {
206+ t .Parallel ()
207+
208+ dir := t .TempDir ()
209+ dataStore , err := store .NewFileStore (filepath .Join (dir , "pingtower.json" ))
210+ if err != nil {
211+ t .Fatalf ("NewFileStore() error = %v" , err )
212+ }
213+
214+ created , err := dataStore .CreateCheck (model.Check {
215+ Name : "Trigger Test" ,
216+ URL : "https://example.com" ,
217+ IntervalSeconds : 60 ,
218+ TimeoutSeconds : 5 ,
219+ ExpectedStatusCode : 200 ,
220+ })
221+ if err != nil {
222+ t .Fatalf ("CreateCheck() error = %v" , err )
223+ }
224+
225+ server := NewServer (config .Load (), log .New (io .Discard , "" , 0 ), dataStore )
226+ server .SetTriggerer (& stubTriggerer {result : model.Result {
227+ CheckID : created .ID ,
228+ Status : "healthy" ,
229+ }})
230+
231+ req := httptest .NewRequest (http .MethodPost , "/checks/" + created .ID + "/trigger" , nil )
232+ res := httptest .NewRecorder ()
233+ server .Handler ().ServeHTTP (res , req )
234+
235+ if res .Code != http .StatusOK {
236+ t .Fatalf ("POST /checks/{id}/trigger status = %d, want %d" , res .Code , http .StatusOK )
237+ }
238+
239+ var result model.Result
240+ if err := json .NewDecoder (res .Body ).Decode (& result ); err != nil {
241+ t .Fatalf ("decode result: %v" , err )
242+ }
243+ if result .Status != "healthy" {
244+ t .Fatalf ("result.Status = %q, want %q" , result .Status , "healthy" )
245+ }
246+ }
247+
248+ func TestTriggerCheckAPI_NotFound (t * testing.T ) {
249+ t .Parallel ()
250+
251+ dir := t .TempDir ()
252+ dataStore , err := store .NewFileStore (filepath .Join (dir , "pingtower.json" ))
253+ if err != nil {
254+ t .Fatalf ("NewFileStore() error = %v" , err )
255+ }
256+
257+ server := NewServer (config .Load (), log .New (io .Discard , "" , 0 ), dataStore )
258+ server .SetTriggerer (& stubTriggerer {err : store .ErrNotFound })
259+
260+ req := httptest .NewRequest (http .MethodPost , "/checks/nonexistent/trigger" , nil )
261+ res := httptest .NewRecorder ()
262+ server .Handler ().ServeHTTP (res , req )
263+
264+ if res .Code != http .StatusNotFound {
265+ t .Fatalf ("status = %d, want %d" , res .Code , http .StatusNotFound )
266+ }
267+ }
268+
269+ func TestTriggerCheckAPI_NoTriggerer (t * testing.T ) {
270+ t .Parallel ()
271+
272+ dir := t .TempDir ()
273+ dataStore , err := store .NewFileStore (filepath .Join (dir , "pingtower.json" ))
274+ if err != nil {
275+ t .Fatalf ("NewFileStore() error = %v" , err )
276+ }
277+
278+ server := NewServer (config .Load (), log .New (io .Discard , "" , 0 ), dataStore )
279+
280+ req := httptest .NewRequest (http .MethodPost , "/checks/anything/trigger" , nil )
281+ res := httptest .NewRecorder ()
282+ server .Handler ().ServeHTTP (res , req )
283+
284+ if res .Code != http .StatusNotImplemented {
285+ t .Fatalf ("status = %d, want %d" , res .Code , http .StatusNotImplemented )
286+ }
287+ }
288+
289+ func TestTriggerCheckDashboard (t * testing.T ) {
290+ t .Parallel ()
291+
292+ dir := t .TempDir ()
293+ dataStore , err := store .NewFileStore (filepath .Join (dir , "pingtower.json" ))
294+ if err != nil {
295+ t .Fatalf ("NewFileStore() error = %v" , err )
296+ }
297+
298+ created , err := dataStore .CreateCheck (model.Check {
299+ Name : "Dashboard Trigger Test" ,
300+ URL : "https://example.com" ,
301+ IntervalSeconds : 60 ,
302+ TimeoutSeconds : 5 ,
303+ ExpectedStatusCode : 200 ,
304+ })
305+ if err != nil {
306+ t .Fatalf ("CreateCheck() error = %v" , err )
307+ }
308+
309+ server := NewServer (config .Load (), log .New (io .Discard , "" , 0 ), dataStore )
310+ server .SetTriggerer (& stubTriggerer {result : model.Result {
311+ CheckID : created .ID ,
312+ Status : "healthy" ,
313+ }})
314+
315+ form := url.Values {"redirect_to" : []string {"/checks/" + created .ID + "/view" }}
316+ req := httptest .NewRequest (http .MethodPost , "/dashboard/checks/" + created .ID + "/trigger" , bytes .NewBufferString (form .Encode ()))
317+ req .Header .Set ("Content-Type" , "application/x-www-form-urlencoded" )
318+ res := httptest .NewRecorder ()
319+ server .Handler ().ServeHTTP (res , req )
320+
321+ if res .Code != http .StatusSeeOther {
322+ t .Fatalf ("dashboard trigger status = %d, want %d" , res .Code , http .StatusSeeOther )
323+ }
324+ if loc := res .Header ().Get ("Location" ); loc != "/checks/" + created .ID + "/view" {
325+ t .Fatalf ("Location = %q, want detail page" , loc )
326+ }
327+ }
328+
329+ // stubTriggerer is a test double for the Triggerer interface.
330+ type stubTriggerer struct {
331+ result model.Result
332+ err error
333+ }
334+
335+ func (s * stubTriggerer ) RunNow (_ string ) (model.Result , error ) {
336+ return s .result , s .err
337+ }
0 commit comments