Skip to content

Commit

Permalink
Initial support for fasthttp client (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
gavv committed May 19, 2016
1 parent 77edb1e commit 3f1451b
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 0 deletions.
20 changes: 20 additions & 0 deletions expect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"net/http"
"net/http/httptest"
"testing"

"github.com/gavv/httpexpect/fasthttpexpect"
)

func TestExpectMethods(t *testing.T) {
Expand Down Expand Up @@ -206,4 +208,22 @@ func TestExpectLiveFast(t *testing.T) {
})
})
}

func BenchmarkExpectStd(b *testing.B) {
testExpectLive(b.N, func(url string) *Expect {
return WithConfig(Config{
BaseURL: url,
Reporter: NewAssertReporter(b),
})
})
}

func BenchmarkExpectFast(b *testing.B) {
testExpectLive(b.N, func(url string) *Expect {
return WithConfig(Config{
BaseURL: url,
Client: fasthttpexpect.NewClient(),
Reporter: NewAssertReporter(b),
})
})
}
91 changes: 91 additions & 0 deletions fasthttpexpect/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Package fasthttpexpect provides fasthttp adapter for httpexpect.
package fasthttpexpect

import (
"bytes"
"github.com/valyala/fasthttp"
"io"
"net/http"
)

// FastClient defines interface compatible with various fasthttp clients.
type FastClient interface {
// Do sends request and returns response.
Do(*fasthttp.Request, *fasthttp.Response) error
}

// FastClientAdapter wraps FastClient to implement httpexpect.Client.
type FastClientAdapter struct {
fastclient FastClient
}

var (
defaultFastClient fasthttp.Client
)

// NewClient returns a new adapater for default fasthttp.Client.
func NewClient() FastClientAdapter {
return WithClient(&defaultFastClient)
}

// WithClient returns a new adapter for custom fasthttp.Client.
func WithClient(fastclient FastClient) FastClientAdapter {
return FastClientAdapter{fastclient}
}

// Do implements httpexpect.Client.Do.
func (adapter FastClientAdapter) Do(
stdreq *http.Request) (stdresp *http.Response, err error) {

fastreq := fasthttp.AcquireRequest()

if stdreq.Body != nil {
fastreq.SetBodyStream(stdreq.Body, -1)
}

fastreq.SetRequestURI(stdreq.URL.String())

fastreq.Header.SetMethod(stdreq.Method)

for k, a := range stdreq.Header {
for _, v := range a {
fastreq.Header.Add(k, v)
}
}

var fastresp fasthttp.Response

if err = adapter.fastclient.Do(fastreq, &fastresp); err == nil {
status := fastresp.Header.StatusCode()
body := fastresp.Body()

stdresp = &http.Response{
Request: stdreq,
StatusCode: status,
Status: http.StatusText(status),
}

fastresp.Header.VisitAll(func(k, v []byte) {
if stdresp.Header == nil {
stdresp.Header = make(http.Header)
}
stdresp.Header.Add(string(k), string(v))
})

if body != nil {
stdresp.Body = readCloserAdapter{bytes.NewReader(body)}
}
}

fasthttp.ReleaseRequest(fastreq)

return
}

type readCloserAdapter struct {
io.Reader
}

func (b readCloserAdapter) Close() error {
return nil
}
53 changes: 53 additions & 0 deletions fasthttpexpect/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package fasthttpexpect

import (
"bytes"
"github.com/stretchr/testify/assert"
"github.com/valyala/fasthttp"
"io/ioutil"
"net/http"
"testing"
)

type mockFastClient struct {
t *testing.T
}

func (c mockFastClient) Do(req *fasthttp.Request, resp *fasthttp.Response) error {
assert.Equal(c.t, "GET", string(req.Header.Method()))
assert.Equal(c.t, "http://example.com", string(req.Header.RequestURI()))
assert.Equal(c.t, "body", string(req.Body()))

resp.Header.Set("Content-Type", "application/json")
resp.SetBody([]byte(`{"hello":"world"}`))

return nil
}

func TestClient(t *testing.T) {
adapter := WithClient(mockFastClient{t})

req, err := http.NewRequest(
"GET", "http://example.com", bytes.NewReader([]byte("body")))

if err != nil {
t.Fatal(err)
}

resp, err := adapter.Do(req)
if err != nil {
t.Fatal(err)
}

header := http.Header{
"Content-Type": {"application/json"},
}

b, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}

assert.Equal(t, header, resp.Header)
assert.Equal(t, `{"hello":"world"}`, string(b))
}
6 changes: 6 additions & 0 deletions wercker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ build:
name: go test
code: |
go test -coverprofile profile.cov .
go test ./fasthttpexpect
go test ./example
- script:
name: go bench
code: |
go test -bench . .
- script:
name: coveralls
code: |
Expand Down

0 comments on commit 3f1451b

Please sign in to comment.