From 121369d9c082a2756d845774ab557c623bf404a7 Mon Sep 17 00:00:00 2001 From: Elouan Martinet Date: Sun, 15 Nov 2020 18:26:35 +0100 Subject: [PATCH 1/6] Add basic duration comparison --- core/condition.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/condition.go b/core/condition.go index 964416fd..cf13e87b 100644 --- a/core/condition.go +++ b/core/condition.go @@ -7,6 +7,7 @@ import ( "log" "strconv" "strings" + "time" ) const ( @@ -185,7 +186,9 @@ func sanitizeAndResolveNumerical(list []string, result *Result) []int64 { var sanitizedNumbers []int64 sanitizedList := sanitizeAndResolve(list, result) for _, element := range sanitizedList { - if number, err := strconv.ParseInt(element, 10, 64); err != nil { + if duration, err := time.ParseDuration(element); err == nil { + sanitizedNumbers = append(sanitizedNumbers, duration.Milliseconds()) + } else if number, err := strconv.ParseInt(element, 10, 64); err != nil { // Default to 0 if the string couldn't be converted to an integer sanitizedNumbers = append(sanitizedNumbers, 0) } else { From 573b5f89e15a457fb91c1d6cf6903c155c8f4540 Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Mon, 16 Nov 2020 10:10:02 -0500 Subject: [PATCH 2/6] Improve test coverage --- core/condition.go | 7 ++++--- core/condition_test.go | 22 ++++++++++++++++++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/core/condition.go b/core/condition.go index cf13e87b..36cc9bf3 100644 --- a/core/condition.go +++ b/core/condition.go @@ -2,12 +2,13 @@ package core import ( "fmt" - "github.com/TwinProduction/gatus/jsonpath" - "github.com/TwinProduction/gatus/pattern" "log" "strconv" "strings" "time" + + "github.com/TwinProduction/gatus/jsonpath" + "github.com/TwinProduction/gatus/pattern" ) const ( @@ -186,7 +187,7 @@ func sanitizeAndResolveNumerical(list []string, result *Result) []int64 { var sanitizedNumbers []int64 sanitizedList := sanitizeAndResolve(list, result) for _, element := range sanitizedList { - if duration, err := time.ParseDuration(element); err == nil { + if duration, err := time.ParseDuration(element); duration != 0 && err == nil { sanitizedNumbers = append(sanitizedNumbers, duration.Milliseconds()) } else if number, err := strconv.ParseInt(element, 10, 64); err != nil { // Default to 0 if the string couldn't be converted to an integer diff --git a/core/condition_test.go b/core/condition_test.go index d4e929df..90890e58 100644 --- a/core/condition_test.go +++ b/core/condition_test.go @@ -320,7 +320,7 @@ func TestCondition_evaluateWithUnsetCertificateExpiration(t *testing.T) { } } -func TestCondition_evaluateWithCertificateExpirationGreaterThan(t *testing.T) { +func TestCondition_evaluateWithCertificateExpirationGreaterThanNumerical(t *testing.T) { acceptable := (time.Hour * 24 * 28).Milliseconds() condition := Condition("[CERTIFICATE_EXPIRATION] > " + strconv.FormatInt(acceptable, 10)) result := &Result{CertificateExpiration: time.Hour * 24 * 60} @@ -330,7 +330,7 @@ func TestCondition_evaluateWithCertificateExpirationGreaterThan(t *testing.T) { } } -func TestCondition_evaluateWithCertificateExpirationGreaterThanFailure(t *testing.T) { +func TestCondition_evaluateWithCertificateExpirationGreaterThanNumericalFailure(t *testing.T) { acceptable := (time.Hour * 24 * 28).Milliseconds() condition := Condition("[CERTIFICATE_EXPIRATION] > " + strconv.FormatInt(acceptable, 10)) result := &Result{CertificateExpiration: time.Hour * 24 * 14} @@ -339,3 +339,21 @@ func TestCondition_evaluateWithCertificateExpirationGreaterThanFailure(t *testin t.Errorf("Condition '%s' should have been a failure", condition) } } + +func TestCondition_evaluateWithCertificateExpirationGreaterThanDuration(t *testing.T) { + condition := Condition("[CERTIFICATE_EXPIRATION] > 12h") + result := &Result{CertificateExpiration: 24 * time.Hour} + condition.evaluate(result) + if !result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a success", condition) + } +} + +func TestCondition_evaluateWithCertificateExpirationGreaterThanDurationFailure(t *testing.T) { + condition := Condition("[CERTIFICATE_EXPIRATION] > 48h") + result := &Result{CertificateExpiration: 24 * time.Hour} + condition.evaluate(result) + if result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a failure", condition) + } +} From 5699a1c236f87b39d1fdad7a6b00cda0a2592418 Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Mon, 16 Nov 2020 10:27:46 -0500 Subject: [PATCH 3/6] Improve test coverage for duration parsing --- core/condition_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/condition_test.go b/core/condition_test.go index 90890e58..3aa3fc6d 100644 --- a/core/condition_test.go +++ b/core/condition_test.go @@ -60,7 +60,27 @@ func TestCondition_evaluateWithResponseTimeUsingLessThan(t *testing.T) { } } +func TestCondition_evaluateWithResponseTimeUsingLessThanDuration(t *testing.T) { + condition := Condition("[RESPONSE_TIME] < 1s") + result := &Result{Duration: time.Millisecond * 50} + condition.evaluate(result) + if !result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a success", condition) + } +} + +func TestCondition_evaluateWithResponseTimeUsingLessThanInvalid(t *testing.T) { + condition := Condition("[RESPONSE_TIME] < potato") + result := &Result{Duration: time.Millisecond * 50} + condition.evaluate(result) + if result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have failed because the condition has an invalid numerical value that should've automatically resolved to 0", condition) + } +} + func TestCondition_evaluateWithResponseTimeUsingGreaterThan(t *testing.T) { + // Not exactly sure why you'd want to have a condition that checks if the response time is too fast, + // but hey, who am I to judge? condition := Condition("[RESPONSE_TIME] > 500") result := &Result{Duration: time.Millisecond * 750} condition.evaluate(result) @@ -69,6 +89,15 @@ func TestCondition_evaluateWithResponseTimeUsingGreaterThan(t *testing.T) { } } +func TestCondition_evaluateWithResponseTimeUsingGreaterThanDuration(t *testing.T) { + condition := Condition("[RESPONSE_TIME] > 1s") + result := &Result{Duration: time.Second * 2} + condition.evaluate(result) + if !result.ConditionResults[0].Success { + t.Errorf("Condition '%s' should have been a success", condition) + } +} + func TestCondition_evaluateWithResponseTimeUsingGreaterThanOrEqualTo(t *testing.T) { condition := Condition("[RESPONSE_TIME] >= 500") result := &Result{Duration: time.Millisecond * 500} From c23e21cb413ed9719bd69b69c24cc1964886af8b Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Mon, 16 Nov 2020 12:03:53 -0500 Subject: [PATCH 4/6] Update documentation for CERTIFICATE_EXPIRATION placeholder --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 063a852d..891e8ba2 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ Here are some examples of conditions you can use: | `len([BODY].data) < 5` | Array at JSONPath `$.data` has less than 5 elements | `{"data":[{"id":1}]}` | | | `len([BODY].name) == 8` | String at JSONPath `$.name` has a length of 8 | `{"name":"john.doe"}` | `{"name":"bob"}` | | `[BODY].name == pat(john*)` | String at JSONPath `$.name` matches pattern `john*` | `{"name":"john.doe"}` | `{"name":"bob"}` | +| `[CERTIFICATE_EXPIRATION] > 48h` | Certificate expiration is more than 48h away | `{"name":"john.doe"}` | `{"name":"bob"}` | #### Placeholders @@ -168,7 +169,7 @@ Here are some examples of conditions you can use: | `[IP]` | Resolves into the IP of the target host | 192.168.0.232 | `[BODY]` | Resolves into the response body. Supports JSONPath. | `{"name":"john.doe"}` | `[CONNECTED]` | Resolves into whether a connection could be established | `true` -| `[CERTIFICATE_EXPIRATION]` | Resolves into the duration before certificate expiration, in ms | 4461677039, 0 (if not using HTTPS) +| `[CERTIFICATE_EXPIRATION]` | Resolves into the duration before certificate expiration | `24h`, `48h`, 0 (if not using HTTPS) #### Functions From 2150942876eac1a626331ad2382aa1f4e1e4982a Mon Sep 17 00:00:00 2001 From: Elouan Martinet Date: Mon, 16 Nov 2020 18:16:11 +0100 Subject: [PATCH 5/6] Add day format support for duration comparison --- core/condition.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/condition.go b/core/condition.go index 36cc9bf3..1d48d7b9 100644 --- a/core/condition.go +++ b/core/condition.go @@ -3,6 +3,7 @@ package core import ( "fmt" "log" + "regexp" "strconv" "strings" "time" @@ -186,7 +187,15 @@ func sanitizeAndResolve(list []string, result *Result) []string { func sanitizeAndResolveNumerical(list []string, result *Result) []int64 { var sanitizedNumbers []int64 sanitizedList := sanitizeAndResolve(list, result) + dayRegex := regexp.MustCompile(`^\s*(\d+)d\s*$`) for _, element := range sanitizedList { + if matches := dayRegex.FindStringSubmatch(element); matches != nil { + if days, err := strconv.ParseInt(matches[1], 10, 64); err == nil { + duration := time.Duration(days * int64(time.Hour * 24)) + sanitizedNumbers = append(sanitizedNumbers, duration.Milliseconds()) + continue + } + } if duration, err := time.ParseDuration(element); duration != 0 && err == nil { sanitizedNumbers = append(sanitizedNumbers, duration.Milliseconds()) } else if number, err := strconv.ParseInt(element, 10, 64); err != nil { From e79c849e6d5433a070f51d24c91bb45abbd857f7 Mon Sep 17 00:00:00 2001 From: TwinProduction Date: Tue, 17 Nov 2020 12:16:40 -0500 Subject: [PATCH 6/6] Revert "Add day format support for duration comparison" This reverts commit 21509428 --- core/condition.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core/condition.go b/core/condition.go index 1d48d7b9..36cc9bf3 100644 --- a/core/condition.go +++ b/core/condition.go @@ -3,7 +3,6 @@ package core import ( "fmt" "log" - "regexp" "strconv" "strings" "time" @@ -187,15 +186,7 @@ func sanitizeAndResolve(list []string, result *Result) []string { func sanitizeAndResolveNumerical(list []string, result *Result) []int64 { var sanitizedNumbers []int64 sanitizedList := sanitizeAndResolve(list, result) - dayRegex := regexp.MustCompile(`^\s*(\d+)d\s*$`) for _, element := range sanitizedList { - if matches := dayRegex.FindStringSubmatch(element); matches != nil { - if days, err := strconv.ParseInt(matches[1], 10, 64); err == nil { - duration := time.Duration(days * int64(time.Hour * 24)) - sanitizedNumbers = append(sanitizedNumbers, duration.Milliseconds()) - continue - } - } if duration, err := time.ParseDuration(element); duration != 0 && err == nil { sanitizedNumbers = append(sanitizedNumbers, duration.Milliseconds()) } else if number, err := strconv.ParseInt(element, 10, 64); err != nil {