提交 a24f8839 authored 作者: mooncake9527's avatar mooncake9527

update

上级 da9c0e3b
......@@ -14,58 +14,51 @@ import (
"strings"
"time"
"github.com/duke-git/lancet/v2/retry"
"gitlab.wanzhuangkj.com/tush/xpkg/gin/ctxUtils"
"gitlab.wanzhuangkj.com/tush/xpkg/logger"
"gitlab.wanzhuangkj.com/tush/xpkg/utils/xjson"
"gitlab.wanzhuangkj.com/tush/xpkg/xerrors/xerror"
"github.com/duke-git/lancet/v2/retry"
)
const defaultTimeout = 30 * time.Second
var (
contentMark = []byte(" ...... ")
)
// Request HTTP request
type Request struct {
customRequest func(req *http.Request, data *bytes.Buffer) // used to define HEADER, e.g. to add sign, etc.
url string
params map[string]interface{} // parameters after URL
body string // Body data
bodyJSON interface{} // JSON marshal body data
timeout time.Duration // Client timeout
retryCount uint
headers map[string]string
url string
method string
headers map[string]string
params map[string]interface{} // parameters after URL
reqBody []byte // Body data
reqBodyJSON interface{} // 传入对象,会自动json marshal
timeout time.Duration // Client timeout
retryCount uint
rspBody []byte
request *http.Request
response *Response
method string
err error
}
// Response HTTP response
type Response struct {
Body io.ReadCloser
//Body io.ReadCloser
StatusCode int
Status string // e.g. "200 OK"
Status string
Header http.Header
err error
}
// ----------------------------------- Request way 1 -----------------------------------
// New create a new Request
func New() *Request {
return &Request{}
return &Request{
response: &Response{},
}
}
// Reset set all fields to default value, use at pool
func (req *Request) Reset() {
req.params = nil
req.body = ""
req.bodyJSON = nil
req.reqBody = nil
req.reqBodyJSON = nil
req.timeout = 0
req.headers = nil
......@@ -106,11 +99,11 @@ func (req *Request) SetParam(k string, v interface{}) *Request {
func (req *Request) SetBody(body interface{}) *Request {
switch v := body.(type) {
case string:
req.body = v
req.reqBody = []byte(v)
case []byte:
req.body = string(v)
req.reqBody = v
default:
req.bodyJSON = body
req.reqBodyJSON = body
}
return req
}
......@@ -151,46 +144,44 @@ func (req *Request) SetHeaders(headers map[string]string) *Request {
return req
}
// CustomRequest customize request, e.g. add sign, set header, etc.
func (req *Request) CustomRequest(f func(req *http.Request, data *bytes.Buffer)) *Request {
req.customRequest = f
return req
}
// GET send a GET request
func (req *Request) GET(ctx context.Context) (*Response, error) {
func (req *Request) GET(ctx context.Context) *Request {
req.method = http.MethodGet
return req.pull(ctx)
req.pull(ctx)
return req
}
// DELETE send a DELETE request
func (req *Request) DELETE(ctx context.Context) (*Response, error) {
func (req *Request) DELETE(ctx context.Context) *Request {
req.method = http.MethodDelete
return req.pull(ctx)
req.pull(ctx)
return req
}
// POST send a POST request
func (req *Request) POST(ctx context.Context) (*Response, error) {
func (req *Request) POST(ctx context.Context) *Request {
req.method = http.MethodPost
return req.push(ctx)
req.push(ctx)
return req
}
// PUT send a PUT request
func (req *Request) PUT(ctx context.Context) (*Response, error) {
func (req *Request) PUT(ctx context.Context) *Request {
req.method = http.MethodPut
return req.push(ctx)
req.push(ctx)
return req
}
// PATCH send PATCH requests
func (req *Request) PATCH(ctx context.Context) (*Response, error) {
func (req *Request) PATCH(ctx context.Context) *Request {
req.method = http.MethodPatch
return req.push(ctx)
req.push(ctx)
return req
}
// Do a request
func (req *Request) Do(ctx context.Context, method string, data interface{}) (*Response, error) {
func (req *Request) Do(ctx context.Context, method string, data interface{}) *Request {
req.method = method
switch method {
case http.MethodGet, http.MethodDelete:
if data != nil {
......@@ -198,25 +189,22 @@ func (req *Request) Do(ctx context.Context, method string, data interface{}) (*R
req.SetParams(params)
} else {
req.err = errors.New("params is not a map[string]interface{}")
return nil, req.err
return req
}
}
return req.pull(ctx)
req.pull(ctx)
case http.MethodPost, http.MethodPut, http.MethodPatch:
if data != nil {
req.SetBody(data)
}
return req.push(ctx)
req.push(ctx)
default:
req.err = errors.New("unknow method " + method)
}
req.err = errors.New("unknow method " + method)
return nil, req.err
return req
}
func (req *Request) pull(ctx context.Context) (*Response, error) {
func (req *Request) pull(ctx context.Context) {
val := ""
if len(req.params) > 0 {
values := url.Values{}
......@@ -233,45 +221,32 @@ func (req *Request) pull(ctx context.Context) (*Response, error) {
req.url += "?" + val
}
}
var buf *bytes.Buffer
if req.customRequest != nil {
buf = bytes.NewBufferString(val)
}
return req.send(ctx, nil, buf)
req.send(ctx)
}
func (req *Request) push(ctx context.Context) (*Response, error) {
var buf *bytes.Buffer
if req.bodyJSON != nil {
body, err := json.Marshal(req.bodyJSON)
func (req *Request) push(ctx context.Context) {
if req.reqBodyJSON != nil {
body, err := json.Marshal(req.reqBodyJSON)
if err != nil {
req.err = err
return nil, req.err
return
}
buf = bytes.NewBuffer(body)
} else {
buf = bytes.NewBufferString(req.body)
req.reqBody = body
}
return req.send(ctx, buf, buf)
req.send(ctx)
}
func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer) (*Response, error) {
req.request, req.err = http.NewRequest(req.method, req.url, body)
func (req *Request) send(ctx context.Context) {
bodyBuf := bytes.NewBuffer(req.reqBody)
req.request, req.err = http.NewRequest(req.method, req.url, bodyBuf)
if req.err != nil {
return nil, req.err
return
}
if buf != nil {
if req.reqBody != nil {
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiReq(c, buf)
entity.SetCopyApiReq(c, bodyBuf)
}
}
if req.customRequest != nil {
req.customRequest(req.request, buf)
}
if req.headers != nil {
for k, v := range req.headers {
req.request.Header.Add(k, v)
......@@ -286,195 +261,104 @@ func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer)
logger.Any("method", req.method),
logger.Any("url", req.url),
logger.Any("header", req.request.Header),
logger.Any("body", buf.String()),
logger.Any("body", bodyBuf.String()),
ctxUtils.CtxTraceIDField(ctx))
client := http.Client{Timeout: req.timeout}
resp := &Response{
Header: make(http.Header),
}
ctx, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel()
var err error
if req.retryCount > 0 {
err = retry.Retry(func() error {
response, err := client.Do(req.request)
if err != nil {
logger.Info("[httpCli] fail", logger.Any("err", err), ctxUtils.CtxTraceIDField(ctx))
return xerror.Wrap(err, "client do")
}
if response != nil {
resp.Status = response.Status
resp.StatusCode = response.StatusCode
for k, v := range response.Header {
resp.Header[k] = append(resp.Header[k], v...)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return xerror.Wrap(err, "read response body")
}
bodyBuf := bytes.NewBuffer(body)
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiRsp(c, buf)
}
logger.Info("[httpCli] rsp",
logger.Any("header", resp.Header),
logger.Any("body", bodyBuf.String()),
ctxUtils.CtxTraceIDField(ctx))
if body != nil {
resp.Body = io.NopCloser(bodyBuf)
}
}
return nil
_ = retry.Retry(func() error {
req.pushDo(ctx)
return req.err
},
retry.RetryTimes(req.retryCount),
retry.RetryWithLinearBackoff(2*time.Second),
retry.RetryWithLinearBackoff(8*time.Second),
retry.Context(ctx),
)
} else {
response, e := client.Do(req.request)
if e != nil {
err = xerror.New(e.Error())
if response != nil {
resp.Status = response.Status
resp.StatusCode = response.StatusCode
for k, v := range response.Header {
resp.Header[k] = append(resp.Header[k], v...)
}
resp.err = err
}
return resp, err
}
if response != nil {
resp.Status = response.Status
resp.StatusCode = response.StatusCode
for k, v := range response.Header {
resp.Header[k] = append(resp.Header[k], v...)
}
defer response.Body.Close()
body, e := io.ReadAll(response.Body)
if e != nil {
err = xerror.New(e.Error())
}
bodyBuf := bytes.NewBuffer(body)
logger.Info("[httpCli] rsp",
logger.Any("header", resp.Header),
logger.Any("body", bodyBuf.String()),
ctxUtils.CtxTraceIDField(ctx))
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiRsp(c, bodyBuf)
}
if body != nil {
resp.Body = io.NopCloser(bodyBuf)
}
}
req.pushDo(ctx)
}
if err != nil {
logger.Error("[httpCli] fail", logger.Any("err", err), ctxUtils.CtxTraceIDField(ctx))
var rspHeader map[string][]string
var rspBodyStr string
if req.response != nil {
rspHeader = req.response.Header
if len(req.rspBody) > 0 {
rspBodyStr = bytes.NewBuffer(req.rspBody).String()
}
}
ctxUtils.SetApiCost(ctx, resp.Header)
req.response = resp
req.err = err
resp.err = err
return resp, resp.err
logger.Info("[httpCli] rsp",
logger.Any("method", req.method),
logger.Any("status", req.response.Status),
logger.Any("url", req.url),
logger.Any("header", rspHeader),
logger.Any("body", rspBodyStr),
ctxUtils.CtxTraceIDField(ctx))
}
func copyResponse(resp *Response, response *http.Response) {
if resp == nil || response == nil {
func (req *Request) pushDo(ctx context.Context) {
client := http.Client{Timeout: req.timeout}
ctx, cancel := context.WithTimeout(ctx, req.timeout)
defer cancel()
response, e := client.Do(req.request)
if e != nil {
req.err = e
return
}
resp.Status = response.Status
resp.StatusCode = response.StatusCode
for k, v := range response.Header {
resp.Header[k] = append(resp.Header[k], v...)
}
if response.Body != nil {
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
resp.err = xerror.Wrap(err, "read response body")
}
if len(body) > 0 {
resp.Body = io.NopCloser(bytes.NewBuffer(body))
if response != nil {
req.response.Status = response.Status
req.response.Header = response.Header
ctxUtils.SetApiCost(ctx, req.response.Header)
req.response.StatusCode = response.StatusCode
if response.Body != nil {
defer response.Body.Close()
req.rspBody, req.err = io.ReadAll(response.Body)
if req.err != nil {
return
}
if len(req.rspBody) > 0 {
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiRsp(c, bytes.NewBuffer(req.rspBody))
}
//req.response.Body = io.NopCloser(bytes.NewBuffer(req.rspBody))
}
}
}
}
// Response return response
func (req *Request) Response() (*Response, error) {
if req.err != nil {
return nil, req.err
}
return req.response, req.response.Error()
}
// ----------------------------------- Response -----------------------------------
// Error return err
func (resp *Response) Error() error {
return resp.err
func (req *Request) Err() error {
return req.err
}
// BodyString returns the body data of the HttpResponse
func (resp *Response) BodyString() (string, error) {
if resp.err != nil {
return "", resp.err
func (req *Request) BodyString() string {
if len(req.rspBody) == 0 {
return ""
}
body, err := resp.ReadBody()
return string(body), err
return string(req.rspBody)
}
// BodyString returns the body data of the HttpResponse
func (resp *Response) RspString() string {
ret := make(map[string]any)
ret["status"] = resp.Status
ret["statusCode"] = resp.StatusCode
ret["header"] = resp.Header
if resp.err != nil {
ret["err"] = resp.err.Error()
}
body, err := resp.ReadBody()
if err == nil {
ret["body"] = bytes.NewBuffer(body).String()
}
return xjson.ToJsonString(ret)
}
// ReadBody returns the body data of the HttpResponse
func (resp *Response) ReadBody() ([]byte, error) {
if resp.err != nil {
return []byte{}, resp.err
func (req *Request) ReadRspBody() ([]byte, error) {
if req.err != nil {
return []byte{}, req.err
}
if resp.Body == nil {
if req.rspBody == nil {
return []byte{}, errors.New("nil")
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return []byte{}, err
}
resp.Body.Close()
resp.Body = io.NopCloser(bytes.NewBuffer(body))
return body, nil
return req.rspBody, nil
}
// BindJSON parses the response's body as JSON
func (resp *Response) BindJSON(v interface{}) error {
if resp.err != nil {
return resp.err
func (req *Request) BindJSON(v interface{}) *Request {
if req.err != nil {
return req
}
body, err := resp.ReadBody()
if err != nil {
return err
if err := json.Unmarshal(req.rspBody, v); err != nil {
req.err = err
}
return json.Unmarshal(body, v)
return req
}
// ----------------------------------- Request way 2 -----------------------------------
......@@ -519,125 +403,127 @@ func WithTimeout(t time.Duration) Option {
}
}
// Get request, return custom json format
func Get(ctx context.Context, result interface{}, urlStr string, opts ...Option) error {
o := defaultOptions()
o.apply(opts...)
return gDo(ctx, "GET", result, urlStr, o.params, o.headers, o.timeout)
}
// Delete request, return custom json format
func Delete(ctx context.Context, result interface{}, urlStr string, opts ...Option) error {
o := defaultOptions()
o.apply(opts...)
return gDo(ctx, "DELETE", result, urlStr, o.params, o.headers, o.timeout)
}
// Post request, return custom json format
func Post(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
o := defaultOptions()
o.apply(opts...)
return do(ctx, "POST", result, urlStr, body, o.params, o.headers, o.timeout)
}
// Put request, return custom json format
func Put(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
o := defaultOptions()
o.apply(opts...)
return do(ctx, "PUT", result, urlStr, body, o.params, o.headers, o.timeout)
}
// Patch request, return custom json format
func Patch(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
o := defaultOptions()
o.apply(opts...)
return do(ctx, "PATCH", result, urlStr, body, o.params, o.headers, o.timeout)
}
var requestErr = func(err error) error { return fmt.Errorf("request error, err=%v", err) }
var jsonParseErr = func(err error) error { return fmt.Errorf("json parsing error, err=%v", err) }
var notOKErr = func(resp *Response) error {
body, err := resp.ReadBody()
if err != nil {
return err
}
if len(body) > 500 {
body = append(body[:500], []byte(" ......")...)
}
return fmt.Errorf("statusCode=%d, body=%s", resp.StatusCode, body)
}
func do(ctx context.Context, method string, result interface{}, urlStr string, body interface{}, params KV, headers map[string]string, timeout time.Duration) error {
if result == nil {
return fmt.Errorf("'result' can not be nil")
}
req := &Request{}
req.SetURL(urlStr)
req.SetContentType("application/json")
req.SetParams(params)
req.SetHeaders(headers)
req.SetBody(body)
req.SetTimeout(timeout)
var resp *Response
var err error
switch method {
case "POST":
resp, err = req.POST(ctx)
case "PUT":
resp, err = req.PUT(ctx)
case "PATCH":
resp, err = req.PATCH(ctx)
}
if err != nil {
return requestErr(err)
}
defer resp.Body.Close() //nolint
if resp.StatusCode != 200 {
return notOKErr(resp)
}
err = resp.BindJSON(result)
if err != nil {
return jsonParseErr(err)
}
return nil
}
func gDo(ctx context.Context, method string, result interface{}, urlStr string, params KV, headers map[string]string, timeout time.Duration) error {
req := &Request{}
req.SetURL(urlStr)
req.SetParams(params)
req.SetHeaders(headers)
req.SetTimeout(timeout)
var resp *Response
var err error
switch method {
case "GET":
resp, err = req.GET(ctx)
case "DELETE":
resp, err = req.DELETE(ctx)
}
if err != nil {
return requestErr(err)
}
defer resp.Body.Close() //nolint
if resp.StatusCode != 200 {
return notOKErr(resp)
}
err = resp.BindJSON(result)
if err != nil {
return jsonParseErr(err)
}
return nil
}
//
//// Get request, return custom json format
//func Get(ctx context.Context, result interface{}, urlStr string, opts ...Option) error {
// o := defaultOptions()
// o.apply(opts...)
// return gDo(ctx, "GET", result, urlStr, o.params, o.headers, o.timeout)
//}
//
//// Delete request, return custom json format
//func Delete(ctx context.Context, result interface{}, urlStr string, opts ...Option) error {
// o := defaultOptions()
// o.apply(opts...)
// return gDo(ctx, "DELETE", result, urlStr, o.params, o.headers, o.timeout)
//}
//
//// Post request, return custom json format
//func Post(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
// o := defaultOptions()
// o.apply(opts...)
// return do(ctx, "POST", result, urlStr, body, o.params, o.headers, o.timeout)
//}
//
//// Put request, return custom json format
//func Put(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
// o := defaultOptions()
// o.apply(opts...)
// return do(ctx, "PUT", result, urlStr, body, o.params, o.headers, o.timeout)
//}
//
//// Patch request, return custom json format
//func Patch(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
// o := defaultOptions()
// o.apply(opts...)
// return do(ctx, "PATCH", result, urlStr, body, o.params, o.headers, o.timeout)
//}
//
//var requestErr = func(err error) error { return fmt.Errorf("request error, err=%v", err) }
//var jsonParseErr = func(err error) error { return fmt.Errorf("json parsing error, err=%v", err) }
//var notOKErr = func(resp *Response) error {
// body, err := resp.ReadBody()
// if err != nil {
// return err
// }
// if len(body) > 500 {
// body = append(body[:500], []byte(" ......")...)
// }
// return fmt.Errorf("statusCode=%d, body=%s", resp.StatusCode, body)
//}
//
//func do(ctx context.Context, method string, result interface{}, urlStr string, body interface{}, params KV, headers map[string]string, timeout time.Duration) error {
// if result == nil {
// return fmt.Errorf("'result' can not be nil")
// }
//
// req := &Request{}
// req.SetURL(urlStr)
// req.SetContentType("application/json")
// req.SetParams(params)
// req.SetHeaders(headers)
// req.SetBody(body)
// req.SetTimeout(timeout)
//
// var resp *Response
// var err error
// switch method {
// case "POST":
// resp, err = req.POST(ctx)
// case "PUT":
// resp, err = req.PUT(ctx)
// case "PATCH":
// resp, err = req.PATCH(ctx)
// }
// if err != nil {
// return requestErr(err)
// }
// defer resp.Body.Close() //nolint
//
// if resp.StatusCode != 200 {
// return notOKErr(resp)
// }
//
// err = resp.BindJSON(result)
// if err != nil {
// return jsonParseErr(err)
// }
//
// return nil
//}
//
//func gDo(ctx context.Context, method string, result interface{}, urlStr string, params KV, headers map[string]string, timeout time.Duration) error {
// req := &Request{}
// req.SetURL(urlStr)
// req.SetParams(params)
// req.SetHeaders(headers)
// req.SetTimeout(timeout)
//
// var resp *Response
// var err error
// switch method {
// case "GET":
// resp, err = req.GET(ctx)
// case "DELETE":
// resp, err = req.DELETE(ctx)
// }
// if err != nil {
// return requestErr(err)
// }
// defer resp.Body.Close() //nolint
//
// if resp.StatusCode != 200 {
// return notOKErr(resp)
// }
//
// err = resp.BindJSON(result)
// if err != nil {
// return jsonParseErr(err)
// }
//
// return nil
//}
// StdResult standard return data
type StdResult struct {
......
package httpcli
import (
"bytes"
"context"
"errors"
"fmt"
"net/http"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"gitlab.wanzhuangkj.com/tush/xpkg/utils"
)
type myBody struct {
Name string `json:"name"`
Email string `json:"email"`
}
func runGoHTTPServer() string {
serverAddr, requestAddr := utils.GetLocalHTTPAddrPairs()
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
oKFun := func(c *gin.Context) {
uid := c.Query("uid")
fmt.Printf("request parameters: uid=%s\n", uid)
c.JSON(200, StdResult{
Code: 0,
Msg: "ok",
Data: fmt.Sprintf("uid=%v", uid),
})
}
errFun := func(c *gin.Context) {
uid := c.Query("uid")
fmt.Printf("request parameters: uid=%s\n", uid)
c.JSON(401, StdResult{
Code: 401,
Msg: "authorization failure",
Data: fmt.Sprintf("uid=%v", uid),
})
}
oKPFun := func(c *gin.Context) {
var body myBody
c.BindJSON(&body)
fmt.Println("body data:", body)
c.JSON(200, StdResult{
Code: 0,
Msg: "ok",
Data: body,
})
}
errPFun := func(c *gin.Context) {
var body myBody
c.BindJSON(&body)
fmt.Println("body data:", body)
c.JSON(401, StdResult{
Code: 401,
Msg: "authorization failure",
Data: nil,
})
}
r.GET("/get", oKFun)
r.GET("/get_err", errFun)
r.DELETE("/delete", oKFun)
r.DELETE("/delete_err", errFun)
r.POST("/post", oKPFun)
r.POST("/post_err", errPFun)
r.PUT("/put", oKPFun)
r.PUT("/put_err", errPFun)
r.PATCH("/patch", oKPFun)
r.PATCH("/patch_err", errPFun)
go func() {
err := r.Run(serverAddr)
if err != nil {
panic(err)
}
}()
time.Sleep(time.Millisecond * 200)
return requestAddr
}
// ------------------------------------------------------------------------------------------
func TestGetStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
func TestRequest_SetBody(t *testing.T) {
ctx := context.Background()
req := New()
req.SetURL(requestAddr + "/get")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetParams(KV{
"name": "foo",
})
resp, err := req.GET(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestDeleteStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/delete")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetParams(KV{
"uid": 123,
})
resp, err := req.DELETE(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestPostStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/post")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetBody(&myBody{
Name: "foo",
Email: "bar@gmail.com",
})
resp, err := req.POST(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestPutStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/put")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetBody(&myBody{
Name: "foo",
Email: "bar@gmail.com",
})
resp, err := req.PUT(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestPatchStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/patch")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetBody(&myBody{
Name: "foo",
Email: "bar@gmail.com",
})
resp, err := req.PATCH(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
// ------------------------------------------------------------------------------------------
func TestGet(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
params map[string]interface{}
headers map[string]string
}
tests := []struct {
name string
args args
wantErr bool
wantResult *StdResult
}{
{
name: "get success",
args: args{
result: &StdResult{},
url: requestAddr + "/get",
params: KV{"uid": 123},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantErr: false,
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: "uid=123",
},
},
{
name: "get err",
args: args{
result: &StdResult{},
url: requestAddr + "/get_err",
params: KV{"uid": 123},
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
{
name: "get not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Get(context.Background(), tt.args.result, tt.args.url, WithParams(tt.args.params), WithHeaders(tt.args.headers))
if (err != nil) != tt.wantErr {
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestDelete(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
params KV
headers map[string]string
}
tests := []struct {
name string
args args
wantErr bool
wantResult *StdResult
}{
{
name: "delete success",
args: args{
result: &StdResult{},
url: requestAddr + "/delete",
params: KV{"uid": 123},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantErr: false,
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: "uid=123",
},
},
{
name: "delete err",
args: args{
result: &StdResult{},
url: requestAddr + "/delete_err",
params: KV{"uid": 123},
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
{
name: "delete not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Delete(context.Background(), tt.args.result, tt.args.url, WithParams(tt.args.params), WithHeaders(tt.args.headers))
if (err != nil) != tt.wantErr {
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestPost(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
body interface{}
headers map[string]string
timeout time.Duration
}
tests := []struct {
name string
args args
wantResult *StdResult
wantErr bool
}{
{
name: "post success",
args: args{
result: &StdResult{},
url: requestAddr + "/post",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
timeout: time.Second,
},
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: nil,
},
wantErr: false,
},
{
name: "post error",
args: args{
result: &StdResult{},
url: requestAddr + "/post_err",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
{
name: "post not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
ret := make(map[string]any)
if err := req.SetURL("http://baidu.com").
SetParams(KV{"a": "b"}).
GET(ctx).
BindJSON(&ret).
Err(); err != nil {
t.Error(err.Error())
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Post(context.Background(), tt.args.result, tt.args.url, tt.args.body, WithHeaders(tt.args.headers), WithTimeout(tt.args.timeout))
if (err != nil) != tt.wantErr {
t.Errorf("Post() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestPut(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
body interface{}
headers map[string]string
}
tests := []struct {
name string
args args
wantResult *StdResult
wantErr bool
}{
{
name: "put success",
args: args{
result: &StdResult{},
url: requestAddr + "/put",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: nil,
},
wantErr: false,
},
{
name: "put error",
args: args{
result: &StdResult{},
url: requestAddr + "/put_err",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
{
name: "post not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Put(context.Background(), tt.args.result, tt.args.url, tt.args.body, WithHeaders(tt.args.headers)); (err != nil) != tt.wantErr {
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestPatch(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
body interface{}
headers map[string]string
}
tests := []struct {
name string
args args
wantResult *StdResult
wantErr bool
}{
{
name: "patch success",
args: args{
result: &StdResult{},
url: requestAddr + "/patch",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: nil,
},
wantErr: false,
},
{
name: "patch error",
args: args{
result: &StdResult{},
url: requestAddr + "/patch_err",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
{
name: "post not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Patch(context.Background(), tt.args.result, tt.args.url, tt.args.body, WithHeaders(tt.args.headers)); (err != nil) != tt.wantErr {
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestRequest_Reset(t *testing.T) {
req := &Request{
method: http.MethodGet,
}
req.Reset()
assert.Equal(t, "", req.method)
}
func TestRequest_Do(t *testing.T) {
req := &Request{
method: http.MethodGet,
url: "http://",
}
_, err := req.Do(context.Background(), http.MethodOptions, "")
assert.Error(t, err)
_, err = req.Do(context.Background(), http.MethodGet, map[string]interface{}{"foo": "bar"})
assert.Error(t, err)
_, err = req.Do(context.Background(), http.MethodDelete, "foo=bar")
assert.Error(t, err)
_, err = req.Do(context.Background(), http.MethodPost, &myBody{
Name: "foo",
Email: "bar@gmail.com",
})
assert.Error(t, err)
_, err = req.Response()
assert.Error(t, err)
err = requestErr(err)
assert.Error(t, err)
err = jsonParseErr(err)
assert.Error(t, err)
}
func TestResponse_BodyString(t *testing.T) {
resp := &Response{
Body: nil,
err: nil,
}
_, err := resp.BodyString()
assert.Error(t, err)
resp.err = errors.New("error test")
_, err = resp.BodyString()
assert.Error(t, err)
err = resp.Error()
assert.Error(t, err)
}
func TestError(t *testing.T) {
req := New()
req.SetParam("foo", "bar")
req.SetParam("foo3", make(chan string))
req.SetParams(map[string]interface{}{"foo2": "bar2"})
req.SetBody("foo")
req.SetTimeout(time.Second * 10)
req.CustomRequest(func(req *http.Request, data *bytes.Buffer) {
fmt.Println("customRequest")
})
req.SetURL("http://127.0.0.1:0")
resp, err := req.pull(context.Background())
assert.Error(t, err)
_, err = resp.ReadBody()
assert.Error(t, err)
req.method = http.MethodPost
resp, err = req.push(context.Background())
assert.Error(t, err)
_, err = resp.ReadBody()
assert.Error(t, err)
err = resp.BindJSON(nil)
assert.Error(t, err)
err = notOKErr(resp)
assert.Error(t, err)
err = do(context.Background(), http.MethodPost, nil, "", nil, nil, nil, 0)
assert.Error(t, err)
err = do(context.Background(), http.MethodPost, &StdResult{}, "http://127.0.0.1:0", nil, KV{"foo": "bar"}, nil, 0)
assert.Error(t, err)
err = gDo(context.Background(), http.MethodGet, nil, "http://127.0.0.1:0", nil, nil, 0)
assert.Error(t, err)
}
......@@ -17,10 +17,15 @@ type Request struct {
request *http.Request
response *http.Response
err error
}
func New() *Request {
return &Request{}
return &Request{
request: &http.Request{},
headers: map[string]string{},
params: map[string]interface{}{},
}
}
func (req *Request) SetURL(path string) *Request {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论