Solution 3

This commit is contained in:
holooooo 2021-05-16 14:18:34 +08:00
parent 84946743d9
commit 599e03b0cd
4 changed files with 123 additions and 256 deletions

View File

@ -25,6 +25,27 @@ import (
"github.com/stretchr/testify/assert"
)
type respCarrier struct {
Resp *http.Response
bytes []byte
}
func (r *respCarrier) SetHttpResponse(resp *http.Response) {
r.Resp = resp
}
func (r *respCarrier) SetBytes(bytes []byte) {
r.bytes = bytes
}
func (r *respCarrier) Bytes() []byte {
return r.bytes
}
func (r *respCarrier) String() string {
return string(r.bytes)
}
func TestOption_WithEnableCookie(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/",
WithEnableCookie(true))
@ -33,20 +54,20 @@ func TestOption_WithEnableCookie(t *testing.T) {
}
v := "smallfish"
var str *string
err = client.Get(&str, "/cookies/set?k1="+v)
var resp = &respCarrier{}
err = client.Get(resp, "/cookies/set?k1="+v)
if err != nil {
t.Fatal(err)
}
t.Log(*str)
t.Log(resp.String())
err = client.Get(&str, "/cookies")
err = client.Get(resp, "/cookies")
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, v)
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in cookie")
}
@ -60,14 +81,14 @@ func TestOption_WithUserAgent(t *testing.T) {
t.Fatal(err)
}
var str *string
err = client.Get(&str, "/headers")
var resp = &respCarrier{}
err = client.Get(resp, "/headers")
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, v)
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in user-agent")
}
@ -108,14 +129,14 @@ func TestOption_WithHTTPSetting(t *testing.T) {
t.Fatal(err)
}
var str *string
err = client.Get(&str, "/get")
var resp = &respCarrier{}
err = client.Get(resp, "/get")
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, v)
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in user-agent")
}
@ -128,14 +149,14 @@ func TestOption_WithHeader(t *testing.T) {
}
client.CommonOpts = append(client.CommonOpts, WithHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"))
var str *string
err = client.Get(&str, "/headers")
var resp = &respCarrier{}
err = client.Get(resp, "/headers")
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, "Mozilla/5.0")
n := strings.Index(resp.String(), "Mozilla/5.0")
if n == -1 {
t.Fatal("Mozilla/5.0 not found in user-agent")
}
@ -151,14 +172,14 @@ func TestOption_WithTokenFactory(t *testing.T) {
return "testauth"
}))
var str *string
err = client.Get(&str, "/headers")
var resp = &respCarrier{}
err = client.Get(resp, "/headers")
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, "testauth")
n := strings.Index(resp.String(), "testauth")
if n == -1 {
t.Fatal("Auth is not set in request")
}
@ -170,16 +191,16 @@ func TestOption_WithBasicAuth(t *testing.T) {
t.Fatal(err)
}
var str *string
err = client.Get(&str, "/basic-auth/user/passwd",
var resp = &respCarrier{}
err = client.Get(resp, "/basic-auth/user/passwd",
WithBasicAuth(func() (string, string) {
return "user", "passwd"
}))
if err != nil {
t.Fatal(err)
}
t.Log(str)
n := strings.Index(*str, "authenticated")
t.Log(resp.String())
n := strings.Index(resp.String(), "authenticated")
if n == -1 {
t.Fatal("authenticated not found in response")
}
@ -192,14 +213,14 @@ func TestOption_WithContentType(t *testing.T) {
}
v := "application/json"
var str *string
err = client.Get(&str, "/headers", WithContentType(v))
var resp = &respCarrier{}
err = client.Get(resp, "/headers", WithContentType(v))
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, v)
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in header")
}
@ -212,14 +233,14 @@ func TestOption_WithParam(t *testing.T) {
}
v := "smallfish"
var str *string
err = client.Get(&str, "/get", WithParam("username", v))
var resp = &respCarrier{}
err = client.Get(resp, "/get", WithParam("username", v))
if err != nil {
t.Fatal(err)
}
t.Log(str)
t.Log(resp.String())
n := strings.Index(*str, v)
n := strings.Index(resp.String(), v)
if n == -1 {
t.Fatal(v + " not found in header")
}
@ -238,11 +259,8 @@ func TestOption_WithRetry(t *testing.T) {
retryDelay := 1400 * time.Millisecond
startTime := time.Now().UnixNano() / int64(time.Millisecond)
err = client.Get(nil, "", WithRetry(retryAmount, retryDelay))
_ = client.Get(nil, "", WithRetry(retryAmount, retryDelay))
if err != nil {
t.Fatal(err)
}
endTime := time.Now().UnixNano() / int64(time.Millisecond)
elapsedTime := endTime - startTime
delayedTime := int64(retryAmount) * retryDelay.Milliseconds()

View File

@ -25,15 +25,17 @@ type Client struct {
CommonOpts []BeegoHttpRequestOption
Setting BeegoHTTPSettings
pointer responsePointer
}
type responsePointer struct {
response **http.Response
statusCode **int
header **http.Header
headerValues map[string]**string //用户传一个key然后将key存在map的key里header的value存在value里
contentLength **int64
// If value implement this interface. http.response will saved by SetHttpResponse
type HttpResponseCarrier interface {
SetHttpResponse(resp *http.Response)
}
// If value implement this interface. bytes of http.response will saved by SetHttpResponse
type ResponseBytesCarrier interface {
// Cause of when user get http.response, the body stream is closed. So need to pass bytes by
SetBytes(bytes []byte)
}
// NewClient return a new http client
@ -50,71 +52,6 @@ func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, err
return res, nil
}
// Response will set response to the pointer
func (c *Client) Response(resp **http.Response) *Client {
newC := *c
newC.pointer.response = resp
return &newC
}
// StatusCode will set response StatusCode to the pointer
func (c *Client) StatusCode(code **int) *Client {
newC := *c
newC.pointer.statusCode = code
return &newC
}
// Headers will set response Headers to the pointer
func (c *Client) Headers(headers **http.Header) *Client {
newC := *c
newC.pointer.header = headers
return &newC
}
// HeaderValue will set response HeaderValue to the pointer
func (c *Client) HeaderValue(key string, value **string) *Client {
newC := *c
if newC.pointer.headerValues == nil {
newC.pointer.headerValues = make(map[string]**string)
}
newC.pointer.headerValues[key] = value
return &newC
}
// ContentType will set response ContentType to the pointer
func (c *Client) ContentType(contentType **string) *Client {
return c.HeaderValue("Content-Type", contentType)
}
// ContentLength will set response ContentLength to the pointer
func (c *Client) ContentLength(contentLength **int64) *Client {
newC := *c
newC.pointer.contentLength = contentLength
return &newC
}
// setPointers set the http response value to pointer
func (c *Client) setPointers(resp *http.Response) {
if c.pointer.response != nil {
*c.pointer.response = resp
}
if c.pointer.statusCode != nil {
*c.pointer.statusCode = &resp.StatusCode
}
if c.pointer.header != nil {
*c.pointer.header = &resp.Header
}
if c.pointer.headerValues != nil {
for k, v := range c.pointer.headerValues {
s := resp.Header.Get(k)
*v = &s
}
}
if c.pointer.contentLength != nil {
*c.pointer.contentLength = &resp.ContentLength
}
}
func (c *Client) customReq(req *BeegoHTTPRequest, opts []BeegoHttpRequestOption) {
req.Setting(c.Setting)
opts = append(c.CommonOpts, opts...)
@ -130,7 +67,17 @@ func (c *Client) handleResponse(value interface{}, req *BeegoHTTPRequest) error
if err != nil {
return err
}
c.setPointers(resp)
if carrier, ok := (value).(HttpResponseCarrier); ok {
(carrier).SetHttpResponse(resp)
}
if carrier, ok := (value).(ResponseBytesCarrier); ok {
bytes, err := req.Bytes()
if err != nil {
return err
}
(carrier).SetBytes(bytes)
}
return req.ResponseForValue(value)
}

View File

@ -29,91 +29,10 @@ func TestNewClient(t *testing.T) {
assert.Equal(t, true, client.Setting.EnableCookie)
}
func TestClient_Response(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
type slideSshowResponse struct {
Resp *http.Response
bytes []byte
var resp *http.Response
err = client.Response(&resp).Get(nil, "status/203")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 203, resp.StatusCode)
}
func TestClient_StatusCode(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
var statusCode *int
err = client.StatusCode(&statusCode).Get(nil, "status/203")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 203, *statusCode)
}
func TestClient_Headers(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
var header *http.Header
err = client.Headers(&header).Get(nil, "bytes/123")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "123", header.Get("Content-Length"))
}
func TestClient_HeaderValue(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
var val *string
err = client.Headers(nil).HeaderValue("Content-Length", &val).Get(nil, "bytes/123")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "123", *val)
}
func TestClient_ContentType(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
var contentType *string
err = client.ContentType(&contentType).Get(nil, "bytes/123")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "application/octet-stream", *contentType)
}
func TestClient_ContentLength(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
var contentLength *int64
err = client.ContentLength(&contentLength).Get(nil, "bytes/123")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, int64(123), *contentLength)
}
type total struct {
Slideshow slideshow `json:"slideshow" yaml:"slideshow"`
}
@ -132,36 +51,37 @@ type slide struct {
Title string `json:"title" yaml:"title" xml:"title"`
}
func (s *slideSshowResponse) SetHttpResponse(resp *http.Response) {
s.Resp = resp
}
func (s *slideSshowResponse) SetBytes(bytes []byte) {
s.bytes = bytes
}
func (s *slideSshowResponse) Bytes() []byte {
return s.bytes
}
func (s *slideSshowResponse) String() string {
return string(s.bytes)
}
func TestClient_Get(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/")
if err != nil {
t.Fatal(err)
}
// basic type
var s *string
err = client.Get(&s, "/base64/SFRUUEJJTiBpcyBhd2Vzb21l")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "HTTPBIN is awesome", *s)
var bytes *[]byte
err = client.Get(&bytes, "/base64/SFRUUEJJTiBpcyBhd2Vzb21l")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, []byte("HTTPBIN is awesome"), *bytes)
// json
var tp *total
err = client.Get(&tp, "/json")
var s *slideSshowResponse
err = client.Get(&s, "/json")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Sample Slide Show", tp.Slideshow.Title)
assert.Equal(t, 2, len(tp.Slideshow.Slides))
assert.Equal(t, "Overview", tp.Slideshow.Slides[1].Title)
assert.Equal(t, "Sample Slide Show", s.Slideshow.Title)
assert.Equal(t, 2, len(s.Slideshow.Slides))
assert.Equal(t, "Overview", s.Slideshow.Slides[1].Title)
// xml
var ssp *slideshow
@ -174,14 +94,14 @@ func TestClient_Get(t *testing.T) {
assert.Equal(t, "Overview", ssp.Slides[1].Title)
// yaml
tp = nil
err = client.Get(&tp, "/base64/c2xpZGVzaG93OgogIGF1dGhvcjogWW91cnMgVHJ1bHkKICBkYXRlOiBkYXRlIG9mIHB1YmxpY2F0aW9uCiAgc2xpZGVzOgogIC0gdGl0bGU6IFdha2UgdXAgdG8gV29uZGVyV2lkZ2V0cyEKICAgIHR5cGU6IGFsbAogIC0gaXRlbXM6CiAgICAtIFdoeSA8ZW0+V29uZGVyV2lkZ2V0czwvZW0+IGFyZSBncmVhdAogICAgLSBXaG8gPGVtPmJ1eXM8L2VtPiBXb25kZXJXaWRnZXRzCiAgICB0aXRsZTogT3ZlcnZpZXcKICAgIHR5cGU6IGFsbAogIHRpdGxlOiBTYW1wbGUgU2xpZGUgU2hvdw==")
s = nil
err = client.Get(&s, "/base64/c2xpZGVzaG93OgogIGF1dGhvcjogWW91cnMgVHJ1bHkKICBkYXRlOiBkYXRlIG9mIHB1YmxpY2F0aW9uCiAgc2xpZGVzOgogIC0gdGl0bGU6IFdha2UgdXAgdG8gV29uZGVyV2lkZ2V0cyEKICAgIHR5cGU6IGFsbAogIC0gaXRlbXM6CiAgICAtIFdoeSA8ZW0+V29uZGVyV2lkZ2V0czwvZW0+IGFyZSBncmVhdAogICAgLSBXaG8gPGVtPmJ1eXM8L2VtPiBXb25kZXJXaWRnZXRzCiAgICB0aXRsZTogT3ZlcnZpZXcKICAgIHR5cGU6IGFsbAogIHRpdGxlOiBTYW1wbGUgU2xpZGUgU2hvdw==")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "Sample Slide Show", tp.Slideshow.Title)
assert.Equal(t, 2, len(tp.Slideshow.Slides))
assert.Equal(t, "Overview", tp.Slideshow.Slides[1].Title)
assert.Equal(t, "Sample Slide Show", s.Slideshow.Title)
assert.Equal(t, 2, len(s.Slideshow.Slides))
assert.Equal(t, "Overview", s.Slideshow.Slides[1].Title)
}
@ -191,19 +111,19 @@ func TestClient_Post(t *testing.T) {
t.Fatal(err)
}
var s *string
err = client.Get(&s, "/json")
var resp = &slideSshowResponse{}
err = client.Get(resp, "/json")
if err != nil {
t.Fatal(err)
}
var resp *http.Response
err = client.Response(&resp).Post(&s, "/post", *s)
jsonStr := resp.String()
err = client.Post(resp, "/post", jsonStr)
if err != nil {
t.Fatal(err)
}
assert.NotNil(t, resp)
assert.Equal(t, http.MethodPost, resp.Request.Method)
assert.Equal(t, http.MethodPost, resp.Resp.Request.Method)
}
func TestClient_Put(t *testing.T) {
@ -212,19 +132,19 @@ func TestClient_Put(t *testing.T) {
t.Fatal(err)
}
var s *string
err = client.Get(&s, "/json")
var resp = &slideSshowResponse{}
err = client.Get(resp, "/json")
if err != nil {
t.Fatal(err)
}
var resp *http.Response
err = client.Response(&resp).Put(&s, "/put", *s)
jsonStr := resp.String()
err = client.Put(resp, "/put", jsonStr)
if err != nil {
t.Fatal(err)
}
assert.NotNil(t, resp)
assert.Equal(t, http.MethodPut, resp.Request.Method)
assert.Equal(t, http.MethodPut, resp.Resp.Request.Method)
}
func TestClient_Delete(t *testing.T) {
@ -233,13 +153,13 @@ func TestClient_Delete(t *testing.T) {
t.Fatal(err)
}
var resp *http.Response
err = client.Response(&resp).Delete(nil, "/delete")
var resp = &slideSshowResponse{}
err = client.Delete(resp, "/delete")
if err != nil {
t.Fatal(err)
}
assert.NotNil(t, resp)
assert.Equal(t, http.MethodDelete, resp.Request.Method)
assert.Equal(t, http.MethodDelete, resp.Resp.Request.Method)
}
func TestClient_Head(t *testing.T) {
@ -248,11 +168,11 @@ func TestClient_Head(t *testing.T) {
t.Fatal(err)
}
var resp *http.Response
err = client.Response(&resp).Head(nil, "")
var resp = &slideSshowResponse{}
err = client.Head(resp, "")
if err != nil {
t.Fatal(err)
}
assert.NotNil(t, resp)
assert.Equal(t, http.MethodHead, resp.Request.Method)
assert.Equal(t, http.MethodHead, resp.Resp.Request.Method)
}

View File

@ -663,30 +663,12 @@ func (b *BeegoHTTPRequest) Response() (*http.Response, error) {
// ResponseForValue attempts to resolve the response body to value using an existing method.
// Calls Response inner.
// If value type is **string or **[]byte, the func directly passes response body into the pointer.
// Else if response header contain Content-Type, func will call ToJSON\ToXML\ToYAML.
// Finally it will try to parse body as json\yaml\xml, If all attempts fail, an error will be returned
// If response header contain Content-Type, func will call ToJSON\ToXML\ToYAML.
// Else it will try to parse body as json\yaml\xml, If all attempts fail, an error will be returned
func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error {
if value == nil {
return nil
}
// handle basic type
switch v := value.(type) {
case **string:
s, err := b.String()
if err != nil {
return nil
}
*v = &s
return nil
case **[]byte:
bs, err := b.Bytes()
if err != nil {
return nil
}
*v = &bs
return nil
}
resp, err := b.Response()
if err != nil {