mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-21 08:10:24 +08:00
merge master
This commit is contained in:
@@ -52,7 +52,7 @@
|
||||
"msg": "check status_code"
|
||||
},
|
||||
{
|
||||
"check": "body.headers.postman-token",
|
||||
"check": "body.headers.\"postman-token\"",
|
||||
"assert": "equal",
|
||||
"expect": "ea19464c-ddd4-4724-abe9-5e2b254c2723",
|
||||
"msg": "check body.headers.postman-token"
|
||||
|
||||
@@ -123,24 +123,35 @@ type responseObject struct {
|
||||
|
||||
const textExtractorSubRegexp string = `(.*)`
|
||||
|
||||
func (v *responseObject) searchField(value string) interface{} {
|
||||
var result interface{}
|
||||
if strings.Contains(value, textExtractorSubRegexp) {
|
||||
result = v.searchRegexp(value)
|
||||
} else {
|
||||
result = v.searchJmespath(value)
|
||||
func (v *responseObject) searchField(field string, variablesMapping map[string]interface{}) interface{} {
|
||||
var result interface{} = field
|
||||
if strings.Contains(field, "$") {
|
||||
// parse reference variables in field before search
|
||||
var err error
|
||||
result, err = v.parser.Parse(field, variablesMapping)
|
||||
if err != nil {
|
||||
log.Error().Str("filed name", field).Err(err).Msg("fail to parse field before search")
|
||||
}
|
||||
}
|
||||
// search field using jmespath or regex if parsed field is still string and contains specified fieldTags
|
||||
if parsedField, ok := result.(string); ok && checkSearchField(parsedField) {
|
||||
if strings.Contains(field, textExtractorSubRegexp) {
|
||||
result = v.searchRegexp(parsedField)
|
||||
} else {
|
||||
result = v.searchJmespath(parsedField)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *responseObject) Extract(extractors map[string]string) map[string]interface{} {
|
||||
func (v *responseObject) Extract(extractors map[string]string, variablesMapping map[string]interface{}) map[string]interface{} {
|
||||
if extractors == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
extractMapping := make(map[string]interface{})
|
||||
for key, value := range extractors {
|
||||
extractedValue := v.searchField(value)
|
||||
extractedValue := v.searchField(value, variablesMapping)
|
||||
log.Info().Str("from", value).Interface("value", extractedValue).Msg("extract value")
|
||||
log.Info().Str("variable", key).Interface("value", extractedValue).Msg("set variable")
|
||||
extractMapping[key] = extractedValue
|
||||
@@ -157,19 +168,7 @@ func (v *responseObject) Validate(iValidators []interface{}, variablesMapping ma
|
||||
}
|
||||
// parse check value
|
||||
checkItem := validator.Check
|
||||
var checkValue interface{}
|
||||
if strings.Contains(checkItem, "$") {
|
||||
// parse reference variables in checkItem
|
||||
checkValue, err = v.parser.Parse(checkItem, variablesMapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
checkValue = checkItem
|
||||
}
|
||||
if searchCheckValue, ok := checkValue.(string); ok && checkSearchField(searchCheckValue) {
|
||||
checkValue = v.searchField(searchCheckValue)
|
||||
}
|
||||
checkValue := v.searchField(checkItem, variablesMapping)
|
||||
|
||||
// get assert method
|
||||
assertMethod := validator.Assert
|
||||
|
||||
@@ -419,7 +419,7 @@ func runStepRequest(r *SessionRunner, step *TStep) (stepResult *StepResult, err
|
||||
|
||||
// extract variables from response
|
||||
extractors := step.Extract
|
||||
extractMapping := respObj.Extract(extractors)
|
||||
extractMapping := respObj.Extract(extractors, stepVariables)
|
||||
stepResult.ExportVars = extractMapping
|
||||
|
||||
// override step variables with extracted variables
|
||||
|
||||
@@ -365,7 +365,7 @@ func runStepWebSocket(r *SessionRunner, step *TStep) (stepResult *StepResult, er
|
||||
|
||||
// extract variables from response
|
||||
extractors := step.Extract
|
||||
extractMapping := respObj.Extract(extractors)
|
||||
extractMapping := respObj.Extract(extractors, stepVariables)
|
||||
stepResult.ExportVars = extractMapping
|
||||
|
||||
// override step variables with extracted variables
|
||||
|
||||
@@ -199,6 +199,9 @@ func (tc *TCase) MakeCompat() (err error) {
|
||||
func convertCompatRequestBody(request *Request) {
|
||||
if request != nil && request.Body == nil {
|
||||
if request.Json != nil {
|
||||
if request.Headers == nil {
|
||||
request.Headers = make(map[string]string)
|
||||
}
|
||||
request.Headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
request.Body = request.Json
|
||||
request.Json = nil
|
||||
@@ -228,7 +231,7 @@ func convertCompatValidator(Validators []interface{}) (err error) {
|
||||
if iMsg, msgExisted := validatorMap["msg"]; msgExisted {
|
||||
validator.Message = iMsg.(string)
|
||||
}
|
||||
validator.Check = convertCheckExpr(validator.Check)
|
||||
validator.Check = convertJmespathExpr(validator.Check)
|
||||
Validators[i] = validator
|
||||
continue
|
||||
}
|
||||
@@ -246,7 +249,7 @@ func convertCompatValidator(Validators []interface{}) (err error) {
|
||||
validator.Message = validatorContent[2].(string)
|
||||
}
|
||||
}
|
||||
validator.Check = convertCheckExpr(validator.Check)
|
||||
validator.Check = convertJmespathExpr(validator.Check)
|
||||
Validators[i] = validator
|
||||
continue
|
||||
}
|
||||
@@ -258,18 +261,20 @@ func convertCompatValidator(Validators []interface{}) (err error) {
|
||||
// convertExtract deals with extract expr including hyphen
|
||||
func convertExtract(extract map[string]string) {
|
||||
for key, value := range extract {
|
||||
extract[key] = convertCheckExpr(value)
|
||||
extract[key] = convertJmespathExpr(value)
|
||||
}
|
||||
}
|
||||
|
||||
// convertCheckExpr deals with check expression including hyphen
|
||||
func convertCheckExpr(checkExpr string) string {
|
||||
// convertJmespathExpr deals with limited jmespath expression conversion
|
||||
func convertJmespathExpr(checkExpr string) string {
|
||||
if strings.Contains(checkExpr, textExtractorSubRegexp) {
|
||||
return checkExpr
|
||||
}
|
||||
checkItems := strings.Split(checkExpr, ".")
|
||||
for i, checkItem := range checkItems {
|
||||
if strings.Contains(checkItem, "-") && !strings.Contains(checkItem, "\"") {
|
||||
checkItem = strings.Trim(checkItem, "\"")
|
||||
lowerItem := strings.ToLower(checkItem)
|
||||
if strings.HasPrefix(lowerItem, "content-") || lowerItem == "user-agent" {
|
||||
checkItems[i] = fmt.Sprintf("\"%s\"", checkItem)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,21 +210,20 @@ func TestConvertCheckExpr(t *testing.T) {
|
||||
}{
|
||||
// normal check expression
|
||||
{"a.b.c", "a.b.c"},
|
||||
{"headers.\"Content-Type\"", "headers.\"Content-Type\""},
|
||||
{"a.\"b-c\".d", "a.\"b-c\".d"},
|
||||
{"a.b-c.d", "a.b-c.d"},
|
||||
{"body.args.a[-1]", "body.args.a[-1]"},
|
||||
// check expression using regex
|
||||
{"covering (.*) testing,", "covering (.*) testing,"},
|
||||
{" (.*) a-b-c", " (.*) a-b-c"},
|
||||
// abnormal check expression
|
||||
{"-", "\"-\""},
|
||||
{"b-c", "\"b-c\""},
|
||||
{"a.b-c.d", "a.\"b-c\".d"},
|
||||
{"a-b.c-d", "\"a-b\".\"c-d\""},
|
||||
{"\"a-b\".c-d", "\"a-b\".\"c-d\""},
|
||||
{"headers.Content-Type", "headers.\"Content-Type\""},
|
||||
{"body.I-am-a-Key.name", "body.\"I-am-a-Key\".name"},
|
||||
{"headers.\"Content-Type", "headers.\"Content-Type\""},
|
||||
{"headers.Content-Type\"", "headers.\"Content-Type\""},
|
||||
{"headers.User-Agent", "headers.\"User-Agent\""},
|
||||
}
|
||||
for _, expr := range exprs {
|
||||
if !assert.Equal(t, convertCheckExpr(expr.before), expr.after) {
|
||||
if !assert.Equal(t, expr.after, convertJmespathExpr(expr.before)) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ func TestCaseExtractStepSingle(t *testing.T) {
|
||||
"var1": "bar1",
|
||||
"agent": "HttpRunnerPlus",
|
||||
"expectedStatusCode": 200,
|
||||
"jmespathFoo1": "body.args.foo1",
|
||||
}).
|
||||
GET("/get").
|
||||
WithParams(map[string]interface{}{"foo1": "$var1", "foo2": "bar2"}).
|
||||
@@ -25,7 +26,7 @@ func TestCaseExtractStepSingle(t *testing.T) {
|
||||
Extract().
|
||||
WithJmesPath("status_code", "statusCode").
|
||||
WithJmesPath("headers.\"Content-Type\"", "contentType").
|
||||
WithJmesPath("body.args.foo1", "varFoo1").
|
||||
WithJmesPath("$jmespathFoo1", "varFoo1").
|
||||
Validate().
|
||||
AssertEqual("$statusCode", "$expectedStatusCode", "check status code"). // assert with extracted variable from current step
|
||||
AssertEqual("$contentType", "application/json; charset=utf-8", "check header Content-Type"). // assert with extracted variable from current step
|
||||
|
||||
Reference in New Issue
Block a user