From 6ab8899dc6afa8eb297b13b491790363a2eeff7a Mon Sep 17 00:00:00 2001 From: TwiN Date: Wed, 15 Feb 2023 19:30:29 -0500 Subject: [PATCH] fix(condition): Partially support numbers with floating point (#434) * docs: Don't include Pushover in alerting provider examples * fix(condition): Partially support numbers with floating point Fixes #433 Does not add support for decimal numbers, but it converts float64 to int64. The reason why I'm not just using float64 instead of int64 is because float64 does not support all the numbers that int64 supports, which means this would be a breaking change. Instead, this change at least supports the non-decimal part of floating point numbers. This is an improvement over the current implementation, as right now, numbers with decimals are just converted to 0 when compared using a non-equal operator --- README.md | 2 +- core/condition.go | 12 ++++++++++-- core/condition_test.go | 7 +++++++ jsonpath/jsonpath_test.go | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6e8774e3..c9828909 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Gatus is a developer-oriented health dashboard that gives you the ability to monitor your services using HTTP, ICMP, TCP, and even DNS queries as well as evaluate the result of said queries by using a list of conditions on values like the status code, the response time, the certificate expiration, the body and many others. The icing on top is that each of these health -checks can be paired with alerting via Slack, PagerDuty, Pushover, Discord, Twilio and more. +checks can be paired with alerting via Slack, Teams, PagerDuty, Discord, Twilio and many more. I personally deploy it in my Kubernetes cluster and let it monitor the status of my core applications: https://status.twin.sh/ diff --git a/core/condition.go b/core/condition.go index 35e857f7..bca75760 100644 --- a/core/condition.go +++ b/core/condition.go @@ -302,10 +302,18 @@ func sanitizeAndResolveNumerical(list []string, result *Result) (parameters []st parameters, resolvedParameters := sanitizeAndResolve(list, result) for _, element := range resolvedParameters { if duration, err := time.ParseDuration(element); duration != 0 && err == nil { + // If the string is a duration, convert it to milliseconds resolvedNumericalParameters = append(resolvedNumericalParameters, 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 - resolvedNumericalParameters = append(resolvedNumericalParameters, 0) + // It's not an int, so we'll check if it's a float + if f, err := strconv.ParseFloat(element, 64); err == nil { + // It's a float, but we'll convert it to an int. We're losing precision here, but it's better than + // just returning 0. + resolvedNumericalParameters = append(resolvedNumericalParameters, int64(f)) + } else { + // Default to 0 if the string couldn't be converted to an integer or a float + resolvedNumericalParameters = append(resolvedNumericalParameters, 0) + } } else { resolvedNumericalParameters = append(resolvedNumericalParameters, number) } diff --git a/core/condition_test.go b/core/condition_test.go index 678eed9e..25976d6a 100644 --- a/core/condition_test.go +++ b/core/condition_test.go @@ -294,6 +294,13 @@ func TestCondition_evaluate(t *testing.T) { ExpectedSuccess: false, ExpectedOutput: "[BODY].data.id (1) > 5", }, + { + Name: "body-jsonpath-float-using-greater-than-issue433", // As of v5.3.1, Gatus will convert a float to an int. We're losing precision, but it's better than just returning 0 + Condition: Condition("[BODY].balance > 100"), + Result: &Result{body: []byte(`{"balance": "123.40000000000005"}`)}, + ExpectedSuccess: true, + ExpectedOutput: "[BODY].balance > 100", + }, { Name: "body-jsonpath-complex-int-using-less-than", Condition: Condition("[BODY].data.id < 5"), diff --git a/jsonpath/jsonpath_test.go b/jsonpath/jsonpath_test.go index 41d657c2..83244c5c 100644 --- a/jsonpath/jsonpath_test.go +++ b/jsonpath/jsonpath_test.go @@ -158,6 +158,22 @@ func TestEval(t *testing.T) { ExpectedOutputLength: 0, ExpectedError: true, }, + { + Name: "float-as-string", + Path: "balance", + Data: `{"balance": "123.40000000000005"}`, + ExpectedOutput: "123.40000000000005", + ExpectedOutputLength: 18, + ExpectedError: false, + }, + { + Name: "float-as-number", + Path: "balance", + Data: `{"balance": 123.40000000000005}`, + ExpectedOutput: "123.40000000000005", + ExpectedOutputLength: 18, + ExpectedError: false, + }, } for _, scenario := range scenarios { t.Run(scenario.Name, func(t *testing.T) {