mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-09 06:23:52 +08:00
Merge pull request #97 from bbx-winner/main
fix #97: incorrect data type when extracting data using jmespath
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## v0.6.2 (2022-02-18)
|
## v0.6.2 (2022-02-20)
|
||||||
|
|
||||||
- fix: omit pseudo header names for HTTP/1, e.g. :authority
|
- fix: omit pseudo header names for HTTP/1, e.g. :authority
|
||||||
- fix: generate `headers.\"Content-Type\"` in har2case
|
- fix: generate `headers.\"Content-Type\"` in har2case
|
||||||
|
- change: json unmarshal to json.Number when parsing data
|
||||||
|
- fix: incorrect data type when extracting data using jmespath
|
||||||
|
|
||||||
## v0.6.1 (2022-02-17)
|
## v0.6.1 (2022-02-17)
|
||||||
|
|
||||||
|
|||||||
@@ -119,9 +119,13 @@
|
|||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
"foo1": "$varFoo1",
|
"foo1": "$varFoo1",
|
||||||
"foo2": "${max($a, $b)}"
|
"foo2": "${max($a, $b)}",
|
||||||
|
"time": "${get_timestamp()}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"extract": {
|
||||||
|
"varTime": "body.form.time"
|
||||||
|
},
|
||||||
"validate": [
|
"validate": [
|
||||||
{
|
{
|
||||||
"check": "status_code",
|
"check": "status_code",
|
||||||
@@ -142,6 +146,24 @@
|
|||||||
"msg": "check args foo2"
|
"msg": "check args foo2"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get with timestamp",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"url": "/get",
|
||||||
|
"params": {
|
||||||
|
"time": "$varTime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"check": "body.args.time",
|
||||||
|
"assert": "length_equals",
|
||||||
|
"expect": 13,
|
||||||
|
"msg": "check extracted var timestamp"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ teststeps:
|
|||||||
body:
|
body:
|
||||||
foo1: $varFoo1
|
foo1: $varFoo1
|
||||||
foo2: ${max($a, $b)}
|
foo2: ${max($a, $b)}
|
||||||
|
time: ${get_timestamp()}
|
||||||
|
extract:
|
||||||
|
varTime: body.form.time
|
||||||
validate:
|
validate:
|
||||||
- check: status_code
|
- check: status_code
|
||||||
assert: equals
|
assert: equals
|
||||||
@@ -93,3 +96,14 @@ teststeps:
|
|||||||
assert: equals
|
assert: equals
|
||||||
expect: "12.3"
|
expect: "12.3"
|
||||||
msg: check args foo2
|
msg: check args foo2
|
||||||
|
- name: get with timestamp
|
||||||
|
request:
|
||||||
|
method: GET
|
||||||
|
url: /get
|
||||||
|
params:
|
||||||
|
time: $varTime
|
||||||
|
validate:
|
||||||
|
- check: body.args.time
|
||||||
|
assert: length_equals
|
||||||
|
expect: 13
|
||||||
|
msg: check extracted var timestamp
|
||||||
|
|||||||
@@ -48,11 +48,18 @@ var demoTestCase = &hrp.TestCase{
|
|||||||
WithBody(map[string]interface{}{
|
WithBody(map[string]interface{}{
|
||||||
"foo1": "$varFoo1", // reference former extracted variable
|
"foo1": "$varFoo1", // reference former extracted variable
|
||||||
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
|
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
|
||||||
|
"time": "${get_timestamp()}",
|
||||||
}).
|
}).
|
||||||
|
Extract().
|
||||||
|
WithJmesPath("body.form.time", "varTime").
|
||||||
Validate().
|
Validate().
|
||||||
AssertEqual("status_code", 200, "check status code").
|
AssertEqual("status_code", 200, "check status code").
|
||||||
AssertLengthEqual("body.form.foo1", 5, "check args foo1").
|
AssertLengthEqual("body.form.foo1", 5, "check args foo1").
|
||||||
AssertEqual("body.form.foo2", "12.3", "check args foo2"), // form data will be converted to string
|
AssertEqual("body.form.foo2", "12.3", "check args foo2"), // form data will be converted to string
|
||||||
|
hrp.NewStep("get with timestamp").
|
||||||
|
GET("/get").WithParams(map[string]interface{}{"time": "$varTime"}).
|
||||||
|
Validate().
|
||||||
|
AssertLengthEqual("body.args.time", 13, "check extracted var timestamp"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
parser.go
13
parser.go
@@ -69,8 +69,7 @@ func (p *parser) parseData(raw interface{}, variablesMapping map[string]interfac
|
|||||||
case reflect.String:
|
case reflect.String:
|
||||||
// json.Number
|
// json.Number
|
||||||
if rawValue, ok := raw.(json.Number); ok {
|
if rawValue, ok := raw.(json.Number); ok {
|
||||||
// use the same rule as json.Unmarshal (float64, for JSON numbers)
|
return parseJSONNumber(rawValue)
|
||||||
return rawValue.Float64()
|
|
||||||
}
|
}
|
||||||
// other string
|
// other string
|
||||||
value := rawValue.String()
|
value := rawValue.String()
|
||||||
@@ -109,6 +108,16 @@ func (p *parser) parseData(raw interface{}, variablesMapping map[string]interfac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseJSONNumber(raw json.Number) (interface{}, error) {
|
||||||
|
if strings.Contains(raw.String(), ".") {
|
||||||
|
// float64
|
||||||
|
return raw.Float64()
|
||||||
|
} else {
|
||||||
|
// int64
|
||||||
|
return raw.Int64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
regexVariable = `[a-zA-Z_]\w*` // variable name should start with a letter or underscore
|
regexVariable = `[a-zA-Z_]\w*` // variable name should start with a letter or underscore
|
||||||
regexFunctionName = `[a-zA-Z_]\w*` // function name should start with a letter or underscore
|
regexFunctionName = `[a-zA-Z_]\w*` // function name should start with a letter or underscore
|
||||||
|
|||||||
12
response.go
12
response.go
@@ -1,6 +1,7 @@
|
|||||||
package hrp
|
package hrp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -53,7 +54,9 @@ func newResponseObject(t *testing.T, parser *parser, resp *http.Response) (*resp
|
|||||||
// convert respObjMeta to interface{}
|
// convert respObjMeta to interface{}
|
||||||
respObjMetaBytes, _ := json.Marshal(respObjMeta)
|
respObjMetaBytes, _ := json.Marshal(respObjMeta)
|
||||||
var data interface{}
|
var data interface{}
|
||||||
if err := json.Unmarshal(respObjMetaBytes, &data); err != nil {
|
decoder := json.NewDecoder(bytes.NewReader(respObjMetaBytes))
|
||||||
|
decoder.UseNumber()
|
||||||
|
if err := decoder.Decode(&data); err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Str("respObjMeta", string(respObjMetaBytes)).
|
Str("respObjMeta", string(respObjMetaBytes)).
|
||||||
Err(err).
|
Err(err).
|
||||||
@@ -167,5 +170,12 @@ func (v *responseObject) searchJmespath(expr string) interface{} {
|
|||||||
log.Error().Str("expr", expr).Err(err).Msg("search jmespath failed")
|
log.Error().Str("expr", expr).Err(err).Msg("search jmespath failed")
|
||||||
return expr // jmespath not found, return the expression
|
return expr // jmespath not found, return the expression
|
||||||
}
|
}
|
||||||
|
if number, ok := checkValue.(json.Number); ok {
|
||||||
|
checkNumber, err := parseJSONNumber(number)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Interface("json number", number).Err(err).Msg("convert json number failed")
|
||||||
|
}
|
||||||
|
return checkNumber
|
||||||
|
}
|
||||||
return checkValue
|
return checkValue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user