refactor: replace http client with net/http

This commit is contained in:
debugtalk
2021-10-29 17:55:50 +08:00
parent 9e76d62a7c
commit a517203a19
4 changed files with 122 additions and 38 deletions

1
go.mod
View File

@@ -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
View File

@@ -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=

View File

@@ -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
View File

@@ -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)
}
}