| package mockhttpclient |
| |
| import ( |
| "fmt" |
| "io" |
| "io/ioutil" |
| "net/http" |
| "regexp" |
| "sync" |
| "testing" |
| "time" |
| |
| "github.com/gorilla/mux" |
| assert "github.com/stretchr/testify/require" |
| "go.skia.org/infra/go/testutils/unittest" |
| "go.skia.org/infra/go/util" |
| ) |
| |
| func TestBasic(t *testing.T) { |
| unittest.SmallTest(t) |
| // This is the example in the documentation. |
| r := mux.NewRouter() |
| r.Schemes("https").Host("www.google.com").Methods("GET"). |
| Handler(MockGetDialogue([]byte("Here's a response."))) |
| client := NewMuxClient(r) |
| res, err := client.Get("https://www.google.com") |
| assert.NoError(t, err) |
| respBody, err := ioutil.ReadAll(res.Body) |
| assert.NoError(t, err) |
| assert.Equal(t, []byte("Here's a response."), respBody) |
| } |
| |
| func TestVars(t *testing.T) { |
| unittest.SmallTest(t) |
| // This is the example in the documentation. |
| r := mux.NewRouter() |
| expectedResponse := "Success." |
| r.Host("example.com").Methods("POST").Path("/add/{id:[a-zA-Z0-9]+}"). |
| Queries("name", "{name}", "size", "42"). |
| HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| t := MuxSafeT(t) |
| assert.Equal(t, mux.Vars(r)["id"], mux.Vars(r)["name"]) |
| _, err := w.Write([]byte(expectedResponse)) |
| assert.NoError(t, err) |
| }) |
| client := NewMuxClient(r) |
| resp, err := client.Post("http://example.com/add/foo?name=foo&size=42", "", nil) |
| assert.NoError(t, err) |
| actualResponse, err := ioutil.ReadAll(resp.Body) |
| assert.NoError(t, err) |
| assert.Equal(t, expectedResponse, string(actualResponse)) |
| } |
| |
| // mockTestingT mocks expect.TestingT. |
| type mockTestingT struct { |
| errors []string |
| } |
| |
| func (t *mockTestingT) Errorf(format string, args ...interface{}) { |
| t.errors = append(t.errors, fmt.Sprintf(format, args...)) |
| } |
| |
| func TestAssertionFailure(t *testing.T) { |
| unittest.SmallTest(t) |
| mockT := &mockTestingT{} |
| |
| r := mux.NewRouter() |
| r.Host("example.com").Methods("POST").Path("/add/{id:[a-zA-Z0-9]+}"). |
| Queries("name", "{name}", "size", "42"). |
| HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| t := MuxSafeT(mockT) |
| assert.Equal(t, mux.Vars(r)["id"], mux.Vars(r)["name"]) |
| }) |
| client := NewMuxClient(r) |
| _, err := client.Post("http://example.com/add/foo?name=bar&size=42", "", nil) |
| |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), "Test failed") |
| assert.Contains(t, err.Error(), "while handling HTTP request for http://example.com/add/foo?name=bar&size=42") |
| |
| assert.Equal(t, 1, len(mockT.errors)) |
| re := regexp.MustCompile(`Not equal:\s+expected:\s+"foo"\s+actual\s+:\s+"bar"\s*`) |
| assert.True(t, re.MatchString(mockT.errors[0]), "Expected test failure message to match regexp %q, but got %q", re, mockT.errors[0]) |
| } |
| |
| func TestMissingHandler(t *testing.T) { |
| unittest.SmallTest(t) |
| r := mux.NewRouter() |
| handlerCalled := false |
| r.Host("example.com").Methods("POST").Path("/add/{id:[a-zA-Z0-9]+}"). |
| // Intentional typo "naem". |
| Queries("naem", "{name}", "size", "42"). |
| HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| handlerCalled = true |
| }) |
| client := NewMuxClient(r) |
| _, err := client.Post("http://example.com/add/foo?name=foo&size=42", "", nil) |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), "No matching handler for http://example.com/add/foo?name=foo&size=42") |
| assert.False(t, handlerCalled) |
| } |
| |
| func TestErrorResponse(t *testing.T) { |
| unittest.SmallTest(t) |
| r := mux.NewRouter() |
| r.Schemes("https").Host("www.google.com").Methods("GET"). |
| Handler(MockGetError("TODO(benjaminwagner)", http.StatusTeapot)) |
| client := NewMuxClient(r) |
| res, err := client.Get("https://www.google.com") |
| assert.NoError(t, err) |
| assert.Equal(t, http.StatusTeapot, res.StatusCode) |
| } |
| |
| // doStreamingRequestAndCheckBodyClosed performs a POST request to url using client with a streaming |
| // body. Asserts that the body is closed by client within 10 seconds. Returns the result of |
| // client.Post. |
| func doStreamingRequestAndAssertBodyClosed(t *testing.T, client *http.Client, url string) (*http.Response, error) { |
| reader, writer := io.Pipe() |
| abort := time.After(10 * time.Second) |
| aborted := false |
| var writeErr error |
| wg := sync.WaitGroup{} |
| wg.Add(1) |
| go func() { |
| defer util.Close(writer) |
| defer wg.Done() |
| for { |
| select { |
| case <-abort: |
| aborted = true |
| return |
| default: |
| } |
| _, writeErr = writer.Write([]byte("aaaaaaaaaaaaaaaa")) |
| if writeErr != nil { |
| return |
| } |
| } |
| }() |
| |
| resp, err := client.Post(url, "text/plain", reader) |
| |
| wg.Wait() |
| assert.False(t, aborted) |
| assert.Equal(t, io.ErrClosedPipe, writeErr) |
| |
| return resp, err |
| } |
| |
| func TestStreamingBodyClosedForEmptyHandler(t *testing.T) { |
| unittest.SmallTest(t) |
| r := mux.NewRouter() |
| r.Host("example.com").Methods("POST").Path("/add/{id:[a-zA-Z0-9]+}"). |
| HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| }) |
| client := NewMuxClient(r) |
| _, err := doStreamingRequestAndAssertBodyClosed(t, client, "http://example.com/add/foo") |
| assert.NoError(t, err) |
| } |
| |
| func TestStreamingBodyClosedForMissingHandler(t *testing.T) { |
| unittest.SmallTest(t) |
| r := mux.NewRouter() |
| handlerCalled := false |
| r.Host("example.com").Methods("POST").Path("/add/{id:[a-zA-Z0-9]+}"). |
| HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| handlerCalled = true |
| }) |
| client := NewMuxClient(r) |
| _, err := doStreamingRequestAndAssertBodyClosed(t, client, "http://example.com/remove/foo") |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), "No matching handler for http://example.com/remove/foo") |
| assert.False(t, handlerCalled) |
| } |
| |
| func TestStreamingBodyClosedForInvalidURL(t *testing.T) { |
| unittest.SmallTest(t) |
| r := mux.NewRouter() |
| handlerCalled := false |
| r.Host("example.com").Methods("POST").Path("/add/{id:[a-zA-Z0-9]+}"). |
| HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| handlerCalled = true |
| }) |
| client := NewMuxClient(r) |
| _, err := doStreamingRequestAndAssertBodyClosed(t, client, "http:///remove/foo") |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), "invalid request") |
| assert.False(t, handlerCalled) |
| } |
| |
| func TestMockDialogueFailureInMuxClient(t *testing.T) { |
| unittest.SmallTest(t) |
| r := mux.NewRouter() |
| r.Schemes("https").Host("www.google.com").Methods("POST"). |
| Handler(MockGetDialogue([]byte("Here's a response."))) |
| client := NewMuxClient(r) |
| _, err := client.Post("https://www.google.com", "", nil) |
| assert.Error(t, err) |
| assert.Contains(t, err.Error(), `Wrong Method, expected "GET", but was "POST"`) |
| } |