From 6bbbc077ed2229c26fa9ee4b1dc12ca417ba8808 Mon Sep 17 00:00:00 2001 From: Edwin Love Date: Tue, 27 Aug 2019 15:50:22 +0000 Subject: [PATCH 1/2] Create go.mod and go.sum --- go.mod | 11 +++++++++++ go.sum | 10 ++++++++++ 2 files changed, 21 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..304cd85 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/thingful/httpmock + +go 1.12 + +require ( + github.com/PuerkitoBio/purell v1.0.0 + github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 + github.com/goware/urlx v0.0.0-20160113170155-86bdc2456038 + golang.org/x/net v0.0.0-20161101191631-4bb47a1098b3 + golang.org/x/text v0.0.0-20161027091323-a8b38433e35b +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6b703ed --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/goware/urlx v0.0.0-20160113170155-86bdc2456038 h1:Gc3BCC674dsGqSp0cu9UAPydZRC7gxEOuUNKgXQPAx8= +github.com/goware/urlx v0.0.0-20160113170155-86bdc2456038/go.mod h1:Zn362WbIrTvMfW1tj4MxrEct8vJtNlnljZPnRssPfDU= +golang.org/x/net v0.0.0-20161101191631-4bb47a1098b3 h1:9FrZULpPblLeSMxFmRapLbJGYHjcvaCZYD+5rwKQqZA= +golang.org/x/net v0.0.0-20161101191631-4bb47a1098b3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/text v0.0.0-20161027091323-a8b38433e35b h1:bQeEFHDAz2T0N9zVAr0qdH8BRhoZocCxLudf/77OxGY= +golang.org/x/text v0.0.0-20161027091323-a8b38433e35b/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From a5ba32b46788ae84f7d92cd89905da3d76e87378 Mon Sep 17 00:00:00 2001 From: Edwin Love Date: Tue, 27 Aug 2019 15:52:21 +0000 Subject: [PATCH 2/2] Use byte array instead of reader for stubbed request body This allows multiple stubbed request with bodies to be used as the io.Reader was being emptied on the first pass so was empty next time around --- stubbed_request.go | 21 +++--- transport.go | 14 ++++ transport_test.go | 182 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 9 deletions(-) diff --git a/stubbed_request.go b/stubbed_request.go index c992246..f991424 100644 --- a/stubbed_request.go +++ b/stubbed_request.go @@ -57,7 +57,7 @@ type StubRequest struct { Method string URL string Header *http.Header - Body io.Reader + Body []byte Responder Responder Called bool } @@ -74,7 +74,11 @@ func (r *StubRequest) WithHeader(header *http.Header) *StubRequest { // // Deprecated: use the functional WithBody configuration function instead func (r *StubRequest) WithBody(body io.Reader) *StubRequest { - r.Body = body + var err error + r.Body, err = ioutil.ReadAll(body) + if err != nil { + panic(err) + } return r } @@ -90,7 +94,11 @@ func WithHeader(header *http.Header) Option { // request func WithBody(body io.Reader) Option { return func(r *StubRequest) { - r.Body = body + var err error + r.Body, err = ioutil.ReadAll(body) + if err != nil { + panic(err) + } } } @@ -136,17 +144,12 @@ func (r *StubRequest) Matches(req *http.Request) error { // if our stub includes a body, then it should equal the actual request body // to match if r.Body != nil { - stubBody, err := ioutil.ReadAll(r.Body) - if err != nil { - return err - } - requestBody, err := ioutil.ReadAll(req.Body) if err != nil { return err } - if bytes.Compare(stubBody, requestBody) != 0 { + if bytes.Compare(r.Body, requestBody) != 0 { return ErrIncorrectRequestBody } } diff --git a/transport.go b/transport.go index 7491c3d..70b5d2c 100644 --- a/transport.go +++ b/transport.go @@ -1,6 +1,8 @@ package httpmock import ( + "bytes" + "io/ioutil" "net/http" "strings" "sync" @@ -72,8 +74,20 @@ func (m *MockTransport) stubForRequest(req *http.Request) (*StubRequest, error) var err error var errs = []error{} + haveBody := false + var body []byte + if req.Body != nil { + body, err = ioutil.ReadAll(req.Body) + if err != nil { + return nil, err + } + haveBody = true + } // find the first stub that matches the request for _, stub := range m.stubs { + if haveBody { + req.Body = ioutil.NopCloser(bytes.NewReader(body)) + } err = stub.Matches(req) if err == nil { return stub, nil diff --git a/transport_test.go b/transport_test.go index 48ec177..634d182 100644 --- a/transport_test.go +++ b/transport_test.go @@ -231,6 +231,186 @@ func TestAllStubsCalled(t *testing.T) { } } +func TestAllStubsCalledWithMultipleRequestsWithTheSameMethodAndUrl(t *testing.T) { + Activate() + defer DeactivateAndReset() + + RegisterStubRequest(NewStubRequest("GET", "http://example.com", NewStringResponder(200, "ok"))) + + // make a single request + resp, err := http.Get("http://example.com") + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err != nil { + t.Errorf("Expected no error when not all stubs called") + } + + // make a second request + resp, err = http.Get("http://example.com") + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err != nil { + t.Errorf("Expected no error when not all stubs called") + } + +} + +func TestAllStubsCalledWithTheSameMethodUrlHeaderAndBody(t *testing.T) { + Activate() + defer DeactivateAndReset() + + body, err := json.Marshal(map[string]string{"foo": "bar"}) + if err != nil { + panic(err) + } + + // register a stub with body and header + RegisterStubRequest( + NewStubRequest( + "POST", "http://example.com", NewStringResponder(200, "ok"), + ).WithHeader( + &http.Header{"X-Foo-Bar": []string{"Foo Bar Baz"}}, + ).WithBody(bytes.NewBuffer(body)), + ) + + // make a single request + req, err := http.NewRequest("POST", "http://example.com", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Foo-Bar", "Foo Bar Baz") + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err != nil { + t.Errorf("Expected no error when not all stubs called") + } + + // make a second identical request + req, err = http.NewRequest("POST", "http://example.com", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Foo-Bar", "Foo Bar Baz") + resp, err = http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err != nil { + t.Errorf("Expected no error when all stubs called") + } + +} + +func TestAllStubsCalledWithDifferentMethodUrlHeaderAndBody(t *testing.T) { + Activate() + defer DeactivateAndReset() + + body, err := json.Marshal(map[string]string{"foo": "bar"}) + if err != nil { + panic(err) + } + + body2, err := json.Marshal(map[string]string{"foo": "baz"}) + if err != nil { + panic(err) + } + + // register two stubs + RegisterStubRequest( + NewStubRequest( + "POST", "http://example.com", NewStringResponder(200, "ok"), + ).WithHeader( + &http.Header{"X-Foo-Bar": []string{"Foo Bar Baz"}}, + ).WithBody( + bytes.NewBuffer(body2), + ), + ) + + RegisterStubRequest( + NewStubRequest( + "POST", "http://example.com", NewStringResponder(200, "ok"), + ).WithHeader( + &http.Header{"X-Foo-Bar": []string{"Foo Bar Baz"}}, + ).WithBody(bytes.NewBuffer(body)), + ) + + // make a single request + req, err := http.NewRequest("POST", "http://example.com", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Foo-Bar", "Foo Bar Baz") + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err == nil { + t.Errorf("Expected error when not all stubs called") + } + + if !strings.Contains(err.Error(), "http://example.com") { + t.Errorf("Expected error message to contain uncalled stub, got: '%s'", err.Error()) + } + + // make a single request + req, err = http.NewRequest("POST", "http://example.com", bytes.NewReader(body)) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Foo-Bar", "Foo Bar Baz") + resp, err = http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err == nil { + t.Errorf("Expected error when not all stubs called") + } + + if !strings.Contains(err.Error(), "http://example.com") { + t.Errorf("Expected error message to contain uncalled stub, got: '%s'", err.Error()) + } + + // make a single request + req, err = http.NewRequest("POST", "http://example.com", bytes.NewReader(body2)) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Foo-Bar", "Foo Bar Baz") + resp, err = http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + resp.Body.Close() + + err = AllStubsCalled() + if err != nil { + t.Errorf("Expected no error when all stubs called") + } + +} + func TestMockTransportReset(t *testing.T) { DeactivateAndReset() @@ -451,3 +631,5 @@ func TestMockTransportNonDefaultAllowedHosts(t *testing.T) { // restore our original initialTransport = cachedTransport } + +// func