mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +08:00
refactor: replace http client with net/http
This commit is contained in:
1
go.mod
1
go.mod
@@ -7,7 +7,6 @@ require (
|
||||
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
|
||||
github.com/debugtalk/boomer v1.6.0
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/imroc/req v0.3.0
|
||||
github.com/jmespath/go-jmespath v0.4.0
|
||||
github.com/maja42/goval v1.2.1
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -170,8 +170,6 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U=
|
||||
github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
|
||||
21
response.go
21
response.go
@@ -2,19 +2,20 @@ package hrp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/imroc/req"
|
||||
"github.com/jmespath/go-jmespath"
|
||||
|
||||
"github.com/httprunner/hrp/builtin"
|
||||
)
|
||||
|
||||
func NewResponseObject(t *testing.T, resp *req.Resp) (*ResponseObject, error) {
|
||||
func NewResponseObject(t *testing.T, resp *http.Response) (*ResponseObject, error) {
|
||||
// prepare response headers
|
||||
headers := make(map[string]string)
|
||||
for k, v := range resp.Response().Header {
|
||||
for k, v := range resp.Header {
|
||||
if len(v) > 0 {
|
||||
headers[k] = v[0]
|
||||
}
|
||||
@@ -22,19 +23,25 @@ func NewResponseObject(t *testing.T, resp *req.Resp) (*ResponseObject, error) {
|
||||
|
||||
// prepare response cookies
|
||||
cookies := make(map[string]string)
|
||||
for _, cookie := range resp.Response().Cookies() {
|
||||
for _, cookie := range resp.Cookies() {
|
||||
cookies[cookie.Name] = cookie.Value
|
||||
}
|
||||
|
||||
// read response body
|
||||
respBodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse response body
|
||||
var body interface{}
|
||||
if err := json.Unmarshal(resp.Bytes(), &body); err != nil {
|
||||
if err := json.Unmarshal(respBodyBytes, &body); err != nil {
|
||||
// response body is not json, use raw body
|
||||
body = string(resp.Bytes())
|
||||
body = string(respBodyBytes)
|
||||
}
|
||||
|
||||
respObjMeta := respObjMeta{
|
||||
StatusCode: resp.Response().StatusCode,
|
||||
StatusCode: resp.StatusCode,
|
||||
Headers: headers,
|
||||
Cookies: cookies,
|
||||
Body: body,
|
||||
|
||||
136
runner.go
136
runner.go
@@ -1,10 +1,16 @@
|
||||
package hrp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/imroc/req"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -17,14 +23,14 @@ func NewRunner() *Runner {
|
||||
return &Runner{
|
||||
t: &testing.T{},
|
||||
debug: false, // default to turn off debug
|
||||
client: req.New(),
|
||||
client: &http.Client{},
|
||||
}
|
||||
}
|
||||
|
||||
type Runner struct {
|
||||
t *testing.T
|
||||
debug bool
|
||||
client *req.Req
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (r *Runner) WithTestingT(t *testing.T) *Runner {
|
||||
@@ -41,7 +47,7 @@ func (r *Runner) SetDebug(debug bool) *Runner {
|
||||
|
||||
func (r *Runner) SetProxyUrl(proxyUrl string) *Runner {
|
||||
log.Info().Str("proxyUrl", proxyUrl).Msg("[init] SetProxyUrl")
|
||||
r.client.SetProxyUrl(proxyUrl)
|
||||
// TODO
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -107,6 +113,7 @@ func (r *Runner) runStep(step IStep, config *TConfig) (stepData *StepData, err e
|
||||
// TODO: override testcase config
|
||||
stepData, err = r.runStepTestCase(tc.step)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("run referenced testcase step failed")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -114,6 +121,7 @@ func (r *Runner) runStep(step IStep, config *TConfig) (stepData *StepData, err e
|
||||
tStep := parseStep(step, config)
|
||||
stepData, err = r.runStepRequest(tStep)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("run request step failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -132,49 +140,110 @@ func (r *Runner) runStepRequest(step *TStep) (stepData *StepData, err error) {
|
||||
ResponseLength: 0,
|
||||
}
|
||||
|
||||
// prepare request args
|
||||
var v []interface{}
|
||||
rawUrl := step.Request.URL
|
||||
method := step.Request.Method
|
||||
req := &http.Request{
|
||||
Method: string(method),
|
||||
Header: make(http.Header),
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
}
|
||||
|
||||
// prepare request headers
|
||||
if len(step.Request.Headers) > 0 {
|
||||
headers, err := parseHeaders(step.Request.Headers, step.Variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "parse headers failed")
|
||||
}
|
||||
for key, value := range headers {
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
v = append(v, req.Header(headers))
|
||||
}
|
||||
if length := req.Header.Get("Content-Length"); length != "" {
|
||||
if l, err := strconv.ParseInt(length, 10, 64); err == nil {
|
||||
req.ContentLength = l
|
||||
}
|
||||
}
|
||||
if host := req.Header.Get("Host"); host != "" {
|
||||
req.Host = host
|
||||
}
|
||||
|
||||
// prepare request params
|
||||
var queryParams url.Values
|
||||
if len(step.Request.Params) > 0 {
|
||||
params, err := parseData(step.Request.Params, step.Variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "parse data failed")
|
||||
}
|
||||
parsedParams := params.(map[string]interface{})
|
||||
if len(parsedParams) > 0 {
|
||||
queryParams = make(url.Values)
|
||||
for k, v := range parsedParams {
|
||||
queryParams.Add(k, fmt.Sprint(v))
|
||||
}
|
||||
}
|
||||
v = append(v, req.Param(params.(map[string]interface{})))
|
||||
}
|
||||
if step.Request.Body != nil {
|
||||
data, err := parseData(step.Request.Body, step.Variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch data.(type) {
|
||||
case map[string]interface{}: // post json
|
||||
v = append(v, req.BodyJSON(data))
|
||||
default: // post raw data
|
||||
v = append(v, data)
|
||||
if queryParams != nil {
|
||||
// append params to url
|
||||
paramStr := queryParams.Encode()
|
||||
if strings.IndexByte(rawUrl, '?') == -1 {
|
||||
rawUrl = rawUrl + "?" + paramStr
|
||||
} else {
|
||||
rawUrl = rawUrl + "&" + paramStr
|
||||
}
|
||||
}
|
||||
|
||||
// prepare request cookies
|
||||
for cookieName, cookieValue := range step.Request.Cookies {
|
||||
v = append(v, &http.Cookie{
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: cookieName,
|
||||
Value: cookieValue,
|
||||
})
|
||||
}
|
||||
|
||||
// do request action
|
||||
req.Debug = r.debug
|
||||
resp, err := r.client.Do(string(step.Request.Method), step.Request.URL, v...)
|
||||
if err != nil {
|
||||
return
|
||||
// prepare request body
|
||||
if step.Request.Body != nil {
|
||||
data, err := parseData(step.Request.Body, step.Variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var dataBytes []byte
|
||||
switch vv := data.(type) {
|
||||
case map[string]interface{}: // post json
|
||||
dataBytes, err = json.Marshal(vv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
setContentType(req, "application/json; charset=UTF-8")
|
||||
case string:
|
||||
dataBytes = []byte(vv)
|
||||
case []byte:
|
||||
dataBytes = vv
|
||||
case bytes.Buffer:
|
||||
dataBytes = vv.Bytes()
|
||||
default: // unexpected body type
|
||||
return nil, errors.New("unexpected request body type")
|
||||
}
|
||||
setBodyBytes(req, dataBytes)
|
||||
}
|
||||
defer resp.Response().Body.Close()
|
||||
|
||||
// prepare url
|
||||
u, err := url.Parse(rawUrl)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "parse url failed")
|
||||
}
|
||||
req.URL = u
|
||||
|
||||
// do request action
|
||||
// req.Debug = r.debug
|
||||
// resp, err := r.client.Do(string(step.Request.Method), step.Request.URL, v...)
|
||||
|
||||
resp, err := r.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "do request failed")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// new response object
|
||||
respObj, err := NewResponseObject(r.t, resp)
|
||||
@@ -198,7 +267,7 @@ func (r *Runner) runStepRequest(step *TStep) (stepData *StepData, err error) {
|
||||
}
|
||||
|
||||
stepData.Success = true
|
||||
stepData.ResponseLength = resp.Response().ContentLength
|
||||
stepData.ResponseLength = resp.ContentLength
|
||||
return
|
||||
}
|
||||
|
||||
@@ -241,3 +310,14 @@ func (r *Runner) parseConfig(config *TConfig) error {
|
||||
func (r *Runner) GetSummary() *TestCaseSummary {
|
||||
return &TestCaseSummary{}
|
||||
}
|
||||
|
||||
func setBodyBytes(req *http.Request, data []byte) {
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(data))
|
||||
req.ContentLength = int64(len(data))
|
||||
}
|
||||
|
||||
func setContentType(req *http.Request, contentType string) {
|
||||
if req.Header.Get("Content-Type") == "" {
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user