diff --git a/docs/BUILTIN.md b/docs/BUILTIN.md new file mode 100644 index 00000000..e90b0a04 --- /dev/null +++ b/docs/BUILTIN.md @@ -0,0 +1,44 @@ +# Builtin + +## Assertion Methods + +### Usage +In "teststeps" of each json/yaml testcase, the "validate" part contains four fields: "check", "assert", "expect" and +"msg", when using assertion methods, method name should be put in "assert" field. The assertion result of "check" +element will be checked out using the regulation you put in "assert" field and compared with the element in "expect" +field. + +### Method List + +- equals: assert the element to check equals the expected element. +- equal: alias for equals. +- greater_than: assert the element to check is greater than the expected element. +- less_than: assert the element to check is less than the expected element. +- greater_or_equals: assert the element to check is greater than or equal with the expected element. +- less_or_equals: assert the element to check is less than or equal with the expected element. +- not_equal: assert the element to check is not equal with the expected element. +- contained_by: assert the expected element contains the element to check. +- regex_match: assert the element to check matches the expected element using regex. +- type_match: assert the element to check matches the expected element in type. +- startswith: assert the element to check starts with the expected element. +- endswith: assert the element to check ends with the expected element. +- length_equals: assert the length of the element to check is equal with the expected element. +- length_equal: alias for length_equals. +- contains: assert the element to check contains the expected element. +- string_equals: assert the string is equal with the expected string. + +## Common Functions + +### Usage +The common functions are useful during the variables configuration, you can use "${FUNCTION_NAME}" to call the specific +function to define variables. + +### Function List +- get_timestamp: get the thirteen-digit timestamp of current time. (call without argument) +- sleep: sleep n seconds to simulate the thinking time. (call with one argument n) +- gen_random_string: get the n-digit random string. (call with one argument n) +- max: get the maximum of two numbers m and n. (call with two argument m and n) +- md5: get the MD5 of the input string s. (call with one argument s) + + + diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4f2f8207..4959cea2 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,7 @@ ## v0.3.1 (2021-12-30) +- feat: add more plentiful response assertion methods - feat: set ulimit to 10240 before load testing - fix: concurrent map writes in load testing diff --git a/examples/function_test.go b/examples/function_test.go index cd2c2d98..44c8c590 100644 --- a/examples/function_test.go +++ b/examples/function_test.go @@ -19,14 +19,18 @@ func TestCaseCallFunction(t *testing.T) { TestSteps: []hrp.IStep{ hrp.NewStep("get with params"). GET("/get"). - WithParams(map[string]interface{}{"foo1": "${gen_random_string($n)}", "foo2": "${max($a, $b)}"}). + WithParams(map[string]interface{}{"foo1": "${gen_random_string($n)}", "foo2": "${max($a, $b)}", "foo3": "Foo3"}). WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}). Extract(). WithJmesPath("body.args.foo1", "varFoo1"). Validate(). AssertEqual("status_code", 200, "check status code"). AssertLengthEqual("body.args.foo1", 5, "check args foo1"). - AssertEqual("body.args.foo2", "12.3", "check args foo2"), // notice: request params value will be converted to string + AssertEqual("body.args.foo2", "12.3", "check args foo2"). + AssertTypeMatch("body.args.foo3", "str", "check args foo3 is type string"). + AssertStringEqual("body.args.foo3", "foo3", "check args foo3 case-insensitivity"). + AssertContains("body.args.foo3", "Foo", "check contains "). + AssertContainedBy("body.args.foo3", "this is Foo3 test", "check contained by"), // notice: request params value will be converted to string hrp.NewStep("post json data with functions"). POST("/post"). WithHeaders(map[string]string{"User-Agent": "HttpRunnerPlus"}). diff --git a/internal/builtin/assertion.go b/internal/builtin/assertion.go index c995e26e..d59f6366 100644 --- a/internal/builtin/assertion.go +++ b/internal/builtin/assertion.go @@ -16,8 +16,9 @@ var Assertions = map[string]func(t assert.TestingT, expected interface{}, actual "greater_or_equals": assert.GreaterOrEqual, "less_or_equals": assert.LessOrEqual, "not_equal": assert.NotEqual, - "contains": assert.Contains, + "contained_by": assert.Contains, "regex_match": assert.Regexp, + "type_match": assert.IsType, // custom assertions "startswith": StartsWith, // check if string starts with substring "endswith": EndsWith, // check if string ends with substring @@ -27,6 +28,8 @@ var Assertions = map[string]func(t assert.TestingT, expected interface{}, actual "length_less_or_equals": LessOrEqualsLength, "length_greater_than": GreaterThanLength, "length_greater_or_equals": GreaterOrEqualsLength, + "contains": Contains, + "string_equals": EqualString, } func StartsWith(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { @@ -149,6 +152,23 @@ func convertInt(value interface{}) (int, error) { } } +// Contains assert whether actual element contains expected element +func Contains(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + return assert.Contains(t, actual, expected, msgAndArgs) +} + +func EqualString(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if !assert.IsType(t, "string", actual, msgAndArgs) { + return false + } + if !assert.IsType(t, "string", expected, msgAndArgs) { + return false + } + actualString := actual.(string) + expectedString := expected.(string) + return assert.True(t, strings.EqualFold(actualString, expectedString), msgAndArgs) +} + // getLen try to get length of object. // return (false, 0) if impossible. func getLen(x interface{}) (ok bool, length int) { diff --git a/internal/builtin/function.go b/internal/builtin/function.go index f4f7aaae..5554eaf6 100644 --- a/internal/builtin/function.go +++ b/internal/builtin/function.go @@ -19,7 +19,7 @@ var Functions = map[string]interface{}{ "sleep": sleep, // call with one argument "gen_random_string": genRandomString, // call with one argument "max": math.Max, // call with two arguments - "md5": MD5, + "md5": MD5, // call with one argument "parameterize": loadFromCSV, "P": loadFromCSV, } diff --git a/validate.go b/validate.go index 9464ea1b..8e2e857b 100644 --- a/validate.go +++ b/validate.go @@ -101,6 +101,17 @@ func (s *StepRequestValidation) AssertContains(jmesPath string, expected interfa return s } +func (s *StepRequestValidation) AssertTypeMatch(jmesPath string, expected interface{}, msg string) *StepRequestValidation { + v := Validator{ + Check: jmesPath, + Assert: "type_match", + Expect: expected, + Message: msg, + } + s.step.Validators = append(s.step.Validators, v) + return s +} + func (s *StepRequestValidation) AssertRegexp(jmesPath string, expected interface{}, msg string) *StepRequestValidation { v := Validator{ Check: jmesPath, @@ -145,6 +156,18 @@ func (s *StepRequestValidation) AssertLengthEqual(jmesPath string, expected inte return s } + +func (s *StepRequestValidation) AssertContainedBy(jmesPath string, expected interface{}, msg string) *StepRequestValidation { + v := Validator{ + Check: jmesPath, + Assert: "contained_by", + Expect: expected, + Message: msg, + } + s.step.Validators = append(s.step.Validators, v) + return s +} + func (s *StepRequestValidation) AssertLengthLessThan(jmesPath string, expected interface{}, msg string) *StepRequestValidation { v := Validator{ Check: jmesPath, @@ -156,6 +179,17 @@ func (s *StepRequestValidation) AssertLengthLessThan(jmesPath string, expected i return s } +func (s *StepRequestValidation) AssertStringEqual(jmesPath string, expected interface{}, msg string) *StepRequestValidation { + v := Validator{ + Check: jmesPath, + Assert: "string_equals", + Expect: expected, + Message: msg, + } + s.step.Validators = append(s.step.Validators, v) + return s +} + func (s *StepRequestValidation) AssertLengthLessOrEquals(jmesPath string, expected interface{}, msg string) *StepRequestValidation { v := Validator{ Check: jmesPath,