320 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package opsgenie
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"reflect"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/TwiN/gatus/v5/alerting/alert"
 | |
| 	"github.com/TwiN/gatus/v5/client"
 | |
| 	"github.com/TwiN/gatus/v5/core"
 | |
| 	"github.com/TwiN/gatus/v5/test"
 | |
| )
 | |
| 
 | |
| func TestAlertProvider_IsValid(t *testing.T) {
 | |
| 	invalidProvider := AlertProvider{APIKey: ""}
 | |
| 	if invalidProvider.IsValid() {
 | |
| 		t.Error("provider shouldn't have been valid")
 | |
| 	}
 | |
| 	validProvider := AlertProvider{APIKey: "00000000-0000-0000-0000-000000000000"}
 | |
| 	if !validProvider.IsValid() {
 | |
| 		t.Error("provider should've been valid")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestAlertProvider_Send(t *testing.T) {
 | |
| 	defer client.InjectHTTPClient(nil)
 | |
| 	description := "my bad alert description"
 | |
| 	scenarios := []struct {
 | |
| 		Name             string
 | |
| 		Provider         AlertProvider
 | |
| 		Alert            alert.Alert
 | |
| 		Resolved         bool
 | |
| 		MockRoundTripper test.MockRoundTripper
 | |
| 		ExpectedError    bool
 | |
| 	}{
 | |
| 		{
 | |
| 			Name:          "triggered",
 | |
| 			Provider:      AlertProvider{},
 | |
| 			Alert:         alert.Alert{Description: &description, SuccessThreshold: 1, FailureThreshold: 1},
 | |
| 			Resolved:      false,
 | |
| 			ExpectedError: false,
 | |
| 			MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
 | |
| 				return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}
 | |
| 			}),
 | |
| 		},
 | |
| 		{
 | |
| 			Name:          "triggered-error",
 | |
| 			Provider:      AlertProvider{},
 | |
| 			Alert:         alert.Alert{Description: &description, SuccessThreshold: 5, FailureThreshold: 3},
 | |
| 			Resolved:      false,
 | |
| 			ExpectedError: true,
 | |
| 			MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
 | |
| 				return &http.Response{StatusCode: http.StatusInternalServerError, Body: http.NoBody}
 | |
| 			}),
 | |
| 		},
 | |
| 		{
 | |
| 			Name:          "resolved",
 | |
| 			Provider:      AlertProvider{},
 | |
| 			Alert:         alert.Alert{Description: &description, SuccessThreshold: 5, FailureThreshold: 3},
 | |
| 			Resolved:      true,
 | |
| 			ExpectedError: false,
 | |
| 			MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
 | |
| 				return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}
 | |
| 			}),
 | |
| 		},
 | |
