mirror of
https://github.com/TwiN/gatus.git
synced 2025-01-10 07:58:21 +01:00
e307d1ab35
* feat(alerting): Add group-specific webhook URL for discord Add group-specific webhook URL for discord alert Provides support for paging multiple Discords based on the group selector while keeping backward compatibility to the old Discords configuration manifest integration per team can be specified in the overrides sections in an array form. ref: #96 Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * docs: update Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * Update README.md * Update README.md * Update alerting/provider/discord/discord.go Co-authored-by: TwiN <twin@linux.com> * Update README.md Co-authored-by: TwiN <twin@linux.com> * test: revert testing name * Update alerting/provider/discord/discord_test.go Co-authored-by: TwiN <twin@linux.com> Co-authored-by: TwiN <twin@linux.com>
259 lines
8.2 KiB
Go
259 lines
8.2 KiB
Go
package discord
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/TwiN/gatus/v3/alerting/alert"
|
|
"github.com/TwiN/gatus/v3/client"
|
|
"github.com/TwiN/gatus/v3/core"
|
|
"github.com/TwiN/gatus/v3/test"
|
|
)
|
|
|
|
func TestAlertProvider_IsValid(t *testing.T) {
|
|
invalidProvider := AlertProvider{WebhookURL: ""}
|
|
if invalidProvider.IsValid() {
|
|
t.Error("provider shouldn't have been valid")
|
|
}
|
|
validProvider := AlertProvider{WebhookURL: "http://example.com"}
|
|
if !validProvider.IsValid() {
|
|
t.Error("provider should've been valid")
|
|
}
|
|
}
|
|
|
|
func TestAlertProvider_IsValidWithOverride(t *testing.T) {
|
|
providerWithInvalidOverrideGroup := AlertProvider{
|
|
Overrides: []Override{
|
|
{
|
|
WebhookURL: "http://example.com",
|
|
Group: "",
|
|
},
|
|
},
|
|
}
|
|
if providerWithInvalidOverrideGroup.IsValid() {
|
|
t.Error("provider Group shouldn't have been valid")
|
|
}
|
|
providerWithInvalidOverrideTo := AlertProvider{
|
|
Overrides: []Override{
|
|
{
|
|
WebhookURL: "",
|
|
Group: "group",
|
|
},
|
|
},
|
|
}
|
|
if providerWithInvalidOverrideTo.IsValid() {
|
|
t.Error("provider integration key shouldn't have been valid")
|
|
}
|
|
providerWithValidOverride := AlertProvider{
|
|
WebhookURL: "http://example.com",
|
|
Overrides: []Override{
|
|
{
|
|
WebhookURL: "http://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 \"content\": \"\",\n \"embeds\": [\n {\n \"title\": \":helmet_with_white_cross: Gatus\",\n \"description\": \"An alert for **endpoint-name** has been triggered due to having failed 3 time(s) in a row:\\n> description-1\",\n \"color\": 15158332,\n \"fields\": [\n {\n \"name\": \"Condition results\",\n \"value\": \":x: - `[CONNECTED] == true`\\n:x: - `[STATUS] == 200`\\n\",\n \"inline\": false\n }\n ]\n }\n ]\n}",
|
|
},
|
|
{
|
|
Name: "resolved",
|
|
Provider: AlertProvider{},
|
|
Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
|
Resolved: true,
|
|
ExpectedBody: "{\n \"content\": \"\",\n \"embeds\": [\n {\n \"title\": \":helmet_with_white_cross: Gatus\",\n \"description\": \"An alert for **endpoint-name** has been resolved after passing successfully 5 time(s) in a row:\\n> description-2\",\n \"color\": 3066993,\n \"fields\": [\n {\n \"name\": \"Condition results\",\n \"value\": \":white_check_mark: - `[CONNECTED] == true`\\n:white_check_mark: - `[STATUS] == 200`\\n\",\n \"inline\": false\n }\n ]\n }\n ]\n}",
|
|
},
|
|
}
|
|
for _, scenario := range scenarios {
|
|
t.Run(scenario.Name, func(t *testing.T) {
|
|
body := scenario.Provider.buildRequestBody(
|
|
&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 body != scenario.ExpectedBody {
|
|
t.Errorf("expected %s, got %s", scenario.ExpectedBody, body)
|
|
}
|
|
out := make(map[string]interface{})
|
|
if err := json.Unmarshal([]byte(body), &out); err != nil {
|
|
t.Error("expected body to be valid JSON, got error:", err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAlertProvider_GetDefaultAlert(t *testing.T) {
|
|
if (AlertProvider{DefaultAlert: &alert.Alert{}}).GetDefaultAlert() == nil {
|
|
t.Error("expected default alert to be not nil")
|
|
}
|
|
if (AlertProvider{DefaultAlert: nil}).GetDefaultAlert() != nil {
|
|
t.Error("expected default alert to be nil")
|
|
}
|
|
}
|
|
|
|
func TestAlertProvider_getWebhookURLForGroup(t *testing.T) {
|
|
tests := []struct {
|
|
Name string
|
|
Provider AlertProvider
|
|
InputGroup string
|
|
ExpectedOutput string
|
|
}{
|
|
{
|
|
Name: "provider-no-override-specify-no-group-should-default",
|
|
Provider: AlertProvider{
|
|
WebhookURL: "http://example.com",
|
|
Overrides: nil,
|
|
},
|
|
InputGroup: "",
|
|
ExpectedOutput: "http://example.com",
|
|
},
|
|
{
|
|
Name: "provider-no-override-specify-group-should-default",
|
|
Provider: AlertProvider{
|
|
WebhookURL: "http://example.com",
|
|
Overrides: nil,
|
|
},
|
|
InputGroup: "group",
|
|
ExpectedOutput: "http://example.com",
|
|
},
|
|
{
|
|
Name: "provider-with-override-specify-no-group-should-default",
|
|
Provider: AlertProvider{
|
|
WebhookURL: "http://example.com",
|
|
Overrides: []Override{
|
|
{
|
|
Group: "group",
|
|
WebhookURL: "http://example01.com",
|
|
},
|
|
},
|
|
},
|
|
InputGroup: "",
|
|
ExpectedOutput: "http://example.com",
|
|
},
|
|
{
|
|
Name: "provider-with-override-specify-group-should-override",
|
|
Provider: AlertProvider{
|
|
WebhookURL: "http://example.com",
|
|
Overrides: []Override{
|
|
{
|
|
Group: "group",
|
|
WebhookURL: "http://example01.com",
|
|
},
|
|
},
|
|
},
|
|
InputGroup: "group",
|
|
ExpectedOutput: "http://example01.com",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.Name, func(t *testing.T) {
|
|
if got := tt.Provider.getWebhookURLForGroup(tt.InputGroup); got != tt.ExpectedOutput {
|
|
t.Errorf("AlertProvider.getWebhookURLForGroup() = %v, want %v", got, tt.ExpectedOutput)
|
|
}
|
|
})
|
|
}
|
|
}
|