mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-28 03:30:01 +08:00
feat: parse variable
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
package httpboomer
|
package httpboomer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseStep(step IStep, config *TConfig) *TStep {
|
func parseStep(step IStep, config *TConfig) *TStep {
|
||||||
@@ -27,3 +30,55 @@ func buildURL(baseURL, stepURL string) string {
|
|||||||
// base url missed
|
// base url missed
|
||||||
return uStep.String()
|
return uStep.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseData(raw interface{}, variablesMapping map[string]interface{}) interface{} {
|
||||||
|
switch v := raw.(type) {
|
||||||
|
case string:
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
return parseString(v, variablesMapping)
|
||||||
|
default:
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
regexCompileVariable = regexp.MustCompile(`\$\{(\w+)\}|\$(\w+)`) // parse ${var} or $var
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseString parse string with variables
|
||||||
|
func parseString(raw string, variablesMapping map[string]interface{}) interface{} {
|
||||||
|
matchStartPosition := strings.Index(raw, "$")
|
||||||
|
if matchStartPosition == -1 { // no $ found
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
parsedString := raw[0:matchStartPosition]
|
||||||
|
|
||||||
|
for matchStartPosition < len(raw) {
|
||||||
|
// search variable like ${var} or $var
|
||||||
|
varMatched := regexCompileVariable.FindStringSubmatch(raw[matchStartPosition:])
|
||||||
|
if len(varMatched) == 3 {
|
||||||
|
var varName string
|
||||||
|
if varMatched[1] != "" {
|
||||||
|
varName = varMatched[1] // match ${var}
|
||||||
|
} else {
|
||||||
|
varName = varMatched[2] // match $var
|
||||||
|
}
|
||||||
|
varValue := variablesMapping[varName]
|
||||||
|
|
||||||
|
if fmt.Sprintf("${%s}", varName) == raw || fmt.Sprintf("$%s", varName) == raw {
|
||||||
|
// raw string is a variable, $var or ${var}, return its value directly
|
||||||
|
return varValue
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedString += fmt.Sprintf("%v", varValue)
|
||||||
|
matchStartPosition += len(varMatched[0])
|
||||||
|
log.Printf("[parseString] parsedString: %v, matchStartPosition: %v", parsedString, matchStartPosition)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// append remained string
|
||||||
|
parsedString += raw[matchStartPosition:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedString
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package httpboomer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuildURL(t *testing.T) {
|
func TestBuildURL(t *testing.T) {
|
||||||
@@ -27,3 +29,30 @@ func TestBuildURL(t *testing.T) {
|
|||||||
t.Fatalf("buildURL error, %s != 'https://httpbin.org/get'", url)
|
t.Fatalf("buildURL error, %s != 'https://httpbin.org/get'", url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseDataStringWithVariables(t *testing.T) {
|
||||||
|
variablesMapping := map[string]interface{}{
|
||||||
|
"var_1": "abc",
|
||||||
|
"var_2": "def",
|
||||||
|
"var_3": 123,
|
||||||
|
"var_4": map[string]interface{}{"a": 1},
|
||||||
|
"var_5": true,
|
||||||
|
"var_6": nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.Equal(t, "abc", parseData("$var_1", variablesMapping)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t, "abc", parseData("${var_1}", variablesMapping)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t, "var_1", parseData("var_1", variablesMapping)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t, "abc#XYZ", parseData("$var_1#XYZ", variablesMapping)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !assert.Equal(t, "abc#XYZ", parseData("${var_1}#XYZ", variablesMapping)) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -80,7 +80,7 @@ type ResponseObject struct {
|
|||||||
validationResults map[string]interface{}
|
validationResults map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ResponseObject) Validate(validators []TValidator) error {
|
func (v *ResponseObject) Validate(validators []TValidator, variablesMapping map[string]interface{}) error {
|
||||||
for _, validator := range validators {
|
for _, validator := range validators {
|
||||||
// parse check value
|
// parse check value
|
||||||
checkItem := validator.Check
|
checkItem := validator.Check
|
||||||
@@ -89,7 +89,7 @@ func (v *ResponseObject) Validate(validators []TValidator) error {
|
|||||||
assertMethod := validator.Assert
|
assertMethod := validator.Assert
|
||||||
assertFunc := assertFunctionsMap[assertMethod]
|
assertFunc := assertFunctionsMap[assertMethod]
|
||||||
// parse expected value
|
// parse expected value
|
||||||
expectValue := validator.Expect
|
expectValue := parseData(validator.Expect, variablesMapping)
|
||||||
// do assertion
|
// do assertion
|
||||||
result := assertFunc(v.t, expectValue, checkValue)
|
result := assertFunc(v.t, expectValue, checkValue)
|
||||||
log.Printf("assert %s %s %v => %v", checkItem, assertMethod, expectValue, result)
|
log.Printf("assert %s %s %v => %v", checkItem, assertMethod, expectValue, result)
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ func (r *Runner) runStepRequest(step *TStep) error {
|
|||||||
|
|
||||||
// validate response
|
// validate response
|
||||||
respObj := NewResponseObject(r.t, resp)
|
respObj := NewResponseObject(r.t, resp)
|
||||||
err = respObj.Validate(step.Validators)
|
err = respObj.Validate(step.Validators, step.Variables)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user