Skip to content

Commit

Permalink
Merge pull request #5 from bozd4g/bug/context-canceling-problem
Browse files Browse the repository at this point in the history
Context canceling problem
  • Loading branch information
bozd4g authored Dec 5, 2022
2 parents 3647beb + 0876845 commit a82330e
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 51 deletions.
13 changes: 11 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package gohttpclient
import (
"bytes"
"context"
"io/ioutil"
"net/http"
"time"

"github.com/pkg/errors"
)

type (
Expand Down Expand Up @@ -206,8 +209,14 @@ func (c *Client) sendReq(ctx context.Context, req *http.Request) (*Response, err

res, err := c.httpClient.Do(req.WithContext(reqCtx))
if err != nil {
return nil, err
return nil, errors.Wrap(err, "failed to send request")
}

defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, errors.Wrap(err, "failed to read response body")
}

return &Response{httpResponse: res}, nil
return &Response{res, body}, nil
}
74 changes: 74 additions & 0 deletions client_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package gohttpclient

import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/suite"
)

type IntegrationSuite struct {
suite.Suite
bigJsonFile []byte
}

func TestIntegrationSuite(t *testing.T) {
suite.Run(t, new(IntegrationSuite))
}

func (s *IntegrationSuite) SetupSuite() {}

func (s *IntegrationSuite) Test_Get_WhenServerReturnsBigFile_ShouldRunSuccesfully() {
// Arrange
type Post struct {
ID int `json:"id"`
Title string `json:"title"`
}

ctx := context.Background()

// read large file from test folder
testSvc := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
bigArr := make([]Post, 0)
for i := 0; i < 100000; i++ {
bigArr = append(bigArr, Post{ID: i, Title: fmt.Sprintf("Title %d", i)})
}

postJson, err := json.Marshal(bigArr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

// write cookie
http.SetCookie(w, &http.Cookie{Name: "test", Value: "test"})
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(postJson)
}))

client := New(testSvc.URL)

// Act
resp, err := client.Get(ctx, "/")
body := resp.Body()
status := resp.Status()
headers := resp.Headers()
cookies := resp.Cookies()
ok := resp.Ok()
res := resp.Get()

// Assert
s.NoError(err)
s.NotNil(resp)
s.NotNil(body)
s.Equal(http.StatusOK, status)
s.Equal("application/json", headers.Get("Content-Type"))
s.Equal(1, len(cookies))
s.True(ok)
s.NotNil(res)
}
65 changes: 64 additions & 1 deletion client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,72 @@ func (s *TestClientSuite) Test_Request_WhenDoReturnsAnError_ShouldReturnError()
}
}

func (s *TestClientSuite) Test_Request_WhenBodyReturnsError_ShouldReturnError() {
// Arrange
svc := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Length", "1")
w.Write(nil)
}))
defer svc.Close()

client := New(svc.URL)
requests := []TestMethod{
{
name: "GET",
baseUrl: svc.URL,
method: client.Get,
},
{
name: "POST",
baseUrl: svc.URL,
method: client.Post,
},
{
name: "PUT",
baseUrl: svc.URL,
method: client.Put,
},
{
name: "PATCH",
baseUrl: svc.URL,
method: client.Patch,
},
{
name: "DELETE",
baseUrl: svc.URL,
method: client.Delete,
},
{
name: "CONNECT",
baseUrl: svc.URL,
method: client.Connect,
},
{
name: "OPTIONS",
baseUrl: svc.URL,
method: client.Options,
},
{
name: "TRACE",
baseUrl: svc.URL,
method: client.Trace,
},
}

for _, req := range requests {
s.Suite.Run(req.name, func() {
// Act
response, err := req.method(s.ctx, "")

// Assert
s.Nil(response)
s.Error(err)
})
}
}

