Skip to content

Commit 505bb39

Browse files
authored
Merge pull request #73 from deploymenttheory/dev
Add API handler methods to MockAPIHandler
2 parents 7d1325f + 9f24d11 commit 505bb39

File tree

2 files changed

+197
-0
lines changed

2 files changed

+197
-0
lines changed

httpclient/httpclient_api_handler_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,56 @@ func (m *MockAPIHandler) HandleAPIErrorResponse(resp *http.Response, out interfa
5050
return args.Error(0)
5151
}
5252

53+
func (m *MockAPIHandler) GetAPIBearerTokenAuthenticationSupportStatus() bool {
54+
args := m.Called()
55+
return args.Bool(0)
56+
}
57+
58+
func (m *MockAPIHandler) GetAPIOAuthAuthenticationSupportStatus() bool {
59+
args := m.Called()
60+
return args.Bool(0)
61+
}
62+
63+
func (m *MockAPIHandler) GetAPIOAuthWithCertAuthenticationSupportStatus() bool {
64+
args := m.Called()
65+
return args.Bool(0)
66+
}
67+
68+
func (m *MockAPIHandler) GetAcceptHeader() string {
69+
args := m.Called()
70+
return args.String(0)
71+
}
72+
73+
func (m *MockAPIHandler) GetContentTypeHeader(method string, log logger.Logger) string {
74+
args := m.Called(method, log)
75+
return args.String(0)
76+
}
77+
78+
func (m *MockAPIHandler) GetDefaultBaseDomain() string {
79+
args := m.Called()
80+
return args.String(0)
81+
}
82+
83+
func (m *MockAPIHandler) GetOAuthTokenEndpoint() string {
84+
args := m.Called()
85+
return args.String(0)
86+
}
87+
88+
func (m *MockAPIHandler) GetBearerTokenEndpoint() string {
89+
args := m.Called()
90+
return args.String(0)
91+
}
92+
93+
func (m *MockAPIHandler) GetTokenRefreshEndpoint() string {
94+
args := m.Called()
95+
return args.String(0)
96+
}
97+
98+
func (m *MockAPIHandler) GetTokenInvalidateEndpoint() string {
99+
args := m.Called()
100+
return args.String(0)
101+
}
102+
53103
// TestLoadAPIHandler verifies the functionality of the LoadAPIHandler function in the httpclient package.
54104
// This function is designed to return the appropriate APIHandler implementation based on the provided apiType argument.
55105
// The test cases cover the following scenarios:
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// http_request_test.go
2+
package httpclient
3+
4+
import (
5+
"bytes"
6+
"errors"
7+
"io/ioutil"
8+
"net/http"
9+
"testing"
10+
11+
"github.com/deploymenttheory/go-api-http-client/logger"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/mock"
14+
"go.uber.org/zap"
15+
)
16+
17+
// MockClient extends httpclient.Client to override methods for testing
18+
type MockClient struct {
19+
Client
20+
Mock mock.Mock
21+
}
22+
23+
// executeRequestWithRetries mock
24+
func (m *MockClient) executeRequestWithRetries(method, endpoint string, body, out interface{}, log logger.Logger) (*http.Response, error) {
25+
args := m.Mock.Called(method, endpoint, body, out, log)
26+
return args.Get(0).(*http.Response), args.Error(1)
27+
}
28+
29+
// executeRequest mock
30+
func (m *MockClient) executeRequest(method, endpoint string, body, out interface{}, log logger.Logger) (*http.Response, error) {
31+
args := m.Mock.Called(method, endpoint, body, out, log)
32+
return args.Get(0).(*http.Response), args.Error(1)
33+
}
34+
35+
func TestDoRequest(t *testing.T) {
36+
mockLogger := NewMockLogger()
37+
testClient := &MockClient{}
38+
39+
// Mock responses
40+
mockResponse := &http.Response{
41+
StatusCode: http.StatusOK,
42+
}
43+
44+
// Define test cases
45+
testCases := []struct {
46+
method string
47+
useRetries bool
48+
expectedError error
49+
}{
50+
{"GET", true, nil},
51+
{"PUT", true, nil},
52+
{"DELETE", true, nil},
53+
{"POST", false, nil},
54+
{"PATCH", false, nil},
55+
{"UNSUPPORTED", false, mockLogger.Error("HTTP method not supported", zap.String("method", "UNSUPPORTED"))},
56+
}
57+
58+
for _, tc := range testCases {
59+
t.Run(tc.method, func(t *testing.T) {
60+
if tc.useRetries {
61+
testClient.Mock.On("executeRequestWithRetries", tc.method, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockResponse, tc.expectedError)
62+
} else {
63+
testClient.Mock.On("executeRequest", tc.method, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockResponse, tc.expectedError)
64+
}
65+
66+
resp, err := testClient.DoRequest(tc.method, "/test", nil, nil, mockLogger)
67+
68+
if tc.expectedError != nil {
69+
assert.Error(t, err)
70+
} else {
71+
assert.NoError(t, err)
72+
assert.Equal(t, http.StatusOK, resp.StatusCode)
73+
}
74+
75+
if tc.useRetries {
76+
testClient.Mock.AssertCalled(t, "executeRequestWithRetries", tc.method, mock.Anything, mock.Anything, mock.Anything, mock.Anything)
77+
} else if tc.method != "UNSUPPORTED" {
78+
testClient.Mock.AssertCalled(t, "executeRequest", tc.method, mock.Anything, mock.Anything, mock.Anything, mock.Anything)
79+
}
80+
})
81+
}
82+
}
83+
84+
func TestExecuteRequestWithRetries(t *testing.T) {
85+
mockLogger := NewMockLogger()
86+
testClient := &MockClient{}
87+
88+
// Simulate transient error response
89+
transientErrorResponse := &http.Response{StatusCode: http.StatusServiceUnavailable}
90+
91+
testCases := []struct {
92+
name string
93+
response *http.Response
94+
expectedRetries int
95+
expectedError error
96+
}{
97+
{
98+
name: "TransientErrorWithRetry",
99+
response: transientErrorResponse,
100+
expectedRetries: 3, // Assuming max retry attempts is 3
101+
expectedError: nil,
102+
},
103+
// Add more test cases as needed
104+
}
105+
106+
for _, tc := range testCases {
107+
t.Run(tc.name, func(t *testing.T) {
108+
testClient.Mock.On("executeHTTPRequest", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.response, errors.New("transient error")).Times(tc.expectedRetries)
109+
testClient.Mock.On("executeHTTPRequest", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&http.Response{StatusCode: http.StatusOK}, nil).Once()
110+
111+
_, err := testClient.executeRequestWithRetries("GET", "/test", nil, nil, mockLogger)
112+
113+
if tc.expectedError != nil {
114+
assert.Error(t, err)
115+
} else {
116+
assert.NoError(t, err)
117+
}
118+
testClient.Mock.AssertNumberOfCalls(t, "executeHTTPRequest", tc.expectedRetries+1)
119+
})
120+
}
121+
}
122+
123+
// mockHTTPClient is a mock of the http.Client
124+
type mockHTTPClient struct {
125+
DoFunc func(*http.Request) (*http.Response, error)
126+
}
127+
128+
func (m *mockHTTPClient) Do(req *http.Request) (*http.Response, error) {
129+
return m.DoFunc(req)
130+
}
131+
132+
func TestHandleErrorResponse(t *testing.T) {
133+
mockLogger := NewMockLogger()
134+
client := &Client{
135+
APIHandler: NewMockAPIHandler(), // Assume NewMockAPIHandler returns a mock that satisfies your APIHandler interface
136+
}
137+
138+
// Simulate an API error response
139+
apiErrorResponse := &http.Response{
140+
StatusCode: http.StatusBadRequest,
141+
Body: ioutil.NopCloser(bytes.NewBufferString(`{"error":"bad request"}`)),
142+
}
143+
144+
err := client.handleErrorResponse(apiErrorResponse, nil, mockLogger, "POST", "/test")
145+
assert.Error(t, err)
146+
// Additional assertions based on the error handling logic in your APIHandler
147+
}

0 commit comments

Comments
 (0)