-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
525 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package client | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"strings" | ||
) | ||
|
||
// ResponseDecoder is an interface for decoding an HTTP response body. | ||
type ResponseDecoder interface { | ||
Decode(io.Reader, any) error | ||
} | ||
|
||
// JSONResponseDecoder decodes JSON-encoded HTTP response bodies. | ||
type JSONResponseDecoder struct{} | ||
|
||
// Decode decodes a JSON-encoded response body into the provided interface. | ||
func (d *JSONResponseDecoder) Decode(r io.Reader, v any) error { | ||
return json.NewDecoder(r).Decode(v) | ||
} | ||
|
||
// StringResponseDecoder decodes plain text or HTML-encoded HTTP response bodies. | ||
type StringResponseDecoder struct{} | ||
|
||
// Decode decodes a plain text or HTML-encoded response body into the provided string. | ||
func (d *StringResponseDecoder) Decode(r io.Reader, v any) error { | ||
if str, ok := v.(*string); ok { | ||
data, err := io.ReadAll(r) | ||
if err != nil { | ||
return err | ||
} | ||
*str = string(data) | ||
return nil | ||
} | ||
return fmt.Errorf("StringResponseDecoder: unsupported type %T", v) | ||
} | ||
|
||
// selectDecoder selects the appropriate ResponseDecoder based on the Content-Type of the response. | ||
func selectDecoder(contentType string) ResponseDecoder { | ||
switch { | ||
case strings.Contains(contentType, MIMEApplicationJSON): | ||
return &JSONResponseDecoder{} | ||
case strings.Contains(contentType, MIMETextPlain), strings.Contains(contentType, MIMETextHTML): | ||
return &StringResponseDecoder{} | ||
// Add more cases as needed | ||
default: | ||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package client | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
type HTTPClientCallDecoderSuite struct { | ||
suite.Suite | ||
} | ||
|
||
func (suite *HTTPClientCallDecoderSuite) TestJSONResponseDecoder_Decode() { | ||
suite.Run("decodes JSON response successfully", func() { | ||
decoder := &JSONResponseDecoder{} | ||
body := `{"key":"value"}` | ||
r := io.NopCloser(bytes.NewBufferString(body)) | ||
var result map[string]string | ||
|
||
err := decoder.Decode(r, &result) | ||
suite.NoError(err) | ||
suite.Equal("value", result["key"]) | ||
}) | ||
|
||
suite.Run("returns error for invalid JSON", func() { | ||
decoder := &JSONResponseDecoder{} | ||
body := `{"key":"value"` | ||
r := io.NopCloser(bytes.NewBufferString(body)) | ||
var result map[string]string | ||
|
||
err := decoder.Decode(r, &result) | ||
suite.Error(err) | ||
}) | ||
} | ||
|
||
func (suite *HTTPClientCallDecoderSuite) TestStringResponseDecoder_Decode() { | ||
suite.Run("decodes plain text response successfully", func() { | ||
decoder := &StringResponseDecoder{} | ||
body := "Hello, world!" | ||
r := io.NopCloser(bytes.NewBufferString(body)) | ||
var result string | ||
|
||
err := decoder.Decode(r, &result) | ||
suite.NoError(err) | ||
suite.Equal("Hello, world!", result) | ||
}) | ||
|
||
suite.Run("decodes HTML response successfully", func() { | ||
decoder := &StringResponseDecoder{} | ||
body := "<html><body>Hello, world!</body></html>" | ||
r := io.NopCloser(bytes.NewBufferString(body)) | ||
var result string | ||
|
||
err := decoder.Decode(r, &result) | ||
suite.NoError(err) | ||
suite.Equal("<html><body>Hello, world!</body></html>", result) | ||
}) | ||
|
||
suite.Run("returns error for unsupported type", func() { | ||
decoder := &StringResponseDecoder{} | ||
body := "Hello, world!" | ||
r := io.NopCloser(bytes.NewBufferString(body)) | ||
var result int | ||
|
||
err := decoder.Decode(r, &result) | ||
suite.Error(err) | ||
suite.EqualError(err, "StringResponseDecoder: unsupported type *int") | ||
}) | ||
} | ||
|
||
func (suite *HTTPClientCallDecoderSuite) TestSelectDecoder() { | ||
suite.Run("selects JSONResponseDecoder for application/json", func() { | ||
contentType := "application/json" | ||
decoder := selectDecoder(contentType) | ||
_, ok := decoder.(*JSONResponseDecoder) | ||
suite.True(ok) | ||
}) | ||
|
||
suite.Run("selects StringResponseDecoder for text/plain", func() { | ||
contentType := "text/plain" | ||
decoder := selectDecoder(contentType) | ||
_, ok := decoder.(*StringResponseDecoder) | ||
suite.True(ok) | ||
}) | ||
|
||
suite.Run("selects StringResponseDecoder for text/html", func() { | ||
contentType := "text/html" | ||
decoder := selectDecoder(contentType) | ||
_, ok := decoder.(*StringResponseDecoder) | ||
suite.True(ok) | ||
}) | ||
|
||
suite.Run("returns nil for unsupported content type", func() { | ||
contentType := "application/xml" | ||
decoder := selectDecoder(contentType) | ||
suite.Nil(decoder) | ||
}) | ||
} | ||
|
||
func TestHTTPClientCallDecoderSuite(t *testing.T) { | ||
suite.Run(t, new(HTTPClientCallDecoderSuite)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package client | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
type HTTPClientCallHeadersSuite struct { | ||
suite.Suite | ||
call *HTTPClientCall | ||
req *http.Request | ||
} | ||
|
||
func (suite *HTTPClientCallHeadersSuite) SetupTest() { | ||
client := &http.Client{} | ||
suite.call = NewHTTPClientCall("http://example.com", client) | ||
suite.req, _ = http.NewRequest("GET", "http://example.com", nil) | ||
} | ||
|
||
func (suite *HTTPClientCallHeadersSuite) TestSetHeaders() { | ||
suite.Run("sets single header correctly", func() { | ||
headers := http.Header{ | ||
HeaderContentType: []string{"application/json"}, | ||
} | ||
suite.call.Headers(headers) | ||
suite.call.setHeaders(suite.req) | ||
|
||
assert.Equal(suite.T(), "application/json", suite.req.Header.Get(HeaderContentType)) | ||
}) | ||
|
||
suite.Run("sets multiple headers correctly", func() { | ||
headers := http.Header{ | ||
HeaderContentType: []string{"application/json"}, | ||
HeaderAccept: []string{"application/json"}, | ||
} | ||
suite.call.Headers(headers) | ||
suite.call.setHeaders(suite.req) | ||
|
||
assert.Equal(suite.T(), "application/json", suite.req.Header.Get(HeaderContentType)) | ||
assert.Equal(suite.T(), "application/json", suite.req.Header.Get(HeaderAccept)) | ||
}) | ||
|
||
suite.Run("sets multiple values for a single header correctly", func() { | ||
headers := http.Header{ | ||
HeaderAcceptEncoding: []string{"gzip", "deflate"}, | ||
} | ||
suite.call.Headers(headers) | ||
suite.call.setHeaders(suite.req) | ||
|
||
assert.ElementsMatch(suite.T(), []string{"gzip", "deflate"}, suite.req.Header[HeaderAcceptEncoding]) | ||
}) | ||
} | ||
|
||
func TestHTTPClientCallHeadersSuite(t *testing.T) { | ||
suite.Run(t, new(HTTPClientCallHeadersSuite)) | ||
} |
Oops, something went wrong.