func (s *TestClientSuite) Test_Request_ShouldRunSuccesfully() {
// Arrange
// init test server
svc := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require github.com/stretchr/testify v1.6.1

require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.1.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
Expand Down
24 changes: 12 additions & 12 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import (

type (
Response struct {
httpResponse *http.Response
res *http.Response
body []byte
}
)

func (r *Response) Body() ([]byte, error) {
defer r.httpResponse.Body.Close()
return ioutil.ReadAll(r.httpResponse.Body)
func (r *Response) Body() []byte {
return r.body
}

func (r *Response) Unmarshal(v any) error {
defer r.httpResponse.Body.Close()
body, err := ioutil.ReadAll(r.httpResponse.Body)
defer r.res.Body.Close()
body, err := ioutil.ReadAll(r.res.Body)
if err != nil {
return err
}
Expand All @@ -28,21 +28,21 @@ func (r *Response) Unmarshal(v any) error {
}

func (r *Response) Status() int {
return r.httpResponse.StatusCode
return r.res.StatusCode
}

func (r *Response) Header() http.Header {
return r.httpResponse.Header
func (r *Response) Headers() http.Header {
return r.res.Header
}

func (r *Response) Cookies() []*http.Cookie {
return r.httpResponse.Cookies()
return r.res.Cookies()
}

func (r *Response) Ok() bool {
return r.httpResponse.StatusCode >= 200 && r.httpResponse.StatusCode <= 299
return r.res.StatusCode >= 200 && r.res.StatusCode <= 299
}

func (r *Response) Get() *http.Response {
return r.httpResponse
return r.res
}
50 changes: 14 additions & 36 deletions response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,37 +42,15 @@ func (s *TestResponseSuite) SetupSuite() {
func (s *TestResponseSuite) Test_Body_ShouldRunSuccesfully() {
// Arrange
body := []byte("test")

// Act
resp := Response{
&http.Response{
Body: ioutil.NopCloser(bytes.NewBuffer(body)),
},
}

// Assert
responseBody, err := resp.Body()
s.NoError(err)
s.Equal(body, responseBody)
}

func (s *TestResponseSuite) Test_Body_ShouldReturnError() {
// Arrange
mockReadCloser := mockReadCloser{}
mockReadCloser.On("Read", mock.AnythingOfType("[]uint8")).Return(0, fmt.Errorf("error reading"))
mockReadCloser.On("Close").Return(fmt.Errorf("error closing"))

resp := Response{
&http.Response{
Body: &mockReadCloser,
},
res := &http.Response{
Body: ioutil.NopCloser(bytes.NewBuffer(body)),
}

// Act
_, err := resp.Body()
resp := Response{res, body}

// Assert
s.Error(err)
s.Equal(body, resp.Body())
}

func (s *TestResponseSuite) Test_Unmarshal_ShouldRunSuccesfully() {
Expand All @@ -81,7 +59,7 @@ func (s *TestResponseSuite) Test_Unmarshal_ShouldRunSuccesfully() {

// Act
resp := Response{
&http.Response{
res: &http.Response{
Body: ioutil.NopCloser(bytes.NewBuffer(body)),
},
}
Expand All @@ -100,7 +78,7 @@ func (s *TestResponseSuite) Test_Unmarshal_WhenBodyIsWrong_ShouldReturnError() {
mockReadCloser.On("Close").Return(fmt.Errorf("error closing"))

resp := Response{
&http.Response{
res: &http.Response{
Body: &mockReadCloser,
},
}
Expand All @@ -119,7 +97,7 @@ func (s *TestResponseSuite) Test_Unmarshal_WhenUnMarshalReturnsError_ShouldRetur

// Act
resp := Response{
&http.Response{
res: &http.Response{
Body: ioutil.NopCloser(bytes.NewBuffer(body)),
},
}
Expand All @@ -133,7 +111,7 @@ func (s *TestResponseSuite) Test_Unmarshal_WhenUnMarshalReturnsError_ShouldRetur
func (s *TestResponseSuite) Test_Status_ShouldRunSuccesfully() {
// Arrange
resp := Response{
&http.Response{
res: &http.Response{
StatusCode: 200,
},
}
Expand All @@ -148,15 +126,15 @@ func (s *TestResponseSuite) Test_Status_ShouldRunSuccesfully() {
func (s *TestResponseSuite) Test_Header_ShouldRunSuccesfully() {
// Arrange
resp := Response{
&http.Response{
res: &http.Response{
Header: http.Header{
"Content-Type": []string{"application/json"},
},
},
}

// Act
header := resp.Header()
header := resp.Headers()

// Assert
s.Equal("application/json", header["Content-Type"][0])
Expand All @@ -165,7 +143,7 @@ func (s *TestResponseSuite) Test_Header_ShouldRunSuccesfully() {
func (s *TestResponseSuite) Test_Cookies_ShouldRunSuccesfully() {
// Arrange
resp := Response{
&http.Response{
res: &http.Response{
Header: http.Header{
"Set-Cookie": []string{"test=1"},
},
Expand All @@ -182,7 +160,7 @@ func (s *TestResponseSuite) Test_Cookies_ShouldRunSuccesfully() {
func (s *TestResponseSuite) Test_Ok_ShouldRunSuccesfully() {
// Arrange
resp := Response{
&http.Response{
res: &http.Response{
StatusCode: 200,
},
}
Expand All @@ -197,7 +175,7 @@ func (s *TestResponseSuite) Test_Ok_ShouldRunSuccesfully() {
func (s *TestResponseSuite) Test_Get_ShouldRunSuccesfully() {
// Arrange
resp := Response{
&http.Response{
res: &http.Response{
Header: http.Header{
"Content-Type": []string{"application/json"},
},
Expand All @@ -208,5 +186,5 @@ func (s *TestResponseSuite) Test_Get_ShouldRunSuccesfully() {
res := resp.Get()

// Assert
s.Equal(resp.httpResponse, res)
s.Equal(resp.res, res)
}

0 comments on commit a82330e

Please sign in to comment.