Skip to content

Commit

Permalink
Merge pull request #71 from maxatome/v1
Browse files Browse the repository at this point in the history
Add NewNotFoundResponder()
  • Loading branch information
maxatome authored Apr 14, 2019
2 parents 7ebf219 + b544528 commit 3acf212
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
65 changes: 65 additions & 0 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"net/http"
"runtime"
"strconv"
"strings"
)
Expand All @@ -29,6 +32,68 @@ func NewErrorResponder(err error) Responder {
}
}

// NewNotFoundResponder creates a Responder typically used in
// conjunction with RegisterNoResponder() function and testing
// package, to be proactive when a Responder is not found. fn is
// called with a unique string parameter containing the name of the
// missing route and the stack trace to localize the origin of the
// call. If fn returns (= if it does not panic), the responder returns
// an error of the form: "Responder not found for GET http://foo.bar/path".
// Note that fn can be nil.
//
// It is useful when writing tests to ensure that all routes have been
// mocked.
//
// Example of use:
// import "testing"
// ...
// func TestMyApp(t *testing.T) {
// ...
// // Calls testing.Fatal with the name of Responder-less route and
// // the stack trace of the call.
// httpmock.RegisterNoResponder(httpmock.NewNotFoundResponder(t.Fatal))
//
// Will abort the current test and print something like:
// response:69: Responder not found for: GET http://foo.bar/path
// Called from goroutine 20 [running]:
// github.com/jarcoal/httpmock.NewNotFoundResponder.func1(0xc00011f000, 0x0, 0x42dfb1, 0x77ece8)
// /go/src/github.com/jarcoal/httpmock/response.go:67 +0x1c1
// github.com/jarcoal/httpmock.runCancelable(0xc00004bfc0, 0xc00011f000, 0x7692f8, 0xc, 0xc0001208b0)
// /go/src/github.com/jarcoal/httpmock/transport.go:146 +0x7e
// github.com/jarcoal/httpmock.(*MockTransport).RoundTrip(0xc00005c980, 0xc00011f000, 0xc00005c980, 0x0, 0x0)
// /go/src/github.com/jarcoal/httpmock/transport.go:140 +0x19d
// net/http.send(0xc00011f000, 0x7d3440, 0xc00005c980, 0x0, 0x0, 0x0, 0xc000010400, 0xc000047bd8, 0x1, 0x0)
// /usr/local/go/src/net/http/client.go:250 +0x461
// net/http.(*Client).send(0x9f6e20, 0xc00011f000, 0x0, 0x0, 0x0, 0xc000010400, 0x0, 0x1, 0x9f7ac0)
// /usr/local/go/src/net/http/client.go:174 +0xfb
// net/http.(*Client).do(0x9f6e20, 0xc00011f000, 0x0, 0x0, 0x0)
// /usr/local/go/src/net/http/client.go:641 +0x279
// net/http.(*Client).Do(...)
// /usr/local/go/src/net/http/client.go:509
// net/http.(*Client).Get(0x9f6e20, 0xc00001e420, 0x23, 0xc00012c000, 0xb, 0x600)
// /usr/local/go/src/net/http/client.go:398 +0x9e
// net/http.Get(...)
// /usr/local/go/src/net/http/client.go:370
// foo.bar/foobar/foobar.TestMyApp(0xc00011e000)
// /go/src/foo.bar/foobar/foobar/my_app_test.go:272 +0xdbb
// testing.tRunner(0xc00011e000, 0x77e3a8)
// /usr/local/go/src/testing/testing.go:865 +0xc0
// created by testing.(*T).Run
// /usr/local/go/src/testing/testing.go:916 +0x35a
func NewNotFoundResponder(fn func(...interface{})) Responder {
return func(req *http.Request) (*http.Response, error) {
mesg := fmt.Sprintf("Responder not found for %s %s", req.Method, req.URL)
if fn != nil {
buf := make([]byte, 4096)
n := runtime.Stack(buf, false)
buf = buf[:n]
fn(mesg + "\nCalled from " +
strings.Replace(strings.TrimSuffix(string(buf), "\n"), "\n", "\n ", -1))
}
return nil, errors.New(mesg)
}
}

// NewStringResponse creates an *http.Response with a body based on the given string. Also accepts
// an http status code.
func NewStringResponse(status int, body string) *http.Response {
Expand Down
50 changes: 50 additions & 0 deletions response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"
)

Expand Down Expand Up @@ -48,6 +50,54 @@ func TestResponderFromResponse(t *testing.T) {
}
}

func TestNewNotFoundResponder(t *testing.T) {
var mesg string
responder := NewNotFoundResponder(func(args ...interface{}) {
mesg = fmt.Sprint(args[0])
})

req, err := http.NewRequest("GET", "http://foo.bar/path", nil)
if err != nil {
t.Fatal("Error creating request")
}

const title = "Responder not found for GET http://foo.bar/path"

resp, err := responder(req)
if resp != nil {
t.Error("resp should be nil")
}
if err == nil {
t.Error("err should be not nil")
} else if err.Error() != title {
t.Errorf(`err mismatch, got: "%s", expected: "%s"`,
err.Error(),
"Responder not found for: GET http://foo.bar/path")
}

if !strings.HasPrefix(mesg, title+"\nCalled from ") {
t.Error(`mesg should begin with "` + title + `\nCalled from ", but it is: "` + mesg + `"`)
}
if strings.HasSuffix(mesg, "\n") {
t.Error(`mesg should not end with \n, but it is: "` + mesg + `"`)
}

// nil fn
responder = NewNotFoundResponder(nil)

resp, err = responder(req)
if resp != nil {
t.Error("resp should be nil")
}
if err == nil {
t.Error("err should be not nil")
} else if err.Error() != title {
t.Errorf(`err mismatch, got: "%s", expected: "%s"`,
err.Error(),
"Responder not found for: GET http://foo.bar/path")
}
}

func TestNewStringResponse(t *testing.T) {
body := "hello world"
status := 200
Expand Down

0 comments on commit 3acf212

Please sign in to comment.