| 		{
 | |
| 			Name:          "resolved-error",
 | |
| 			Provider:      AlertProvider{},
 | |
| 			Alert:         alert.Alert{Description: &description, SuccessThreshold: 5, FailureThreshold: 3},
 | |
| 			Resolved:      true,
 | |
| 			ExpectedError: true,
 | |
| 			MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
 | |
| 				return &http.Response{StatusCode: http.StatusInternalServerError, Body: http.NoBody}
 | |
| 			}),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	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_buildCreateRequestBody(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 	description := "alert description"
 | |
| 	scenarios := []struct {
 | |
| 		Name     string
 | |
| 		Provider *AlertProvider
 | |
| 		Alert    *alert.Alert
 | |
| 		Endpoint *core.Endpoint
 | |
| 		Result   *core.Result
 | |
| 		Resolved bool
 | |
| 		want     alertCreateRequest
 | |
| 	}{
 | |
| 		{
 | |
| 			Name:     "missing all params (unresolved)",
 | |
| 			Provider: &AlertProvider{},
 | |
| 			Alert:    &alert.Alert{},
 | |
| 			Endpoint: &core.Endpoint{},
 | |
| 			Result:   &core.Result{},
 | |
| 			Resolved: false,
 | |
| 			want: alertCreateRequest{
 | |
| 				Message:     " - ",
 | |
| 				Priority:    "P1",
 | |
| 				Source:      "gatus",
 | |
| 				Entity:      "gatus-",
 | |
| 				Alias:       "gatus-healthcheck-",
 | |
| 				Description: "An alert for ** has been triggered due to having failed 0 time(s) in a row\n",
 | |
| 				Tags:        nil,
 | |
| 				Details:     map[string]string{},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name:     "missing all params (resolved)",
 | |
| 			Provider: &AlertProvider{},
 | |
| 			Alert:    &alert.Alert{},
 | |
| 			Endpoint: &core.Endpoint{},
 | |
| 			Result:   &core.Result{},
 | |
| 			Resolved: true,
 | |
| 			want: alertCreateRequest{
 | |
| 				Message:     "RESOLVED:  - ",
 | |
| 				Priority:    "P1",
 | |
| 				Source:      "gatus",
 | |
| 				Entity:      "gatus-",
 | |
| 				Alias:       "gatus-healthcheck-",
 | |
| 				Description: "An alert for ** has been resolved after passing successfully 0 time(s) in a row\n",
 | |
| 				Tags:        nil,
 | |
| 				Details:     map[string]string{},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name:     "with default options (unresolved)",
 | |
| 			Provider: &AlertProvider{},
 | |
| 			Alert: &alert.Alert{
 | |
| 				Description:      &description,
 | |
| 				FailureThreshold: 3,
 | |
| 			},
 | |
| 			Endpoint: &core.Endpoint{
 | |
| 				Name: "my super app",
 | |
| 			},
 | |
| 			Result: &core.Result{
 | |
| 				ConditionResults: []*core.ConditionResult{
 | |
| 					{
 | |
| 						Condition: "[STATUS] == 200",
 | |
| 						Success:   true,
 | |
| 					},
 | |
| 					{
 | |
| 						Condition: "[BODY] == OK",
 | |
| 						Success:   false,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			Resolved: false,
 | |
| 			want: alertCreateRequest{
 | |
| 				Message:     "my super app - " + description,
 | |
| 				Priority:    "P1",
 | |
| 				Source:      "gatus",
 | |
| 				Entity:      "gatus-my-super-app",
 | |
| 				Alias:       "gatus-healthcheck-my-super-app",
 | |
| 				Description: "An alert for *my super app* has been triggered due to having failed 3 time(s) in a row\n▣ - `[STATUS] == 200`\n▢ - `[BODY] == OK`\n",
 | |
| 				Tags:        nil,
 | |
| 				Details:     map[string]string{},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name: "with custom options (resolved)",
 | |
| 			Provider: &AlertProvider{
 | |
| 				Priority:     "P5",
 | |
| 				EntityPrefix: "oompa-",
 | |
| 				AliasPrefix:  "loompa-",
 | |
| 				Source:       "gatus-hc",
 | |
| 				Tags:         []string{"do-ba-dee-doo"},
 | |
| 			},
 | |
| 			Alert: &alert.Alert{
 | |
| 				Description:      &description,
 | |
| 				SuccessThreshold: 4,
 | |
| 			},
 | |
| 			Endpoint: &core.Endpoint{
 | |
| 				Name: "my mega app",
 | |
| 			},
 | |
| 			Result: &core.Result{
 | |
| 				ConditionResults: []*core.ConditionResult{
 | |
| 					{
 | |
| 						Condition: "[STATUS] == 200",
 | |
| 						Success:   true,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			Resolved: true,
 | |
| 			want: alertCreateRequest{
 | |
| 				Message:     "RESOLVED: my mega app - " + description,
 | |
| 				Priority:    "P5",
 | |
| 				Source:      "gatus-hc",
 | |
| 				Entity:      "oompa-my-mega-app",
 | |
| 				Alias:       "loompa-my-mega-app",
 | |
| 				Description: "An alert for *my mega app* has been resolved after passing successfully 4 time(s) in a row\n▣ - `[STATUS] == 200`\n",
 | |
| 				Tags:        []string{"do-ba-dee-doo"},
 | |
| 				Details:     map[string]string{},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name: "with default options and details (unresolved)",
 | |
| 			Provider: &AlertProvider{
 | |
| 				Tags: []string{"foo"},
 | |
| 			},
 | |
| 			Alert: &alert.Alert{
 | |
| 				Description:      &description,
 | |
| 				FailureThreshold: 6,
 | |
| 			},
 | |
| 			Endpoint: &core.Endpoint{
 | |
| 				Name:  "my app",
 | |
| 				Group: "end game",
 | |
| 				URL:   "https://my.go/app",
 | |
| 			},
 | |
| 			Result: &core.Result{
 | |
| 				HTTPStatus: 400,
 | |
| 				Hostname:   "my.go",
 | |
| 				Errors:     []string{"error 01", "error 02"},
 | |
| 				Success:    false,
 | |
| 				ConditionResults: []*core.ConditionResult{
 | |
| 					{
 | |
| 						Condition: "[STATUS] == 200",
 | |
| 						Success:   false,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			Resolved: false,
 | |
| 			want: alertCreateRequest{
 | |
| 				Message:     "[end game] my app - " + description,
 | |
| 				Priority:    "P1",
 | |
| 				Source:      "gatus",
 | |
| 				Entity:      "gatus-end-game-my-app",
 | |
| 				Alias:       "gatus-healthcheck-end-game-my-app",
 | |
| 				Description: "An alert for *end game/my app* has been triggered due to having failed 6 time(s) in a row\n▢ - `[STATUS] == 200`\n",
 | |
| 				Tags:        []string{"foo"},
 | |
| 				Details: map[string]string{
 | |
| 					"endpoint:url":       "https://my.go/app",
 | |
| 					"endpoint:group":     "end game",
 | |
| 					"result:hostname":    "my.go",
 | |
| 					"result:errors":      "error 01,error 02",
 | |
| 					"result:http_status": "400",
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	for _, scenario := range scenarios {
 | |
| 		actual := scenario
 | |
| 		t.Run(actual.Name, func(t *testing.T) {
 | |
| 			if got := actual.Provider.buildCreateRequestBody(actual.Endpoint, actual.Alert, actual.Result, actual.Resolved); !reflect.DeepEqual(got, actual.want) {
 | |
| 				t.Errorf("buildCreateRequestBody() = %v, want %v", got, actual.want)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestAlertProvider_buildCloseRequestBody(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 	description := "alert description"
 | |
| 	scenarios := []struct {
 | |
| 		Name     string
 | |
| 		Provider *AlertProvider
 | |
| 		Alert    *alert.Alert
 | |
| 		Endpoint *core.Endpoint
 | |
| 		want     alertCloseRequest
 | |
| 	}{
 | |
| 		{
 | |
| 			Name:     "Missing all values",
 | |
| 			Provider: &AlertProvider{},
 | |
| 			Alert:    &alert.Alert{},
 | |
| 			Endpoint: &core.Endpoint{},
 | |
| 			want: alertCloseRequest{
 | |
| 				Source: "",
 | |
| 				Note:   "RESOLVED:  - ",
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name:     "Basic values",
 | |
| 			Provider: &AlertProvider{},
 | |
| 			Alert: &alert.Alert{
 | |
| 				Description: &description,
 | |
| 			},
 | |
| 			Endpoint: &core.Endpoint{
 | |
| 				Name: "endpoint name",
 | |
| 			},
 | |
| 			want: alertCloseRequest{
 | |
| 				Source: "endpoint-name",
 | |
| 				Note:   "RESOLVED: endpoint name - alert description",
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, scenario := range scenarios {
 | |
| 		actual := scenario
 | |
| 		t.Run(actual.Name, func(t *testing.T) {
 | |
| 			if got := actual.Provider.buildCloseRequestBody(actual.Endpoint, actual.Alert); !reflect.DeepEqual(got, actual.want) {
 | |
| 				t.Errorf("buildCloseRequestBody() = %v, want %v", got, actual.want)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |