Skip to content

Commit 785bb46

Browse files
schthmstommysitu
authored andcommitted
feat: add capture-on-miss-flag
1 parent 4be8340 commit 785bb46

3 files changed

Lines changed: 95 additions & 9 deletions

File tree

core/cmd/hoverfly/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
hvc "github.com/SpectoLabs/hoverfly/core/certs"
3939
cs "github.com/SpectoLabs/hoverfly/core/cors"
4040
"github.com/SpectoLabs/hoverfly/core/handlers"
41+
v2 "github.com/SpectoLabs/hoverfly/core/handlers/v2"
4142
"github.com/SpectoLabs/hoverfly/core/matching"
4243
mw "github.com/SpectoLabs/hoverfly/core/middleware"
4344
"github.com/SpectoLabs/hoverfly/core/modes"
@@ -77,6 +78,7 @@ var (
7778
synthesize = flag.Bool("synthesize", false, "Start Hoverfly in synthesize mode (middleware is required)")
7879
modify = flag.Bool("modify", false, "Start Hoverfly in modify mode - applies middleware (required) to both outgoing and incoming HTTP traffic")
7980
spy = flag.Bool("spy", false, "Start Hoverfly in spy mode, similar to simulate but calls real server when cache miss")
81+
captureOnMiss = flag.Bool("capture-on-miss", false, "Capture requests that don't match a simulation when in spy mode")
8082
diff = flag.Bool("diff", false, "Start Hoverfly in diff mode - calls real server and compares the actual response with the expected simulation config if present")
8183
middleware = flag.String("middleware", "", "Set middleware by passing the name of the binary and the path of the middleware script separated by space. (i.e. '-middleware \"python script.py\"')")
8284
proxyPort = flag.String("pp", "", "Proxy port - run proxy on another port (i.e. '-pp 9999' to run proxy on port 9999)")
@@ -520,6 +522,15 @@ func main() {
520522
hoverfly.Authentication = authBackend
521523
hoverfly.HTTP = hv.GetDefaultHoverflyHTTPClient(hoverfly.Cfg.TLSVerification, hoverfly.Cfg.UpstreamProxy)
522524

525+
if *spy && *captureOnMiss {
526+
if err := hoverfly.SetModeWithArguments(v2.ModeView{
527+
Mode: modes.Spy,
528+
Arguments: v2.ModeArgumentsView{CaptureOnMiss: true},
529+
}); err != nil {
530+
log.WithError(err).Fatal("Failed to set spy mode with captureOnMiss")
531+
}
532+
}
533+
523534
// if add new user supplied - adding it to database
524535
if *addNew || *authEnabled {
525536
var err error

core/hoverfly_service_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,22 @@ func Test_Hoverfly_SetModeWithArguments_OverwriteDuplicate(t *testing.T) {
985985
Expect(storedMode.Arguments.OverwriteDuplicate).To(BeTrue())
986986
}
987987

988+
func Test_Hoverfly_SetModeWithArguments_SpyCaptureOnMiss(t *testing.T) {
989+
RegisterTestingT(t)
990+
991+
unit := NewHoverflyWithConfiguration(&Configuration{})
992+
993+
Expect(unit.SetModeWithArguments(v2.ModeView{
994+
Mode: "spy",
995+
Arguments: v2.ModeArgumentsView{
996+
CaptureOnMiss: true,
997+
},
998+
})).To(Succeed())
999+
1000+
storedMode := unit.modeMap[modes.Spy].View()
1001+
Expect(storedMode.Arguments.CaptureOnMiss).To(BeTrue())
1002+
}
1003+
9881004
func Test_Hoverfly_AddDiff_AddEntry(t *testing.T) {
9891005
RegisterTestingT(t)
9901006

core/modes/spy_mode_test.go

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ import (
1414
. "github.com/onsi/gomega"
1515
)
1616

17-
type hoverflySpyStub struct{}
17+
type hoverflySpyStub struct {
18+
savedRequest *models.RequestDetails
19+
savedResponse *models.ResponseDetails
20+
savedArguments *modes.ModeArguments
21+
}
1822

1923
// DoRequest - Stub implementation of modes.HoverflySpy interface
20-
func (this hoverflySpyStub) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) {
24+
func (this *hoverflySpyStub) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) {
2125
response := &http.Response{}
2226
if request.Host == "error.com" {
2327
return nil, nil, fmt.Errorf("Could not reach error.com")
@@ -30,7 +34,7 @@ func (this hoverflySpyStub) DoRequest(request *http.Request) (*http.Response, *t
3034
return response, &duration, nil
3135
}
3236

33-
func (this hoverflySpyStub) GetResponse(requestDetails models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) {
37+
func (this *hoverflySpyStub) GetResponse(requestDetails models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) {
3438
if requestDetails.Destination == "positive-match.com" {
3539
return &models.ResponseDetails{
3640
Status: 200,
@@ -42,22 +46,25 @@ func (this hoverflySpyStub) GetResponse(requestDetails models.RequestDetails) (*
4246
}
4347
}
4448

45-
func (this hoverflySpyStub) ApplyMiddleware(pair models.RequestResponsePair) (models.RequestResponsePair, error) {
49+
func (this *hoverflySpyStub) ApplyMiddleware(pair models.RequestResponsePair) (models.RequestResponsePair, error) {
4650
if pair.Request.Path == "middleware-error" {
4751
return pair, fmt.Errorf("middleware-error")
4852
}
4953
return pair, nil
5054
}
5155

52-
func (this hoverflySpyStub) Save(request *models.RequestDetails, response *models.ResponseDetails, arguments *modes.ModeArguments) error {
56+
func (this *hoverflySpyStub) Save(request *models.RequestDetails, response *models.ResponseDetails, arguments *modes.ModeArguments) error {
57+
this.savedRequest = request
58+
this.savedResponse = response
59+
this.savedArguments = arguments
5360
return nil
5461
}
5562

5663
func Test_SpyMode_WhenGivenAMatchingRequestItReturnsTheCorrectResponse(t *testing.T) {
5764
RegisterTestingT(t)
5865

5966
unit := &modes.SpyMode{
60-
Hoverfly: hoverflySpyStub{},
67+
Hoverfly: &hoverflySpyStub{},
6168
}
6269

6370
request := models.RequestDetails{
@@ -74,7 +81,7 @@ func Test_SpyMode_WhenGivenANonMatchingRequestItWillMakeTheRequestAndReturnIt(t
7481
RegisterTestingT(t)
7582

7683
unit := &modes.SpyMode{
77-
Hoverfly: hoverflySpyStub{},
84+
Hoverfly: &hoverflySpyStub{},
7885
}
7986

8087
requestDetails := models.RequestDetails{
@@ -100,7 +107,7 @@ func Test_SpyMode_WhenGivenAMatchingRequesAndMiddlewareFaislItReturnsAnError(t *
100107
RegisterTestingT(t)
101108

102109
unit := &modes.SpyMode{
103-
Hoverfly: hoverflySpyStub{},
110+
Hoverfly: &hoverflySpyStub{},
104111
}
105112

106113
request := models.RequestDetails{
@@ -124,7 +131,7 @@ func Test_SpyMode_ShouldReturnErrorOnRemoteServiceCall(t *testing.T) {
124131
RegisterTestingT(t)
125132

126133
unit := &modes.SpyMode{
127-
Hoverfly: hoverflySpyStub{},
134+
Hoverfly: &hoverflySpyStub{},
128135
}
129136

130137
requestDetails := models.RequestDetails{
@@ -147,3 +154,55 @@ func Test_SpyMode_ShouldReturnErrorOnRemoteServiceCall(t *testing.T) {
147154
Expect(string(responseBody)).To(ContainSubstring("Could not reach error.com"))
148155

149156
}
157+
158+
func Test_SpyMode_OnCacheMiss_WhenCaptureOnMissEnabled_SavesRequestAndResponse(t *testing.T) {
159+
RegisterTestingT(t)
160+
161+
stub := &hoverflySpyStub{}
162+
unit := &modes.SpyMode{
163+
Hoverfly: stub,
164+
Arguments: modes.ModeArguments{CaptureOnMiss: true},
165+
}
166+
167+
requestDetails := models.RequestDetails{
168+
Scheme: "http",
169+
Destination: "negative-match.com",
170+
}
171+
172+
request, err := http.NewRequest("GET", "http://negative-match.com", nil)
173+
Expect(err).To(BeNil())
174+
175+
result, err := unit.Process(request, requestDetails)
176+
Expect(err).To(BeNil())
177+
Expect(result.Response.StatusCode).To(Equal(200))
178+
179+
Expect(stub.savedRequest).ToNot(BeNil())
180+
Expect(stub.savedResponse).ToNot(BeNil())
181+
Expect(stub.savedResponse.Status).To(Equal(200))
182+
Expect(stub.savedResponse.Body).To(Equal("test"))
183+
}
184+
185+
func Test_SpyMode_OnCacheMiss_WhenCaptureOnMissDisabled_DoesNotSave(t *testing.T) {
186+
RegisterTestingT(t)
187+
188+
stub := &hoverflySpyStub{}
189+
unit := &modes.SpyMode{
190+
Hoverfly: stub,
191+
Arguments: modes.ModeArguments{CaptureOnMiss: false},
192+
}
193+
194+
requestDetails := models.RequestDetails{
195+
Scheme: "http",
196+
Destination: "negative-match.com",
197+
}
198+
199+
request, err := http.NewRequest("GET", "http://negative-match.com", nil)
200+
Expect(err).To(BeNil())
201+
202+
result, err := unit.Process(request, requestDetails)
203+
Expect(err).To(BeNil())
204+
Expect(result.Response.StatusCode).To(Equal(200))
205+
206+
Expect(stub.savedRequest).To(BeNil())
207+
Expect(stub.savedResponse).To(BeNil())
208+
}

0 commit comments

Comments
 (0)