diff --git a/http/request.go b/http/request.go new file mode 100644 index 0000000..42dd138 --- /dev/null +++ b/http/request.go @@ -0,0 +1,39 @@ +package http + +import ( + "errors" + "io" + "io/ioutil" + "net/http" +) + +var devnull io.Writer = ioutil.Discard + +func Do(method string, url string, r io.Reader, w io.Writer) error { + req, err := http.NewRequest(method, url, r) + if err != nil { + return err + } + + client := &http.Client{} + res, err := client.Do(req) + + if res != nil { + defer res.Body.Close() + } + + if err != nil { + return err + } + + if res.StatusCode < 200 || res.StatusCode >= 300 { + return errors.New(GetReason(res)) + } + + if w == nil { + _, err = io.Copy(devnull, res.Body) + } else { + _, err = io.Copy(w, res.Body) + } + return err +} diff --git a/http/request_test.go b/http/request_test.go new file mode 100644 index 0000000..30cdf93 --- /dev/null +++ b/http/request_test.go @@ -0,0 +1,118 @@ +package http + +import ( + "bytes" + "errors" + "net/http" + "testing" + + gock "gopkg.in/h2non/gock.v1" +) + +func TestReturnErrorOnInvalidURL(t *testing.T) { + defer gock.Off() + gock.New("").Reply(200) + + err := Do("GET", "://", nil, nil) + if err == nil { + t.Errorf("Expected error not returned") + } + + if gock.IsDone() { + t.Errorf("Request was performed anyway") + } +} + +func TestRequestGivenMethod(t *testing.T) { + defer gock.Off() + mock := gock.New("http://localhost") + mock.Method = "FOO" + mock.Reply(200) + + err := Do("FOO", "http://localhost", nil, nil) + if err != nil { + t.Errorf("Unexpected error on request") + } + + if gock.IsDone() == false { + t.Errorf("Expected request not performed") + } +} + +func TestReturnHTTPErrorAsIs(t *testing.T) { + defer gock.Off() + customError := errors.New("FOO") + gock.New("http://localhost").ReplyError(customError) + + err := Do("GET", "http://localhost", nil, nil) + if errors.Unwrap(err) != customError { + t.Errorf("Returned error is not the expected error") + } + + if gock.IsDone() == false { + t.Errorf("Expected request not performed") + } +} + +func TestReturnHTTPReasonAsErrorWhenUnsuccessful(t *testing.T) { + defer gock.Off() + gock.New("http://localhost").Reply(http.StatusTeapot) + + err := Do("GET", "http://localhost", nil, nil) + if err == nil || err.Error() != http.StatusText(http.StatusTeapot) { + t.Errorf("Reason should be returned as an error") + } + + if gock.IsDone() == false { + t.Errorf("Expected request not performed") + } +} + +func TestCopyResponseBodyToWriter(t *testing.T) { + defer gock.Off() + + gock.New("http://localhost").Reply(200).BodyString("FOO") + + rw := new(bytes.Buffer) + + err := Do("GET", "http://localhost", nil, rw) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + + res := rw.String() + + if res != "FOO" { + t.Errorf("Unexpected output %v", res) + } + + if gock.IsDone() == false { + t.Error("No expected endpoint called") + } +} + +func TestWriteToDevNullWhenNoWriter(t *testing.T) { + defer gock.Off() + + gock.New("http://localhost").Reply(200).BodyString("FOO") + + original := devnull + devnull = new(bytes.Buffer) + + defer func() { devnull = original }() + + err := Do("GET", "http://localhost", nil, nil) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + + res := devnull.(*bytes.Buffer).String() + + if res != "FOO" { + t.Errorf("Unexpected output %v", res) + } + + if gock.IsDone() == false { + t.Error("No expected endpoint called") + } +}