Skip to content

Commit 0131b90

Browse files
Support delaying mock responses by a fixed number of milliseconds (#103)
This feature might be useful for predicting the response time of a handler. When using the Debug(...) helper the total time of the handler is printed to the console. It might be desirable to only use this during experiments and to not run this config in CI. This is why the global option must be enabled to turn this on.
1 parent 24daced commit 0131b90

File tree

6 files changed

+73
-42
lines changed

6 files changed

+73
-42
lines changed

apitest.go

+28-20
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,27 @@ var responseDebugPrefix = fmt.Sprintf("<%s", divider)
3030

3131
// APITest is the top level struct holding the test spec
3232
type APITest struct {
33-
debugEnabled bool
34-
networkingEnabled bool
35-
networkingHTTPClient *http.Client
36-
reporter ReportFormatter
37-
verifier Verifier
38-
recorder *Recorder
39-
handler http.Handler
40-
name string
41-
request *Request
42-
response *Response
43-
observers []Observe
44-
mocksObservers []Observe
45-
recorderHook RecorderHook
46-
mocks []*Mock
47-
t *testing.T
48-
httpClient *http.Client
49-
transport *Transport
50-
meta map[string]interface{}
51-
started time.Time
52-
finished time.Time
33+
debugEnabled bool
34+
mockResponseDelayEnabled bool
35+
networkingEnabled bool
36+
networkingHTTPClient *http.Client
37+
reporter ReportFormatter
38+
verifier Verifier
39+
recorder *Recorder
40+
handler http.Handler
41+
name string
42+
request *Request
43+
response *Response
44+
observers []Observe
45+
mocksObservers []Observe
46+
recorderHook RecorderHook
47+
mocks []*Mock
48+
t *testing.T
49+
httpClient *http.Client
50+
transport *Transport
51+
meta map[string]interface{}
52+
started time.Time
53+
finished time.Time
5354
}
5455

5556
// InboundRequest used to wrap the incoming request with a timestamp
@@ -107,6 +108,12 @@ func (a *APITest) EnableNetworking(cli ...*http.Client) *APITest {
107108
return a
108109
}
109110

111+
// EnableMockResponseDelay turns on mock response delays (defaults to OFF)
112+
func (a *APITest) EnableMockResponseDelay() *APITest {
113+
a.mockResponseDelayEnabled = true
114+
return a
115+
}
116+
110117
// Debug logs to the console the http wire representation of all http interactions that are intercepted by apitest. This includes the inbound request to the application under test, the response returned by the application and any interactions that are intercepted by the mock server.
111118
func (a *APITest) Debug() *APITest {
112119
a.debugEnabled = true
@@ -761,6 +768,7 @@ func (r *Response) runTest() *http.Response {
761768
a.mocks,
762769
a.httpClient,
763770
a.debugEnabled,
771+
a.mockResponseDelayEnabled,
764772
a.mocksObservers,
765773
r.apiTest,
766774
)

examples/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ require (
3636
github.com/mattn/go-colorable v0.1.6 // indirect
3737
github.com/mattn/go-sqlite3 v2.0.3+incompatible
3838
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
39-
github.com/mitchellh/mapstructure v1.3.3
39+
github.com/mitchellh/mapstructure v1.3.3 // indirect
4040
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4141
github.com/modern-go/reflect2 v1.0.1 // indirect
4242
github.com/moul/http2curl v1.0.0 // indirect

examples/go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
214214
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
215215
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
216216
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
217-
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
218-
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
217+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
218+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
219219
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
220220
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
221221
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=

go.sum

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
44
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
55
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
66
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7-
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
8-
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
7+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
98
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
109
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1110
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

mocks.go

+36-17
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,35 @@ import (
1515
"sort"
1616
"strings"
1717
"sync"
18+
"time"
1819
)
1920

2021
// Transport wraps components used to observe and manipulate the real request and response objects
2122
type Transport struct {
22-
debugEnabled bool
23-
mocks []*Mock
24-
nativeTransport http.RoundTripper
25-
httpClient *http.Client
26-
observers []Observe
27-
apiTest *APITest
23+
debugEnabled bool
24+
mockResponseDelayEnabled bool
25+
mocks []*Mock
26+
nativeTransport http.RoundTripper
27+
httpClient *http.Client
28+
observers []Observe
29+
apiTest *APITest
2830
}
2931

3032
func newTransport(
3133
mocks []*Mock,
3234
httpClient *http.Client,
3335
debugEnabled bool,
36+
mockResponseDelayEnabled bool,
3437
observers []Observe,
3538
apiTest *APITest) *Transport {
3639

3740
t := &Transport{
38-
mocks: mocks,
39-
httpClient: httpClient,
40-
debugEnabled: debugEnabled,
41-
observers: observers,
42-
apiTest: apiTest,
41+
mocks: mocks,
42+
httpClient: httpClient,
43+
debugEnabled: debugEnabled,
44+
mockResponseDelayEnabled: mockResponseDelayEnabled,
45+
observers: observers,
46+
apiTest: apiTest,
4347
}
4448
if httpClient != nil {
4549
t.nativeTransport = httpClient.Transport
@@ -114,6 +118,10 @@ func (r *Transport) RoundTrip(req *http.Request) (mockResponse *http.Response, m
114118
return nil, timeoutError{}
115119
}
116120

121+
if r.mockResponseDelayEnabled && matchedResponse.fixedDelayMillis > 0 {
122+
time.Sleep(time.Duration(matchedResponse.fixedDelayMillis) * time.Millisecond)
123+
}
124+
117125
return res, nil
118126
}
119127

@@ -268,12 +276,13 @@ type UnmatchedMock struct {
268276

269277
// MockResponse represents the http response side of a mock interaction
270278
type MockResponse struct {
271-
mock *Mock
272-
timeout bool
273-
headers map[string][]string
274-
cookies []*Cookie
275-
body string
276-
statusCode int
279+
mock *Mock
280+
timeout bool
281+
headers map[string][]string
282+
cookies []*Cookie
283+
body string
284+
statusCode int
285+
fixedDelayMillis int64
277286
}
278287

279288
// StandaloneMocks for using mocks outside of API tests context
@@ -308,6 +317,7 @@ func (r *StandaloneMocks) End() func() {
308317
r.mocks,
309318
r.httpClient,
310319
r.debug,
320+
false,
311321
nil,
312322
nil,
313323
)
@@ -653,6 +663,14 @@ func (r *MockResponse) Status(statusCode int) *MockResponse {
653663
return r
654664
}
655665

666+
// FixedDelay will return the response after the given number of milliseconds.
667+
// APITest::EnableMockResponseDelay must be set for this to take effect.
668+
// If Timeout is set this has no effect.
669+
func (r *MockResponse) FixedDelay(delay int64) *MockResponse {
670+
r.fixedDelayMillis = delay
671+
return r
672+
}
673+
656674
// Times respond the given number of times
657675
func (r *MockResponse) Times(times int) *MockResponse {
658676
r.mock.times = times
@@ -671,6 +689,7 @@ func (r *MockResponse) EndStandalone(other ...*Mock) func() {
671689
append([]*Mock{r.mock}, other...),
672690
r.mock.httpClient,
673691
r.mock.debugStandalone,
692+
false,
674693
nil,
675694
nil,
676695
)

mocks_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,7 @@ func TestMocks_ApiTest_WithMocks(t *testing.T) {
11041104
Get("/user").
11051105
RespondWith().
11061106
Body(`{"name": "jon", "id": "1234"}`).
1107+
FixedDelay(5000).
11071108
Status(http.StatusOK).
11081109
End()
11091110

@@ -1194,10 +1195,12 @@ func TestMocks_ApiTest_SupportsObservingMocksWithReport(t *testing.T) {
11941195
RespondWith().
11951196
Status(http.StatusOK).
11961197
Body("2").
1198+
FixedDelay(1000).
11971199
End()
11981200

11991201
New().
12001202
Report(reporter).
1203+
EnableMockResponseDelay().
12011204
ObserveMocks(func(res *http.Response, req *http.Request, a *APITest) {
12021205
observeMocksCalled = true
12031206
if res == nil || req == nil || a == nil {
@@ -1228,6 +1231,8 @@ func TestMocks_ApiTest_SupportsObservingMocksWithReport(t *testing.T) {
12281231

12291232
assert.Equal(t, 3, len(observedMocks))
12301233
assert.True(t, observeMocksCalled)
1234+
oneSecondInNanoSecs := int64(1000000000)
1235+
assert.Greater(t, reporter.capturedRecorder.Meta["duration"], oneSecondInNanoSecs)
12311236
}
12321237

12331238
func TestMocks_ApiTest_SupportsMultipleMocks(t *testing.T) {

0 commit comments

Comments
 (0)