mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package httpboomer
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/imroc/req"
|
|
"github.com/jmespath/go-jmespath"
|
|
|
|
"github.com/httprunner/httpboomer/builtin"
|
|
)
|
|
|
|
func NewResponseObject(t *testing.T, resp *req.Resp) (*ResponseObject, error) {
|
|
// prepare response headers
|
|
headers := make(map[string]string)
|
|
for k, v := range resp.Response().Header {
|
|
if len(v) > 0 {
|
|
headers[k] = v[0]
|
|
}
|
|
}
|
|
|
|
// prepare response cookies
|
|
cookies := make(map[string]string)
|
|
for _, cookie := range resp.Response().Cookies() {
|
|
cookies[cookie.Name] = cookie.Value
|
|
}
|
|
|
|
// parse response body
|
|
var body interface{}
|
|
if err := json.Unmarshal(resp.Bytes(), &body); err != nil {
|
|
// response body is not json, use raw body
|
|
body = string(resp.Bytes())
|
|
}
|
|
|
|
respObjMeta := respObjMeta{
|
|
StatusCode: resp.Response().StatusCode,
|
|
Headers: headers,
|
|
Cookies: cookies,
|
|
Body: body,
|
|
}
|
|
|
|
// convert respObjMeta to interface{}
|
|
respObjMetaBytes, _ := json.Marshal(respObjMeta)
|
|
var data interface{}
|
|
if err := json.Unmarshal(respObjMetaBytes, &data); err != nil {
|
|
log.Printf("[NewResponseObject] convert respObjMeta to interface{} error: %v, respObjMeta: %v",
|
|
err, string(respObjMetaBytes))
|
|
return nil, err
|
|
}
|
|
|
|
return &ResponseObject{
|
|
t: t,
|
|
respObjMeta: data,
|
|
}, nil
|
|
}
|
|
|
|
type respObjMeta struct {
|
|
StatusCode int `json:"status_code"`
|
|
Headers map[string]string `json:"headers"`
|
|
Cookies map[string]string `json:"cookies"`
|
|
Body interface{} `json:"body"`
|
|
}
|
|
|
|
type ResponseObject struct {
|
|
t *testing.T
|
|
respObjMeta interface{}
|
|
validationResults map[string]interface{}
|
|
}
|
|
|
|
func (v *ResponseObject) Extract(extractors map[string]string) map[string]interface{} {
|
|
if extractors == nil {
|
|
return nil
|
|
}
|
|
|
|
extractMapping := make(map[string]interface{})
|
|
for key, value := range extractors {
|
|
extractedValue := v.searchJmespath(value)
|
|
log.Printf("[extract] %s => %v", value, extractedValue)
|
|
log.Printf("[setVariable] %s = %v", key, extractedValue)
|
|
extractMapping[key] = extractedValue
|
|
}
|
|
|
|
return extractMapping
|
|
}
|
|
|
|
func (v *ResponseObject) Validate(validators []TValidator, variablesMapping map[string]interface{}) (err error) {
|
|
for _, validator := range validators {
|
|
// parse check value
|
|
checkItem := validator.Check
|
|
var checkValue interface{}
|
|
if strings.Contains(checkItem, "$") {
|
|
// reference variable
|
|
checkValue, err = parseData(checkItem, variablesMapping)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
checkValue = v.searchJmespath(checkItem)
|
|
}
|
|
|
|
// get assert method
|
|
assertMethod := validator.Assert
|
|
assertFunc := builtin.Assertions[assertMethod]
|
|
|
|
// parse expected value
|
|
expectValue, err := parseData(validator.Expect, variablesMapping)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// do assertion
|
|
result := assertFunc(v.t, expectValue, checkValue)
|
|
log.Printf("[assert] %s <%s> %v => %v", checkItem, assertMethod, expectValue, result)
|
|
if !result {
|
|
v.t.Fail()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *ResponseObject) searchJmespath(expr string) interface{} {
|
|
checkValue, err := jmespath.Search(expr, v.respObjMeta)
|
|
if err != nil {
|
|
log.Printf("[searchJmespath] jmespath.Search error: %v", err)
|
|
return expr // jmespath not found, return the expression
|
|
}
|
|
return checkValue
|
|
}
|