diff --git a/response.go b/response.go index bb30b045..2861b119 100644 --- a/response.go +++ b/response.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "regexp" "strings" "testing" @@ -85,6 +86,18 @@ type responseObject struct { validationResults []*validationResult } +const textExtractorSubRegexp string = `(.*)` + +func (v *responseObject) extractField(value string) interface{} { + var result interface{} + if strings.Contains(value, textExtractorSubRegexp) { + result = v.searchRegexp(value) + } else { + result = v.searchJmespath(value) + } + return result +} + func (v *responseObject) Extract(extractors map[string]string) map[string]interface{} { if extractors == nil { return nil @@ -92,7 +105,7 @@ func (v *responseObject) Extract(extractors map[string]string) map[string]interf extractMapping := make(map[string]interface{}) for key, value := range extractors { - extractedValue := v.searchJmespath(value) + extractedValue := v.extractField(value) 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 @@ -113,7 +126,8 @@ func (v *responseObject) Validate(validators []Validator, variablesMapping map[s return err } } else { - checkValue = v.searchJmespath(checkItem) + // regExp or jmesPath + checkValue = v.extractField(checkItem) } // get assert method @@ -179,3 +193,27 @@ func (v *responseObject) searchJmespath(expr string) interface{} { } return checkValue } + +func (v *responseObject) searchRegexp(expr string) interface{} { + respMap, ok := v.respObjMeta.(map[string]interface{}) + if !ok { + log.Error().Interface("resp", v.respObjMeta).Msg("convert respObjMeta to map failed") + return expr + } + bodyStr, ok := respMap["body"].(string) + if !ok { + log.Error().Interface("resp", respMap).Msg("convert body to string failed") + return expr + } + regexpCompile, err := regexp.Compile(expr) + if err != nil { + log.Error().Str("expr", expr).Err(err).Msg("compile expr failed") + return expr + } + match := regexpCompile.FindStringSubmatch(bodyStr) + if match != nil || len(match) > 1 { + return match[1] //return first matched result in parentheses + } + log.Error().Str("expr", expr).Msg("search regexp failed") + return expr +} diff --git a/response_test.go b/response_test.go new file mode 100644 index 00000000..cfd3143d --- /dev/null +++ b/response_test.go @@ -0,0 +1,35 @@ +package hrp + +import ( + "io" + "net/http" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSearchRegexp(t *testing.T) { + testText := `hrp aims to be a one-stop solution for HTTP(S) testing, covering API testing, load testing and digital experience monitoring (DEM).` + testData := []struct { + raw string + expected string + }{ + {"covering (.*) testing,", "API"}, + {" (.*) to", "aims"}, + {"^(.*) aims", "hrp"}, + {".* (.*?)$", "(DEM)."}, + } + // new response object + resp := http.Response{} + resp.Body = io.NopCloser(strings.NewReader(testText)) + respObj, err := newResponseObject(t, newParser(), &resp) + if err != nil { + t.Fail() + } + for _, data := range testData { + if !assert.Equal(t, data.expected, respObj.searchRegexp(data.raw)) { + t.Fail() + } + } +}