diff --git a/alerting/provider/matrix/matrix_test.go b/alerting/provider/matrix/matrix_test.go new file mode 100644 index 00000000..1c8cad00 --- /dev/null +++ b/alerting/provider/matrix/matrix_test.go @@ -0,0 +1,295 @@ +package matrix + +import ( + "encoding/json" + "net/http" + "testing" + + "github.com/TwiN/gatus/v4/alerting/alert" + "github.com/TwiN/gatus/v4/client" + "github.com/TwiN/gatus/v4/core" + "github.com/TwiN/gatus/v4/test" +) + +func TestAlertProvider_IsValid(t *testing.T) { + invalidProvider := AlertProvider{AccessToken: "", InternalRoomID: ""} + if invalidProvider.IsValid() { + t.Error("provider shouldn't have been valid") + } + validProvider := AlertProvider{AccessToken: "1", InternalRoomID: "!a:example.com"} + if !validProvider.IsValid() { + t.Error("provider should've been valid") + } + validProviderWithHomeserver := AlertProvider{HomeserverURL: "https://example.com", AccessToken: "1", InternalRoomID: "!a:example.com"} + if !validProviderWithHomeserver.IsValid() { + t.Error("provider with homeserver should've been valid") + } +} + +func TestAlertProvider_IsValidWithOverride(t *testing.T) { + providerWithInvalidOverrideGroup := AlertProvider{ + Overrides: []Override{ + { + AccessToken: "", + InternalRoomID: "", + Group: "", + }, + }, + } + if providerWithInvalidOverrideGroup.IsValid() { + t.Error("provider Group shouldn't have been valid") + } + providerWithInvalidOverrideTo := AlertProvider{ + Overrides: []Override{ + { + AccessToken: "", + InternalRoomID: "", + Group: "group", + }, + }, + } + if providerWithInvalidOverrideTo.IsValid() { + t.Error("provider integration key shouldn't have been valid") + } + providerWithValidOverride := AlertProvider{ + AccessToken: "1", + InternalRoomID: "!a:example.com", + Overrides: []Override{ + { + HomeserverURL: "https://example.com", + AccessToken: "1", + InternalRoomID: "!a:example.com", + Group: "group", + }, + }, + } + if !providerWithValidOverride.IsValid() { + t.Error("provider should've been valid") + } +} + +func TestAlertProvider_Send(t *testing.T) { + defer client.InjectHTTPClient(nil) + firstDescription := "description-1" + secondDescription := "description-2" + scenarios := []struct { + Name string + Provider AlertProvider + Alert alert.Alert + Resolved bool + MockRoundTripper test.MockRoundTripper + ExpectedError bool + }{ + { + Name: "triggered", + Provider: AlertProvider{}, + Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3}, + Resolved: false, + MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response { + return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody} + }), + ExpectedError: false, + }, + { + Name: "triggered-error", + Provider: AlertProvider{}, + Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3}, + Resolved: false, + MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response { + return &http.Response{StatusCode: http.StatusInternalServerError, Body: http.NoBody} + }), + ExpectedError: true, + }, + { + Name: "resolved", + Provider: AlertProvider{}, + Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3}, + Resolved: true, + MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response { + return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody} + }), + ExpectedError: false, + }, + { + Name: "resolved-error", + Provider: AlertProvider{}, + Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3}, + Resolved: true, + MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response { + return &http.Response{StatusCode: http.StatusInternalServerError, Body: http.NoBody} + }), + ExpectedError: true, + }, + } + for _, scenario := range scenarios { + t.Run(scenario.Name, func(t *testing.T) { + client.InjectHTTPClient(&http.Client{Transport: scenario.MockRoundTripper}) + err := scenario.Provider.Send( + &core.Endpoint{Name: "endpoint-name"}, + &scenario.Alert, + &core.Result{ + ConditionResults: []*core.ConditionResult{ + {Condition: "[CONNECTED] == true", Success: scenario.Resolved}, + {Condition: "[STATUS] == 200", Success: scenario.Resolved}, + }, + }, + scenario.Resolved, + ) + if scenario.ExpectedError && err == nil { + t.Error("expected error, got none") + } + if !scenario.ExpectedError && err != nil { + t.Error("expected no error, got", err.Error()) + } + }) + } +} + +func TestAlertProvider_buildRequestBody(t *testing.T) { + firstDescription := "description-1" + secondDescription := "description-2" + scenarios := []struct { + Name string + Provider AlertProvider + Alert alert.Alert + Resolved bool + ExpectedBody string + }{ + { + Name: "triggered", + Provider: AlertProvider{}, + Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3}, + Resolved: false, + ExpectedBody: "{\n\t\"msgtype\": \"m.text\",\n\t\"format\": \"org.matrix.custom.html\",\n\t\"body\": \"An alert for `endpoint-name` has been triggered due to having failed 3 time(s) in a row\\ndescription-1\\n\\n✕ - [CONNECTED] == true\\n✕ - [STATUS] == 200\",\n\t\"formatted_body\": \"
endpoint-name has been triggered due to having failed 3 time(s) in a rowdescription-1\\n
[CONNECTED] == true[STATUS] == 200endpoint-name has been resolved after passing successfully 5 time(s) in a rowdescription-2\\n
[CONNECTED] == true[STATUS] == 200