gatus/core/service_test.go

332 lines
10 KiB
Go
Raw Normal View History

package core
import (
"io/ioutil"
"strings"
"testing"
2020-10-22 03:56:07 +02:00
"time"
)
2020-10-22 04:21:51 +02:00
func TestService_ValidateAndSetDefaults(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
Name: "twinnation-health",
2020-10-23 22:29:20 +02:00
URL: "https://twinnation.org/health",
2020-10-22 04:21:51 +02:00
Conditions: []*Condition{&condition},
Alerts: []*Alert{{Type: PagerDutyAlert}},
}
service.ValidateAndSetDefaults()
if service.Method != "GET" {
t.Error("Service method should've defaulted to GET")
}
if service.Interval != time.Minute {
t.Error("Service interval should've defaulted to 1 minute")
}
if service.Headers == nil {
t.Error("Service headers should've defaulted to an empty map")
}
if len(service.Alerts) != 1 {
t.Error("Service should've had 1 alert")
}
if service.Alerts[0].Enabled {
t.Error("Service alert should've defaulted to disabled")
}
if service.Alerts[0].SuccessThreshold != 2 {
t.Error("Service alert should've defaulted to a success threshold of 2")
}
if service.Alerts[0].FailureThreshold != 3 {
t.Error("Service alert should've defaulted to a failure threshold of 3")
}
}
2020-10-22 04:56:35 +02:00
func TestService_ValidateAndSetDefaultsWithNoName(t *testing.T) {
defer func() { recover() }()
condition := Condition("[STATUS] == 200")
service := &Service{
Name: "",
2020-10-23 22:29:20 +02:00
URL: "http://example.com",
2020-10-22 04:56:35 +02:00
Conditions: []*Condition{&condition},
}
service.ValidateAndSetDefaults()
t.Fatal("Should've panicked because service didn't have a name, which is a mandatory field")
}
func TestService_ValidateAndSetDefaultsWithNoUrl(t *testing.T) {
defer func() { recover() }()
condition := Condition("[STATUS] == 200")
service := &Service{
Name: "example",
2020-10-23 22:29:20 +02:00
URL: "",
2020-10-22 04:56:35 +02:00
Conditions: []*Condition{&condition},
}
service.ValidateAndSetDefaults()
t.Fatal("Should've panicked because service didn't have an url, which is a mandatory field")
}
func TestService_ValidateAndSetDefaultsWithNoConditions(t *testing.T) {
defer func() { recover() }()
service := &Service{
Name: "example",
2020-10-23 22:29:20 +02:00
URL: "http://example.com",
2020-10-22 04:56:35 +02:00
Conditions: nil,
}
service.ValidateAndSetDefaults()
t.Fatal("Should've panicked because service didn't have at least 1 condition")
}
2020-11-18 00:55:31 +01:00
func TestService_ValidateAndSetDefaultsWithDNS(t *testing.T) {
conditionSuccess := Condition("[DNS_RCODE] == NOERROR")
2020-11-18 00:55:31 +01:00
service := &Service{
Name: "dns-test",
2020-11-18 00:55:31 +01:00
URL: "http://example.com",
DNS: &DNS{
QueryType: "A",
QueryName: "example.com",
},
Conditions: []*Condition{&conditionSuccess},
2020-11-18 00:55:31 +01:00
}
service.ValidateAndSetDefaults()
if service.DNS.QueryName != "example.com." {
2020-11-18 00:55:31 +01:00
t.Error("Service.dns.query-name should be formatted with . suffix")
}
}
2020-10-22 04:21:51 +02:00
func TestService_GetAlertsTriggered(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
Name: "twinnation-health",
2020-10-23 22:29:20 +02:00
URL: "https://twinnation.org/health",
2020-10-22 04:21:51 +02:00
Conditions: []*Condition{&condition},
Alerts: []*Alert{{Type: PagerDutyAlert, Enabled: true}},
}
service.ValidateAndSetDefaults()
if service.NumberOfFailuresInARow != 0 {
t.Error("Service.NumberOfFailuresInARow should start with 0")
}
if service.NumberOfSuccessesInARow != 0 {
t.Error("Service.NumberOfSuccessesInARow should start with 0")
}
if len(service.GetAlertsTriggered()) > 0 {
t.Error("No alerts should've been triggered, because service.NumberOfFailuresInARow is 0, which is below the failure threshold")
}
service.NumberOfFailuresInARow = service.Alerts[0].FailureThreshold
if len(service.GetAlertsTriggered()) != 1 {
t.Error("Alert should've been triggered")
}
}
2020-12-19 00:06:57 +01:00
func TestService_buildHTTPRequest(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
Name: "twinnation-health",
2020-12-19 00:06:57 +01:00
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
}
service.ValidateAndSetDefaults()
request := service.buildHTTPRequest()
if request.Method != "GET" {
t.Error("request.Method should've been GET, but was", request.Method)
}
2020-12-19 00:06:57 +01:00
if request.Host != "twinnation.org" {
t.Error("request.Host should've been twinnation.org, but was", request.Host)
2020-12-19 00:06:57 +01:00
}
if userAgent := request.Header.Get("User-Agent"); userAgent != GatusUserAgent {
t.Errorf("request.Header.Get(User-Agent) should've been %s, but was %s", GatusUserAgent, userAgent)
}
}
func TestService_buildHTTPRequestWithCustomUserAgent(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
Headers: map[string]string{
"User-Agent": "Test/2.0",
},
}
service.ValidateAndSetDefaults()
request := service.buildHTTPRequest()
if request.Method != "GET" {
t.Error("request.Method should've been GET, but was", request.Method)
}
if request.Host != "twinnation.org" {
t.Error("request.Host should've been twinnation.org, but was", request.Host)
}
if userAgent := request.Header.Get("User-Agent"); userAgent != "Test/2.0" {
t.Errorf("request.Header.Get(User-Agent) should've been %s, but was %s", "Test/2.0", userAgent)
}
2020-12-19 00:06:57 +01:00
}
func TestService_buildHTTPRequestWithHostHeader(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
Name: "twinnation-health",
2020-12-19 00:06:57 +01:00
URL: "https://twinnation.org/health",
Method: "POST",
2020-12-19 00:06:57 +01:00
Conditions: []*Condition{&condition},
Headers: map[string]string{
"Host": "example.com",
},
}
service.ValidateAndSetDefaults()
request := service.buildHTTPRequest()
if request.Method != "POST" {
t.Error("request.Method should've been POST, but was", request.Method)
}
2020-12-19 00:06:57 +01:00
if request.Host != "example.com" {
t.Error("request.Host should've been example.com, but was", request.Host)
}
}
func TestService_buildHTTPRequestWithGraphQLEnabled(t *testing.T) {
condition := Condition("[STATUS] == 200")
service := Service{
Name: "twinnation-graphql",
URL: "https://twinnation.org/graphql",
Method: "POST",
Conditions: []*Condition{&condition},
GraphQL: true,
Body: `{
2021-03-06 02:33:06 +01:00
users(gender: "female") {
id
name
gender
avatar
}
}`,
}
service.ValidateAndSetDefaults()
request := service.buildHTTPRequest()
if request.Method != "POST" {
t.Error("request.Method should've been POST, but was", request.Method)
}
if contentType := request.Header.Get(ContentTypeHeader); contentType != "application/json" {
t.Error("request.Header.Content-Type should've been application/json, but was", contentType)
}
body, _ := ioutil.ReadAll(request.Body)
if !strings.HasPrefix(string(body), "{\"query\":") {
t.Error("request.body should've started with '{\"query\":', but it didn't:", string(body))
2020-12-19 00:06:57 +01:00
}
}
func TestIntegrationEvaluateHealth(t *testing.T) {
condition := Condition("[STATUS] == 200")
bodyCondition := Condition("[BODY].status == UP")
service := Service{
Name: "twinnation-health",
2020-10-23 22:29:20 +02:00
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition, &bodyCondition},
}
result := service.EvaluateHealth()
if !result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a success", condition)
}
if !result.Connected {
t.Error("Because the connection has been established, result.Connected should've been true")
}
if !result.Success {
t.Error("Because all conditions passed, this should have been a success")
}
}
func TestIntegrationEvaluateHealthWithFailure(t *testing.T) {
condition := Condition("[STATUS] == 500")
service := Service{
Name: "twinnation-health",
URL: "https://twinnation.org/health",
Conditions: []*Condition{&condition},
}
result := service.EvaluateHealth()
if result.ConditionResults[0].Success {
t.Errorf("Condition '%s' should have been a failure", condition)
}
if !result.Connected {
t.Error("Because the connection has been established, result.Connected should've been true")
}
if result.Success {
t.Error("Because one of the conditions failed, success should have been false")
}
}
2020-11-18 00:55:31 +01:00
func TestIntegrationEvaluateHealthForDNS(t *testing.T) {
conditionSuccess := Condition("[DNS_RCODE] == NOERROR")
conditionBody := Condition("[BODY] == 93.184.216.34")
service := Service{
Name: "example",
2020-11-18 00:55:31 +01:00
URL: "8.8.8.8",
DNS: &DNS{
QueryType: "A",
QueryName: "example.com.",
},
Conditions: []*Condition{&conditionSuccess, &conditionBody},
}
result := service.EvaluateHealth()
if !result.ConditionResults[0].Success {
t.Errorf("Conditions '%s' and %s should have been a success", conditionSuccess, conditionBody)
}
if !result.Connected {
t.Error("Because the connection has been established, result.Connected should've been true")
}
if !result.Success {
t.Error("Because all conditions passed, this should have been a success")
}
}
func TestIntegrationEvaluateHealthForICMP(t *testing.T) {
conditionSuccess := Condition("[CONNECTED] == true")
service := Service{
Name: "icmp-test",
2020-12-25 09:05:47 +01:00
URL: "icmp://127.0.0.1",
Conditions: []*Condition{&conditionSuccess},
}
result := service.EvaluateHealth()
if !result.ConditionResults[0].Success {
t.Errorf("Conditions '%s' should have been a success", conditionSuccess)
}
if !result.Connected {
t.Error("Because the connection has been established, result.Connected should've been true")
}
if !result.Success {
t.Error("Because all conditions passed, this should have been a success")
}
}
2020-12-29 23:27:58 +01:00
func TestService_getIP(t *testing.T) {
conditionSuccess := Condition("[CONNECTED] == true")
service := Service{
Name: "invalid-url-test",
2020-12-29 23:27:58 +01:00
URL: "",
Conditions: []*Condition{&conditionSuccess},
}
result := &Result{}
service.getIP(result)
if len(result.Errors) == 0 {
t.Error("service.getIP(result) should've thrown an error because the URL is invalid, thus cannot be parsed")
}
}
func TestService_NeedsToReadBody(t *testing.T) {
statusCondition := Condition("[STATUS] == 200")
bodyCondition := Condition("[BODY].status == UP")
bodyConditionWithLength := Condition("len([BODY].tags) > 0")
if (&Service{Conditions: []*Condition{&statusCondition}}).needsToReadBody() {
t.Error("expected false, got true")
}
if !(&Service{Conditions: []*Condition{&bodyCondition}}).needsToReadBody() {
t.Error("expected true, got false")
}
if !(&Service{Conditions: []*Condition{&bodyConditionWithLength}}).needsToReadBody() {
t.Error("expected true, got false")
}
if !(&Service{Conditions: []*Condition{&statusCondition, &bodyCondition}}).needsToReadBody() {
t.Error("expected true, got false")
}
if !(&Service{Conditions: []*Condition{&bodyCondition, &statusCondition}}).needsToReadBody() {
t.Error("expected true, got false")
}
if !(&Service{Conditions: []*Condition{&bodyConditionWithLength, &statusCondition}}).needsToReadBody() {
t.Error("expected true, got false")
}
}