diff --git a/README.md b/README.md
index 7d9afaa4..aeeb4e83 100644
--- a/README.md
+++ b/README.md
@@ -159,6 +159,8 @@ Here are some examples of conditions you can use:
| `[BODY].age == [BODY].id` | JSONPath value of `$.age` is equal JSONPath `$.id` | `{"age":1,"id":1}` | |
| `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"}` |
+| `has([BODY].errors) == false` | JSONPath `$.errors` does not exist | `{"name":"john.doe"}` | `{"errors":[]}` |
+| `has([BODY].users) == true` | JSONPath `$.users` exists | `{"users":[]}` | `{}` |
| `[BODY].name == pat(john*)` | String at JSONPath `$.name` matches pattern `john*` | `{"name":"john.doe"}` | `{"name":"bob"}` |
| `[BODY].id == any(1, 2)` | Value at JSONPath `$.id` is equal to `1` or `2` | 1, 2 | 3, 4, 5 |
| `[CERTIFICATE_EXPIRATION] > 48h` | Certificate expiration is more than 48h away | 49h, 50h, 123h | 1h, 24h, ... |
@@ -182,6 +184,7 @@ Here are some examples of conditions you can use:
| Function | Description | Example |
|:-----------|:---------------------------------------------------------------------------------------------------------------- |:-------------------------- |
| `len` | Returns the length of the object/slice. Works only with the `[BODY]` placeholder. | `len([BODY].username) > 8`
+| `has` | Returns `true` or `false` based on whether a given path is valid. Works only with the `[BODY]` placeholder. | `has([BODY].errors) == false`
| `pat` | Specifies that the string passed as parameter should be evaluated as a pattern. Works only with `==` and `!=`. | `[IP] == pat(192.168.*)`
| `any` | Specifies that any one of the values passed as parameters is a valid value. Works only with `==` and `!=`. | `[BODY].ip == any(127.0.0.1, ::1)`
diff --git a/core/condition.go b/core/condition.go
index 7c957d32..93736087 100644
--- a/core/condition.go
+++ b/core/condition.go
@@ -51,14 +51,19 @@ const (
// Usage: len([BODY].articles) == 10, len([BODY].name) > 5
LengthFunctionPrefix = "len("
+ // HasFunctionPrefix is the prefix for the has function
+ //
+ // Usage: has([BODY].errors) == true
+ HasFunctionPrefix = "has("
+
// PatternFunctionPrefix is the prefix for the pattern function
//
- // Usage: pat(192.168.*.*)
+ // Usage: [IP] == pat(192.168.*.*)
PatternFunctionPrefix = "pat("
// AnyFunctionPrefix is the prefix for the any function
//
- // Usage: any(1.1.1.1, 1.0.0.1)
+ // Usage: [IP] == any(1.1.1.1, 1.0.0.1)
AnyFunctionPrefix = "any("
// FunctionSuffix is the suffix for all functions
@@ -209,26 +214,39 @@ func sanitizeAndResolve(elements []string, result *Result) ([]string, []string)
default:
// if contains the BodyPlaceholder, then evaluate json path
if strings.Contains(element, BodyPlaceholder) {
- wantLength := false
+ checkingForLength := false
+ checkingForExistence := false
if strings.HasPrefix(element, LengthFunctionPrefix) && strings.HasSuffix(element, FunctionSuffix) {
- wantLength = true
+ checkingForLength = true
element = strings.TrimSuffix(strings.TrimPrefix(element, LengthFunctionPrefix), FunctionSuffix)
}
+ if strings.HasPrefix(element, HasFunctionPrefix) && strings.HasSuffix(element, FunctionSuffix) {
+ checkingForExistence = true
+ element = strings.TrimSuffix(strings.TrimPrefix(element, HasFunctionPrefix), FunctionSuffix)
+ }
resolvedElement, resolvedElementLength, err := jsonpath.Eval(strings.TrimPrefix(element, BodyPlaceholder+"."), result.body)
- if err != nil {
- if err.Error() != "unexpected end of JSON input" {
- result.Errors = append(result.Errors, err.Error())
- }
- if wantLength {
- element = LengthFunctionPrefix + element + FunctionSuffix + " " + InvalidConditionElementSuffix
+ if checkingForExistence {
+ if err != nil {
+ element = "false"
} else {
- element = element + " " + InvalidConditionElementSuffix
+ element = "true"
}
} else {
- if wantLength {
- element = strconv.Itoa(resolvedElementLength)
+ if err != nil {
+ if err.Error() != "unexpected end of JSON input" {
+ result.Errors = append(result.Errors, err.Error())
+ }
+ if checkingForLength {
+ element = LengthFunctionPrefix + element + FunctionSuffix + " " + InvalidConditionElementSuffix
+ } else {
+ element = element + " " + InvalidConditionElementSuffix
+ }
} else {
- element = resolvedElement
+ if checkingForLength {
+ element = strconv.Itoa(resolvedElementLength)
+ } else {
+ element = resolvedElement
+ }
}
}
}
diff --git a/core/condition_test.go b/core/condition_test.go
index 2b4d5d99..8645ca68 100644
--- a/core/condition_test.go
+++ b/core/condition_test.go
@@ -1,663 +1,437 @@
package core
import (
- "fmt"
"strconv"
"testing"
"time"
)
-func TestCondition_evaluateWithIP(t *testing.T) {
- condition := Condition("[IP] == 127.0.0.1")
- result := &Result{IP: "127.0.0.1"}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
-}
-
-func TestCondition_evaluateWithStatus(t *testing.T) {
- condition := Condition("[STATUS] == 201")
- result := &Result{HTTPStatus: 201}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- if result.ConditionResults[0].Condition != string(condition) {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, condition, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithStatusFailure(t *testing.T) {
- condition := Condition("[STATUS] == 200")
- result := &Result{HTTPStatus: 500}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[STATUS] (500) == 200"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithStatusUsingLessThan(t *testing.T) {
- condition := Condition("[STATUS] < 300")
- result := &Result{HTTPStatus: 201}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[STATUS] < 300"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithStatusFailureUsingLessThan(t *testing.T) {
- condition := Condition("[STATUS] < 300")
- result := &Result{HTTPStatus: 404}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[STATUS] (404) < 300"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithResponseTimeUsingLessThan(t *testing.T) {
- condition := Condition("[RESPONSE_TIME] < 500")
- result := &Result{Duration: time.Millisecond * 50}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] < 500"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-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)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] < 1s"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].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)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] (50) < potato (0)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[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)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] > 500"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-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)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] > 1s"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithResponseTimeUsingGreaterThanOrEqualTo(t *testing.T) {
- condition := Condition("[RESPONSE_TIME] >= 500")
- result := &Result{Duration: time.Millisecond * 500}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] >= 500"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithResponseTimeUsingLessThanOrEqualTo(t *testing.T) {
- condition := Condition("[RESPONSE_TIME] <= 500")
- result := &Result{Duration: time.Millisecond * 500}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[RESPONSE_TIME] <= 500"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBody(t *testing.T) {
- condition := Condition("[BODY] == test")
- result := &Result{body: []byte("test")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY] == test"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPath(t *testing.T) {
- condition := Condition("[BODY].status == UP")
- result := &Result{body: []byte("{\"status\":\"UP\"}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].status == UP"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathComplex(t *testing.T) {
- condition := Condition("[BODY].data.name == john")
- result := &Result{body: []byte("{\"data\": {\"id\": 1, \"name\": \"john\"}}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].data.name == john"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithInvalidBodyJSONPathComplex(t *testing.T) {
- condition := Condition("[BODY].data.name == john")
- result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure, because the path was invalid", condition)
- }
- expectedConditionDisplayed := "[BODY].data.name (INVALID) == john"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithInvalidBodyJSONPathComplexWithLengthFunction(t *testing.T) {
- condition := Condition("len([BODY].data.name) == john")
- result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure, because the path was invalid", condition)
- }
- expectedConditionDisplayed := "len([BODY].data.name) (INVALID) == john"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathDoublePlaceholders(t *testing.T) {
- condition := Condition("[BODY].user.firstName != [BODY].user.lastName")
- result := &Result{body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].user.firstName != [BODY].user.lastName"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathDoublePlaceholdersFailure(t *testing.T) {
- condition := Condition("[BODY].user.firstName == [BODY].user.lastName")
- result := &Result{body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[BODY].user.firstName (john) == [BODY].user.lastName (doe)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathLongInt(t *testing.T) {
- condition := Condition("[BODY].data.id == 1")
- result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].data.id == 1"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathComplexInt(t *testing.T) {
- condition := Condition("[BODY].data[1].id == 2")
- result := &Result{body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].data[1].id == 2"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathComplexIntUsingGreaterThan(t *testing.T) {
- condition := Condition("[BODY].data.id > 0")
- result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].data.id > 0"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathComplexIntFailureUsingGreaterThan(t *testing.T) {
- condition := Condition("[BODY].data.id > 5")
- result := &Result{body: []byte("{\"data\": {\"id\": 1}}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[BODY].data.id (1) > 5"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathComplexIntUsingLessThan(t *testing.T) {
- condition := Condition("[BODY].data.id < 5")
- result := &Result{body: []byte("{\"data\": {\"id\": 2}}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].data.id < 5"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyJSONPathComplexIntFailureUsingLessThan(t *testing.T) {
- condition := Condition("[BODY].data.id < 5")
- result := &Result{body: []byte("{\"data\": {\"id\": 10}}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[BODY].data.id (10) < 5"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodySliceLength(t *testing.T) {
- condition := Condition("len([BODY].data) == 3")
- result := &Result{body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "len([BODY].data) == 3"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyStringLength(t *testing.T) {
- condition := Condition("len([BODY].name) == 8")
- result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "len([BODY].name) == 8"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyPattern(t *testing.T) {
- condition := Condition("[BODY] == pat(*john*)")
- result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY] == pat(*john*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithReverseBodyPattern(t *testing.T) {
- condition := Condition("pat(*john*) == [BODY]")
- result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "pat(*john*) == [BODY]"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyStringPattern(t *testing.T) {
- condition := Condition("[BODY].name == pat(*ohn*)")
- result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY].name == pat(*ohn*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyHTMLPattern(t *testing.T) {
- var html = `
john.doe
`
- condition := Condition("[BODY] == pat(*john.doe
*)")
- result := &Result{body: []byte(html)}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[BODY] == pat(*john.doe
*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyStringPatternFailure(t *testing.T) {
- condition := Condition("[BODY].name == pat(bob*)")
- result := &Result{body: []byte("{\"name\": \"john.doe\"}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[BODY].name (john.doe) == pat(bob*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithIPPattern(t *testing.T) {
- condition := Condition("[IP] == pat(10.*)")
- result := &Result{IP: "10.0.0.0"}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[IP] == pat(10.*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithIPPatternFailure(t *testing.T) {
- condition := Condition("[IP] == pat(10.*)")
- result := &Result{IP: "255.255.255.255"}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[IP] (255.255.255.255) == pat(10.*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithStatusPattern(t *testing.T) {
- condition := Condition("[STATUS] == pat(4*)")
- result := &Result{HTTPStatus: 404}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[STATUS] == pat(4*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithStatusPatternFailure(t *testing.T) {
- condition := Condition("[STATUS] != pat(4*)")
- result := &Result{HTTPStatus: 404}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[STATUS] (404) != pat(4*)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithBodyStringAny(t *testing.T) {
- condition := Condition("[BODY].name == any(john.doe, jane.doe)")
- expectedConditionDisplayed := "[BODY].name == any(john.doe, jane.doe)"
- results := []*Result{
- {body: []byte("{\"name\": \"john.doe\"}")},
- {body: []byte("{\"name\": \"jane.doe\"}")},
- }
- for _, result := range results {
- success := condition.evaluate(result)
- if !success || !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
- }
-}
-
-func TestCondition_evaluateWithBodyStringAnyFailure(t *testing.T) {
- condition := Condition("[BODY].name == any(john.doe, jane.doe)")
- result := &Result{body: []byte("{\"name\": \"bob.doe\"}")}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[BODY].name (bob.doe) == any(john.doe, jane.doe)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithStatusAny(t *testing.T) {
- condition := Condition("[STATUS] == any(200, 429)")
- statuses := []int{200, 429}
- for _, status := range statuses {
- result := &Result{HTTPStatus: status}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[STATUS] == any(200, 429)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
- }
-}
-
-func TestCondition_evaluateWithReverseStatusAny(t *testing.T) {
- condition := Condition("any(200, 429) == [STATUS]")
- statuses := []int{200, 429}
- for _, status := range statuses {
- result := &Result{HTTPStatus: status}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "any(200, 429) == [STATUS]"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
- }
-}
-
-func TestCondition_evaluateWithStatusAnyFailure(t *testing.T) {
- condition := Condition("[STATUS] == any(200, 429)")
- statuses := []int{201, 400, 404, 500}
- for _, status := range statuses {
- result := &Result{HTTPStatus: status}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := fmt.Sprintf("[STATUS] (%d) == any(200, 429)", status)
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
- }
-}
-
-func TestCondition_evaluateWithReverseStatusAnyFailure(t *testing.T) {
- condition := Condition("any(200, 429) == [STATUS]")
- statuses := []int{201, 400, 404, 500}
- for _, status := range statuses {
- result := &Result{HTTPStatus: status}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := fmt.Sprintf("any(200, 429) == [STATUS] (%d)", status)
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
- }
-}
-
-func TestCondition_evaluateWithConnected(t *testing.T) {
- condition := Condition("[CONNECTED] == true")
- result := &Result{Connected: true}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[CONNECTED] == true"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithConnectedFailure(t *testing.T) {
- condition := Condition("[CONNECTED] == true")
- result := &Result{Connected: false}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[CONNECTED] (false) == true"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-func TestCondition_evaluateWithUnsetCertificateExpiration(t *testing.T) {
- condition := Condition("[CERTIFICATE_EXPIRATION] == 0")
- result := &Result{}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[CERTIFICATE_EXPIRATION] == 0"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-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}
- condition.evaluate(result)
- if !result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a success", condition)
- }
- expectedConditionDisplayed := "[CERTIFICATE_EXPIRATION] > 2419200000"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
- }
-}
-
-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}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- expectedConditionDisplayed := "[CERTIFICATE_EXPIRATION] (1209600000) > 2419200000"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].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)
- }
- expectedConditionDisplayed := "[CERTIFICATE_EXPIRATION] > 12h"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].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)
- }
- expectedConditionDisplayed := "[CERTIFICATE_EXPIRATION] (86400000) > 48h (172800000)"
- if result.ConditionResults[0].Condition != expectedConditionDisplayed {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, expectedConditionDisplayed, result.ConditionResults[0].Condition)
+func TestCondition_evaluate(t *testing.T) {
+ type scenario struct {
+ Name string
+ Condition Condition
+ Result *Result
+ ExpectedSuccess bool
+ ExpectedOutput string
+ }
+ scenarios := []scenario{
+ {
+ Name: "ip",
+ Condition: Condition("[IP] == 127.0.0.1"),
+ Result: &Result{IP: "127.0.0.1"},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[IP] == 127.0.0.1",
+ },
+ {
+ Name: "status",
+ Condition: Condition("[STATUS] == 200"),
+ Result: &Result{HTTPStatus: 200},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[STATUS] == 200",
+ },
+ {
+ Name: "status-failure",
+ Condition: Condition("[STATUS] == 200"),
+ Result: &Result{HTTPStatus: 500},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[STATUS] (500) == 200",
+ },
+ {
+ Name: "status-using-less-than",
+ Condition: Condition("[STATUS] < 300"),
+ Result: &Result{HTTPStatus: 201},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[STATUS] < 300",
+ },
+ {
+ Name: "status-using-less-than-failure",
+ Condition: Condition("[STATUS] < 300"),
+ Result: &Result{HTTPStatus: 404},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[STATUS] (404) < 300",
+ },
+ {
+ Name: "response-time-using-less-than",
+ Condition: Condition("[RESPONSE_TIME] < 500"),
+ Result: &Result{Duration: 50 * time.Millisecond},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] < 500",
+ },
+ {
+ Name: "response-time-using-less-than-with-duration",
+ Condition: Condition("[RESPONSE_TIME] < 1s"),
+ Result: &Result{Duration: 50 * time.Millisecond},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] < 1s",
+ },
+ {
+ Name: "response-time-using-less-than-invalid",
+ Condition: Condition("[RESPONSE_TIME] < potato"),
+ Result: &Result{Duration: 50 * time.Millisecond},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[RESPONSE_TIME] (50) < potato (0)", // Non-numerical values automatically resolve to 0
+ },
+ {
+ Name: "response-time-using-greater-than",
+ Condition: Condition("[RESPONSE_TIME] > 500"),
+ Result: &Result{Duration: 750 * time.Millisecond},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] > 500",
+ },
+ {
+ Name: "response-time-using-greater-than-with-duration",
+ Condition: Condition("[RESPONSE_TIME] > 1s"),
+ Result: &Result{Duration: 2 * time.Second},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] > 1s",
+ },
+ {
+ Name: "response-time-using-greater-than-or-equal-to-equal",
+ Condition: Condition("[RESPONSE_TIME] >= 500"),
+ Result: &Result{Duration: 500 * time.Millisecond},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] >= 500",
+ },
+ {
+ Name: "response-time-using-greater-than-or-equal-to-greater",
+ Condition: Condition("[RESPONSE_TIME] >= 500"),
+ Result: &Result{Duration: 499 * time.Millisecond},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[RESPONSE_TIME] (499) >= 500",
+ },
+ {
+ Name: "response-time-using-greater-than-or-equal-to-failure",
+ Condition: Condition("[RESPONSE_TIME] >= 500"),
+ Result: &Result{Duration: 499 * time.Millisecond},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[RESPONSE_TIME] (499) >= 500",
+ },
+ {
+ Name: "response-time-using-less-than-or-equal-to-equal",
+ Condition: Condition("[RESPONSE_TIME] <= 500"),
+ Result: &Result{Duration: 500 * time.Millisecond},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] <= 500",
+ },
+ {
+ Name: "response-time-using-less-than-or-equal-to-less",
+ Condition: Condition("[RESPONSE_TIME] <= 500"),
+ Result: &Result{Duration: 25 * time.Millisecond},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[RESPONSE_TIME] <= 500",
+ },
+ {
+ Name: "response-time-using-less-than-or-equal-to-failure",
+ Condition: Condition("[RESPONSE_TIME] <= 500"),
+ Result: &Result{Duration: 750 * time.Millisecond},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[RESPONSE_TIME] (750) <= 500",
+ },
+ {
+ Name: "body",
+ Condition: Condition("[BODY] == test"),
+ Result: &Result{body: []byte("test")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY] == test",
+ },
+ {
+ Name: "body-jsonpath",
+ Condition: Condition("[BODY].status == UP"),
+ Result: &Result{body: []byte("{\"status\":\"UP\"}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].status == UP",
+ },
+ {
+ Name: "body-jsonpath-complex",
+ Condition: Condition("[BODY].data.name == john"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 1, \"name\": \"john\"}}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].data.name == john",
+ },
+ {
+ Name: "body-jsonpath-complex-invalid",
+ Condition: Condition("[BODY].data.name == john"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 1}}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[BODY].data.name (INVALID) == john",
+ },
+ {
+ Name: "body-jsonpath-complex-len",
+ Condition: Condition("len([BODY].data.name) == 4"),
+ Result: &Result{body: []byte("{\"data\": {\"name\": \"john\"}}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "len([BODY].data.name) == 4",
+ },
+ {
+ Name: "body-jsonpath-complex-len-invalid",
+ Condition: Condition("len([BODY].data.name) == john"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 1}}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "len([BODY].data.name) (INVALID) == john",
+ },
+ {
+ Name: "body-jsonpath-double-placeholder",
+ Condition: Condition("[BODY].user.firstName != [BODY].user.lastName"),
+ Result: &Result{body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].user.firstName != [BODY].user.lastName",
+ },
+ {
+ Name: "body-jsonpath-double-placeholder-failure",
+ Condition: Condition("[BODY].user.firstName == [BODY].user.lastName"),
+ Result: &Result{body: []byte("{\"user\": {\"firstName\": \"john\", \"lastName\": \"doe\"}}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[BODY].user.firstName (john) == [BODY].user.lastName (doe)",
+ },
+ {
+ Name: "body-jsonpath-complex-int",
+ Condition: Condition("[BODY].data.id == 1"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 1}}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].data.id == 1",
+ },
+ {
+ Name: "body-jsonpath-complex-array-int",
+ Condition: Condition("[BODY].data[1].id == 2"),
+ Result: &Result{body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].data[1].id == 2",
+ },
+ {
+ Name: "body-jsonpath-complex-int-using-greater-than",
+ Condition: Condition("[BODY].data.id > 0"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 1}}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].data.id > 0",
+ },
+ {
+ Name: "body-jsonpath-complex-int-using-greater-than-failure",
+ Condition: Condition("[BODY].data.id > 5"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 1}}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[BODY].data.id (1) > 5",
+ },
+ {
+ Name: "body-jsonpath-complex-int-using-less-than",
+ Condition: Condition("[BODY].data.id < 5"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 2}}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].data.id < 5",
+ },
+ {
+ Name: "body-jsonpath-complex-int-using-less-than-failure",
+ Condition: Condition("[BODY].data.id < 5"),
+ Result: &Result{body: []byte("{\"data\": {\"id\": 10}}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[BODY].data.id (10) < 5",
+ },
+ {
+ Name: "body-len-array",
+ Condition: Condition("len([BODY].data) == 3"),
+ Result: &Result{body: []byte("{\"data\": [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "len([BODY].data) == 3",
+ },
+ {
+ Name: "body-len-array-invalid",
+ Condition: Condition("len([BODY].data) == 8"),
+ Result: &Result{body: []byte("{\"name\": \"john.doe\"}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "len([BODY].data) (INVALID) == 8",
+ },
+ {
+ Name: "body-len-string",
+ Condition: Condition("len([BODY].name) == 8"),
+ Result: &Result{body: []byte("{\"name\": \"john.doe\"}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "len([BODY].name) == 8",
+ },
+ {
+ Name: "body-pattern",
+ Condition: Condition("[BODY] == pat(*john*)"),
+ Result: &Result{body: []byte("{\"name\": \"john.doe\"}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY] == pat(*john*)",
+ },
+ {
+ Name: "body-pattern-2",
+ Condition: Condition("[BODY].name == pat(john*)"),
+ Result: &Result{body: []byte("{\"name\": \"john.doe\"}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].name == pat(john*)",
+ },
+ {
+ Name: "body-pattern-failure",
+ Condition: Condition("[BODY].name == pat(bob*)"),
+ Result: &Result{body: []byte("{\"name\": \"john.doe\"}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[BODY].name (john.doe) == pat(bob*)",
+ },
+ {
+ Name: "body-pattern-html",
+ Condition: Condition("[BODY] == pat(*john.doe
*)"),
+ Result: &Result{body: []byte(`john.doe
`)},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY] == pat(*john.doe
*)",
+ },
+ {
+ Name: "ip-pattern",
+ Condition: Condition("[IP] == pat(10.*)"),
+ Result: &Result{IP: "10.0.0.0"},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[IP] == pat(10.*)",
+ },
+ {
+ Name: "ip-pattern-failure",
+ Condition: Condition("[IP] == pat(10.*)"),
+ Result: &Result{IP: "255.255.255.255"},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[IP] (255.255.255.255) == pat(10.*)",
+ },
+ {
+ Name: "status-pattern",
+ Condition: Condition("[STATUS] == pat(4*)"),
+ Result: &Result{HTTPStatus: 404},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[STATUS] == pat(4*)",
+ },
+ {
+ Name: "status-pattern-failure",
+ Condition: Condition("[STATUS] == pat(4*)"),
+ Result: &Result{HTTPStatus: 200},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[STATUS] (200) == pat(4*)",
+ },
+ {
+ Name: "body-any",
+ Condition: Condition("[BODY].name == any(john.doe, jane.doe)"),
+ Result: &Result{body: []byte("{\"name\": \"john.doe\"}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].name == any(john.doe, jane.doe)",
+ },
+ {
+ Name: "body-any-2",
+ Condition: Condition("[BODY].name == any(john.doe, jane.doe)"),
+ Result: &Result{body: []byte("{\"name\": \"jane.doe\"}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[BODY].name == any(john.doe, jane.doe)",
+ },
+ {
+ Name: "body-any-failure",
+ Condition: Condition("[BODY].name == any(john.doe, jane.doe)"),
+ Result: &Result{body: []byte("{\"name\": \"bob\"}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[BODY].name (bob) == any(john.doe, jane.doe)",
+ },
+ {
+ Name: "status-any",
+ Condition: Condition("[STATUS] == any(200, 429)"),
+ Result: &Result{HTTPStatus: 200},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[STATUS] == any(200, 429)",
+ },
+ {
+ Name: "status-any-2",
+ Condition: Condition("[STATUS] == any(200, 429)"),
+ Result: &Result{HTTPStatus: 429},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[STATUS] == any(200, 429)",
+ },
+ {
+ Name: "status-any-reverse",
+ Condition: Condition("any(200, 429) == [STATUS]"),
+ Result: &Result{HTTPStatus: 429},
+ ExpectedSuccess: true,
+ ExpectedOutput: "any(200, 429) == [STATUS]",
+ },
+ {
+ Name: "status-any-failure",
+ Condition: Condition("[STATUS] == any(200, 429)"),
+ Result: &Result{HTTPStatus: 404},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[STATUS] (404) == any(200, 429)",
+ },
+ {
+ Name: "connected",
+ Condition: Condition("[CONNECTED] == true"),
+ Result: &Result{Connected: true},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[CONNECTED] == true",
+ },
+ {
+ Name: "connected-failure",
+ Condition: Condition("[CONNECTED] == true"),
+ Result: &Result{Connected: false},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[CONNECTED] (false) == true",
+ },
+ {
+ Name: "certificate-expiration-not-set",
+ Condition: Condition("[CERTIFICATE_EXPIRATION] == 0"),
+ Result: &Result{},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[CERTIFICATE_EXPIRATION] == 0",
+ },
+ {
+ Name: "certificate-expiration-greater-than-numerical",
+ Condition: Condition("[CERTIFICATE_EXPIRATION] > " + strconv.FormatInt((time.Hour*24*28).Milliseconds(), 10)),
+ Result: &Result{CertificateExpiration: time.Hour * 24 * 60},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[CERTIFICATE_EXPIRATION] > 2419200000",
+ },
+ {
+ Name: "certificate-expiration-greater-than-numerical-failure",
+ Condition: Condition("[CERTIFICATE_EXPIRATION] > " + strconv.FormatInt((time.Hour*24*28).Milliseconds(), 10)),
+ Result: &Result{CertificateExpiration: time.Hour * 24 * 14},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[CERTIFICATE_EXPIRATION] (1209600000) > 2419200000",
+ },
+ {
+ Name: "certificate-expiration-greater-than-duration",
+ Condition: Condition("[CERTIFICATE_EXPIRATION] > 12h"),
+ Result: &Result{CertificateExpiration: 24 * time.Hour},
+ ExpectedSuccess: true,
+ ExpectedOutput: "[CERTIFICATE_EXPIRATION] > 12h",
+ },
+ {
+ Name: "certificate-expiration-greater-than-duration",
+ Condition: Condition("[CERTIFICATE_EXPIRATION] > 48h"),
+ Result: &Result{CertificateExpiration: 24 * time.Hour},
+ ExpectedSuccess: false,
+ ExpectedOutput: "[CERTIFICATE_EXPIRATION] (86400000) > 48h (172800000)",
+ },
+ {
+ Name: "has",
+ Condition: Condition("has([BODY].errors) == false"),
+ Result: &Result{body: []byte("{}")},
+ ExpectedSuccess: true,
+ ExpectedOutput: "has([BODY].errors) == false",
+ },
+ {
+ Name: "has-failure",
+ Condition: Condition("has([BODY].errors) == false"),
+ Result: &Result{body: []byte("{\"errors\": [\"1\"]}")},
+ ExpectedSuccess: false,
+ ExpectedOutput: "has([BODY].errors) (true) == false",
+ },
+ {
+ Name: "no-placeholders",
+ Condition: Condition("1 == 2"),
+ Result: &Result{},
+ ExpectedSuccess: false,
+ ExpectedOutput: "1 == 2",
+ },
+ }
+ for _, scenario := range scenarios {
+ t.Run(scenario.Name, func(t *testing.T) {
+ scenario.Condition.evaluate(scenario.Result)
+ if scenario.Result.ConditionResults[0].Success != scenario.ExpectedSuccess {
+ t.Errorf("Condition '%s' should have been success=%v", scenario.Condition, scenario.ExpectedSuccess)
+ }
+ if scenario.Result.ConditionResults[0].Condition != scenario.ExpectedOutput {
+ t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", scenario.Condition, scenario.ExpectedOutput, scenario.Result.ConditionResults[0].Condition)
+ }
+ })
}
}
@@ -672,15 +446,3 @@ func TestCondition_evaluateWithInvalidOperator(t *testing.T) {
t.Error("condition was invalid, result should've had an error")
}
}
-
-func TestCondition_evaluateWithNoPlaceholder(t *testing.T) {
- condition := Condition("1 == 2")
- result := &Result{}
- condition.evaluate(result)
- if result.ConditionResults[0].Success {
- t.Errorf("Condition '%s' should have been a failure", condition)
- }
- if result.ConditionResults[0].Condition != string(condition) {
- t.Errorf("Condition '%s' should have resolved to '%s', got '%s'", condition, condition, result.ConditionResults[0].Condition)
- }
-}