mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-05 23:51:25 +08:00
refactor: replace http client with net/http
This commit is contained in:
@@ -7,7 +7,6 @@ require (
|
|||||||
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
|
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
|
||||||
github.com/debugtalk/boomer v1.6.0
|
github.com/debugtalk/boomer v1.6.0
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
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/jmespath/go-jmespath v0.4.0
|
||||||
github.com/maja42/goval v1.2.1
|
github.com/maja42/goval v1.2.1
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
|
|||||||
@@ -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/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-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/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 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
|||||||
+14
-7
@@ -2,19 +2,20 @@ package hrp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/imroc/req"
|
|
||||||
"github.com/jmespath/go-jmespath"
|
"github.com/jmespath/go-jmespath"
|
||||||
|
|
||||||
"github.com/httprunner/hrp/builtin"
|
"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
|
// prepare response headers
|
||||||
headers := make(map[string]string)
|
headers := make(map[string]string)
|
||||||
for k, v := range resp.Response().Header {
|
for k, v := range resp.Header {
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
headers[k] = v[0]
|
headers[k] = v[0]
|
||||||
}
|
}
|
||||||
@@ -22,19 +23,25 @@ func NewResponseObject(t *testing.T, resp *req.Resp) (*ResponseObject, error) {
|
|||||||
|
|
||||||
// prepare response cookies
|
// prepare response cookies
|
||||||
cookies := make(map[string]string)
|
cookies := make(map[string]string)
|
||||||
for _, cookie := range resp.Response().Cookies() {
|
for _, cookie := range resp.Cookies() {
|
||||||
cookies[cookie.Name] = cookie.Value
|
cookies[cookie.Name] = cookie.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read response body
|
||||||
|
respBodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// parse response body
|
// parse response body
|
||||||
var body interface{}
|
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
|
// response body is not json, use raw body
|
||||||
body = string(resp.Bytes())
|
body = string(respBodyBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
respObjMeta := respObjMeta{
|
respObjMeta := respObjMeta{
|
||||||
StatusCode: resp.Response().StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
Headers: headers,
|
Headers: headers,
|
||||||
Cookies: cookies,
|
Cookies: cookies,
|
||||||
Body: body,
|
Body: body,
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
package hrp
|
package hrp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/imroc/req"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,14 +23,14 @@ func NewRunner() *Runner {
|
|||||||
return &Runner{
|
return &Runner{
|
||||||
t: &testing.T{},
|
t: &testing.T{},
|
||||||
debug: false, // default to turn off debug
|
debug: false, // default to turn off debug
|
||||||
client: req.New(),
|
client: &http.Client{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
debug bool
|
debug bool
|
||||||
client *req.Req
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) WithTestingT(t *testing.T) *Runner {
|
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 {
|
func (r *Runner) SetProxyUrl(proxyUrl string) *Runner {
|
||||||
log.Info().Str("proxyUrl", proxyUrl).Msg("[init] SetProxyUrl")
|
log.Info().Str("proxyUrl", proxyUrl).Msg("[init] SetProxyUrl")
|
||||||
r.client.SetProxyUrl(proxyUrl)
|
// TODO
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +113,7 @@ func (r *Runner) runStep(step IStep, config *TConfig) (stepData *StepData, err e
|
|||||||
// TODO: override testcase config
|
// TODO: override testcase config
|
||||||
stepData, err = r.runStepTestCase(tc.step)
|
stepData, err = r.runStepTestCase(tc.step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("run referenced testcase step failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -114,6 +121,7 @@ func (r *Runner) runStep(step IStep, config *TConfig) (stepData *StepData, err e
|
|||||||
tStep := parseStep(step, config)
|
tStep := parseStep(step, config)
|
||||||
stepData, err = r.runStepRequest(tStep)
|
stepData, err = r.runStepRequest(tStep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("run request step failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,49 +140,110 @@ func (r *Runner) runStepRequest(step *TStep) (stepData *StepData, err error) {
|
|||||||
ResponseLength: 0,
|
ResponseLength: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare request args
|
rawUrl := step.Request.URL
|
||||||
var v []interface{}
|
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 {
|
if len(step.Request.Headers) > 0 {
|
||||||
headers, err := parseHeaders(step.Request.Headers, step.Variables)
|
headers, err := parseHeaders(step.Request.Headers, step.Variables)
|
||||||
if err != nil {
|
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 {
|
if len(step.Request.Params) > 0 {
|
||||||
params, err := parseData(step.Request.Params, step.Variables)
|
params, err := parseData(step.Request.Params, step.Variables)
|
||||||
if err != nil {
|
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 {
|
if queryParams != nil {
|
||||||
data, err := parseData(step.Request.Body, step.Variables)
|
// append params to url
|
||||||
if err != nil {
|
paramStr := queryParams.Encode()
|
||||||
return nil, err
|
if strings.IndexByte(rawUrl, '?') == -1 {
|
||||||
}
|
rawUrl = rawUrl + "?" + paramStr
|
||||||
switch data.(type) {
|
} else {
|
||||||
case map[string]interface{}: // post json
|
rawUrl = rawUrl + "&" + paramStr
|
||||||
v = append(v, req.BodyJSON(data))
|
|
||||||
default: // post raw data
|
|
||||||
v = append(v, data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare request cookies
|
||||||
for cookieName, cookieValue := range step.Request.Cookies {
|
for cookieName, cookieValue := range step.Request.Cookies {
|
||||||
v = append(v, &http.Cookie{
|
req.AddCookie(&http.Cookie{
|
||||||
Name: cookieName,
|
Name: cookieName,
|
||||||
Value: cookieValue,
|
Value: cookieValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// do request action
|
// prepare request body
|
||||||
req.Debug = r.debug
|
if step.Request.Body != nil {
|
||||||
resp, err := r.client.Do(string(step.Request.Method), step.Request.URL, v...)
|
data, err := parseData(step.Request.Body, step.Variables)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
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
|
// new response object
|
||||||
respObj, err := NewResponseObject(r.t, resp)
|
respObj, err := NewResponseObject(r.t, resp)
|
||||||
@@ -198,7 +267,7 @@ func (r *Runner) runStepRequest(step *TStep) (stepData *StepData, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stepData.Success = true
|
stepData.Success = true
|
||||||
stepData.ResponseLength = resp.Response().ContentLength
|
stepData.ResponseLength = resp.ContentLength
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,3 +310,14 @@ func (r *Runner) parseConfig(config *TConfig) error {
|
|||||||
func (r *Runner) GetSummary() *TestCaseSummary {
|
func (r *Runner) GetSummary() *TestCaseSummary {
|
||||||
return &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