2020-04-15 01:20:00 +02:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
2020-12-19 00:40:11 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"strings"
|
2020-04-15 01:20:00 +02:00
|
|
|
"testing"
|
2020-10-22 03:56:07 +02:00
|
|
|
"time"
|
2020-04-15 01:20:00 +02:00
|
|
|
)
|
|
|
|
|
2020-10-22 04:21:51 +02:00
|
|
|
func TestService_ValidateAndSetDefaults(t *testing.T) {
|
|
|
|
condition := Condition("[STATUS] == 200")
|
|
|
|
service := Service{
|
2021-03-09 03:30:11 +01:00
|
|
|
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) {
|
2020-11-18 01:00:16 +01:00
|
|
|
conditionSuccess := Condition("[DNS_RCODE] == NOERROR")
|
2020-11-18 00:55:31 +01:00
|
|
|
service := &Service{
|
2020-11-18 01:00:16 +01:00
|
|
|
Name: "dns-test",
|
2020-11-18 00:55:31 +01:00
|
|
|
URL: "http://example.com",
|
|
|
|
DNS: &DNS{
|
|
|
|
QueryType: "A",
|
|
|
|
QueryName: "example.com",
|
|
|
|
},
|
2020-11-18 01:00:16 +01:00
|
|
|
Conditions: []*Condition{&conditionSuccess},
|
2020-11-18 00:55:31 +01:00
|
|
|
}
|
|
|
|
service.ValidateAndSetDefaults()
|
2020-11-18 01:00:16 +01:00
|
|
|
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{
|
2021-03-09 03:30:11 +01:00
|
|
|
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{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "twinnation-health",
|
2020-12-19 00:06:57 +01:00
|
|
|
URL: "https://twinnation.org/health",
|
|
|
|
Conditions: []*Condition{&condition},
|
|
|
|
}
|
|
|
|
service.ValidateAndSetDefaults()
|
|
|
|
request := service.buildHTTPRequest()
|
2020-12-19 00:40:11 +01:00
|
|
|
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" {
|
2020-12-19 00:40:11 +01:00
|
|
|
t.Error("request.Host should've been twinnation.org, but was", request.Host)
|
2020-12-19 00:06:57 +01:00
|
|
|
}
|
2020-12-31 01:56:12 +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{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "twinnation-health",
|
2020-12-31 01:56:12 +01:00
|
|
|
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{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "twinnation-health",
|
2020-12-19 00:06:57 +01:00
|
|
|
URL: "https://twinnation.org/health",
|
2020-12-19 00:40:11 +01:00
|
|
|
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()
|
2020-12-19 00:40:11 +01:00
|
|
|
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" {
|
2020-12-19 00:40:11 +01:00
|
|
|
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{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "twinnation-graphql",
|
2020-12-19 00:40:11 +01:00
|
|
|
URL: "https://twinnation.org/graphql",
|
|
|
|
Method: "POST",
|
|
|
|
Conditions: []*Condition{&condition},
|
|
|
|
GraphQL: true,
|
|
|
|
Body: `{
|
2021-03-06 02:33:06 +01:00
|
|
|
users(gender: "female") {
|
2020-12-19 00:40:11 +01:00
|
|
|
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\":") {
|
2021-03-09 03:30:11 +01:00
|
|
|
t.Error("request.body should've started with '{\"query\":', but it didn't:", string(body))
|
2020-12-19 00:06:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-25 01:49:32 +02:00
|
|
|
func TestIntegrationEvaluateHealth(t *testing.T) {
|
2020-04-15 01:20:00 +02:00
|
|
|
condition := Condition("[STATUS] == 200")
|
2021-03-09 03:30:11 +01:00
|
|
|
bodyCondition := Condition("[BODY].status == UP")
|
2020-04-15 01:20:00 +02:00
|
|
|
service := Service{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "twinnation-health",
|
2020-10-23 22:29:20 +02:00
|
|
|
URL: "https://twinnation.org/health",
|
2021-03-09 03:30:11 +01:00
|
|
|
Conditions: []*Condition{&condition, &bodyCondition},
|
2020-04-15 01:20:00 +02:00
|
|
|
}
|
2020-09-25 01:49:32 +02:00
|
|
|
result := service.EvaluateHealth()
|
2020-04-15 01:20:00 +02:00
|
|
|
if !result.ConditionResults[0].Success {
|
|
|
|
t.Errorf("Condition '%s' should have been a success", condition)
|
|
|
|
}
|
2020-10-05 01:55:19 +02:00
|
|
|
if !result.Connected {
|
|
|
|
t.Error("Because the connection has been established, result.Connected should've been true")
|
|
|
|
}
|
2020-04-15 01:20:00 +02:00
|
|
|
if !result.Success {
|
|
|
|
t.Error("Because all conditions passed, this should have been a success")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-25 06:07:18 +01:00
|
|
|
func TestIntegrationEvaluateHealthWithFailure(t *testing.T) {
|
|
|
|
condition := Condition("[STATUS] == 500")
|
|
|
|
service := Service{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "twinnation-health",
|
2020-12-25 06:07:18 +01:00
|
|
|
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{
|
2021-03-09 03:30:11 +01:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-25 06:07:18 +01:00
|
|
|
func TestIntegrationEvaluateHealthForICMP(t *testing.T) {
|
|
|
|
conditionSuccess := Condition("[CONNECTED] == true")
|
2020-04-15 01:20:00 +02:00
|
|
|
service := Service{
|
2021-03-09 03:30:11 +01:00
|
|
|
Name: "icmp-test",
|
2020-12-25 09:05:47 +01:00
|
|
|
URL: "icmp://127.0.0.1",
|
2020-12-25 06:07:18 +01:00
|
|
|
Conditions: []*Condition{&conditionSuccess},
|
2020-04-15 01:20:00 +02:00
|
|
|
}
|
2020-09-25 01:49:32 +02:00
|
|
|
result := service.EvaluateHealth()
|
2020-12-25 06:07:18 +01:00
|
|
|
if !result.ConditionResults[0].Success {
|
|
|
|
t.Errorf("Conditions '%s' should have been a success", conditionSuccess)
|
2020-04-15 01:20:00 +02:00
|
|
|
}
|
2020-10-05 01:55:19 +02:00
|
|
|
if !result.Connected {
|
|
|
|
t.Error("Because the connection has been established, result.Connected should've been true")
|
|
|
|
}
|
2020-12-25 06:07:18 +01:00
|
|
|
if !result.Success {
|
|
|
|
t.Error("Because all conditions passed, this should have been a success")
|
2020-04-15 01:20:00 +02:00
|
|
|
}
|
|
|
|
}
|
2020-12-29 23:27:58 +01:00
|
|
|
|
|
|
|
func TestService_getIP(t *testing.T) {
|
|
|
|
conditionSuccess := Condition("[CONNECTED] == true")
|
|
|
|
service := Service{
|
2021-03-09 03:30:11 +01:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
2021-03-09 03:30:11 +01:00
|
|
|
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|