From 2c0849a154127d3f091ee6664ecd10227713a182 Mon Sep 17 00:00:00 2001 From: kapishmalik Date: Tue, 8 Oct 2024 20:55:21 +0530 Subject: [PATCH 1/4] capture delay along with response --- core/hoverfly_funcs.go | 12 +++++++----- core/hoverfly_funcs_test.go | 5 +++-- core/modes/capture_mode.go | 13 ++++++++----- core/modes/capture_mode_test.go | 8 +++++--- core/modes/diff_mode.go | 14 ++++++++------ core/modes/diff_mode_test.go | 16 +++++++++------- core/modes/modify_mode.go | 13 ++++++++----- core/modes/modify_mode_test.go | 8 +++++--- core/modes/spy_mode.go | 13 ++++++++----- core/modes/spy_mode_test.go | 8 +++++--- functional-tests/core/ft_capture_mode_test.go | 12 ++++++------ 11 files changed, 72 insertions(+), 50 deletions(-) diff --git a/core/hoverfly_funcs.go b/core/hoverfly_funcs.go index da97baa6a..66c483c64 100644 --- a/core/hoverfly_funcs.go +++ b/core/hoverfly_funcs.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/SpectoLabs/hoverfly/core/errors" v2 "github.com/SpectoLabs/hoverfly/core/handlers/v2" @@ -19,19 +20,20 @@ import ( ) // DoRequest - performs request and returns response that should be returned to client and error -func (hf *Hoverfly) DoRequest(request *http.Request) (*http.Response, error) { +func (hf *Hoverfly) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) { // We can't have this set. And it only contains "/pkg/net/http/" anyway request.RequestURI = "" client, err := GetHttpClient(hf, request.Host) if err != nil { - return nil, err + return nil, nil, err } + start := time.Now() resp, err := client.Do(request) if err != nil { - return nil, err + return nil, nil, err } resp.Header.Set("Hoverfly", "Was-Here") @@ -40,8 +42,8 @@ func (hf *Hoverfly) DoRequest(request *http.Request) (*http.Response, error) { resp.Header.Add("Hoverfly", "Forwarded") } - return resp, nil - + elapsed := time.Since(start) + return resp, &elapsed, nil } // GetResponse returns stored response from cache diff --git a/core/hoverfly_funcs_test.go b/core/hoverfly_funcs_test.go index 5cf4f2b2f..cb8ca6d1b 100644 --- a/core/hoverfly_funcs_test.go +++ b/core/hoverfly_funcs_test.go @@ -26,8 +26,9 @@ func Test_Hoverfly_DoRequest_DoesNotPanicWhenCannotMakeRequest(t *testing.T) { request, err := http.NewRequest("GET", "w.specto.fake", ioutil.NopCloser(bytes.NewBuffer([]byte("")))) Expect(err).To(BeNil()) - response, err := unit.DoRequest(request) + response, time, err := unit.DoRequest(request) Expect(response).To(BeNil()) + Expect(time).To(BeNil()) Expect(err).ToNot(BeNil()) } @@ -43,7 +44,7 @@ func Test_Hoverfly_DoRequest_FailedHTTP(t *testing.T) { req, err := http.NewRequest("POST", "http://capture_body.com", body) Expect(err).To(BeNil()) - _, err = unit.DoRequest(req) + _, _, err = unit.DoRequest(req) Expect(err).ToNot(BeNil()) } diff --git a/core/modes/capture_mode.go b/core/modes/capture_mode.go index c4f812556..eb7f2b723 100644 --- a/core/modes/capture_mode.go +++ b/core/modes/capture_mode.go @@ -3,7 +3,9 @@ package modes import ( "bytes" "io/ioutil" + "math" "net/http" + "time" "github.com/SpectoLabs/hoverfly/core/models" "github.com/SpectoLabs/hoverfly/core/util" @@ -14,7 +16,7 @@ import ( type HoverflyCapture interface { ApplyMiddleware(models.RequestResponsePair) (models.RequestResponsePair, error) - DoRequest(*http.Request) (*http.Response, error) + DoRequest(*http.Request) (*http.Response, *time.Duration, error) Save(*models.RequestDetails, *models.ResponseDetails, *ModeArguments) error } @@ -59,7 +61,7 @@ func (this CaptureMode) Process(request *http.Request, details models.RequestDet return ReturnErrorAndLog(request, err, &pair, "There was an error when preparing request for pass through", Capture) } - response, err := this.Hoverfly.DoRequest(modifiedRequest) + response, duration, err := this.Hoverfly.DoRequest(modifiedRequest) if err != nil { return ReturnErrorAndLog(request, err, &pair, "There was an error when forwarding the request to the intended destination", Capture) } @@ -68,9 +70,10 @@ func (this CaptureMode) Process(request *http.Request, details models.RequestDet respHeaders := util.GetResponseHeaders(response) responseObj := &models.ResponseDetails{ - Status: response.StatusCode, - Body: respBody, - Headers: respHeaders, + Status: response.StatusCode, + Body: respBody, + Headers: respHeaders, + FixedDelay: int(math.Ceil(duration.Seconds())), } if this.Arguments.Headers == nil { diff --git a/core/modes/capture_mode_test.go b/core/modes/capture_mode_test.go index efc97b1a9..007a4d1f6 100644 --- a/core/modes/capture_mode_test.go +++ b/core/modes/capture_mode_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" "testing" + "time" "github.com/SpectoLabs/hoverfly/core/models" "github.com/SpectoLabs/hoverfly/core/modes" @@ -25,10 +26,10 @@ func (this hoverflyCaptureStub) ApplyMiddleware(pair models.RequestResponsePair) } // DoRequest - Stub implementation of modes.HoverflyCapture interface -func (this hoverflyCaptureStub) DoRequest(request *http.Request) (*http.Response, error) { +func (this hoverflyCaptureStub) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) { response := &http.Response{} if request.Host == "error.com" { - return nil, errors.New("Could not reach error.com") + return nil, nil, errors.New("Could not reach error.com") } response.StatusCode = 200 @@ -42,7 +43,8 @@ func (this hoverflyCaptureStub) DoRequest(request *http.Request) (*http.Response response.Trailer.Set("X-Bin-Id", "xyz") } - return response, nil + duration := 1 * time.Second + return response, &duration, nil } // Save - Stub implementation of modes.HoverflyCapture interface diff --git a/core/modes/diff_mode.go b/core/modes/diff_mode.go index 03415a556..5426f40cc 100644 --- a/core/modes/diff_mode.go +++ b/core/modes/diff_mode.go @@ -14,6 +14,7 @@ import ( log "github.com/sirupsen/logrus" "io" "io/ioutil" + "math" "net/http" "reflect" "time" @@ -21,7 +22,7 @@ import ( type HoverflyDiff interface { GetResponse(models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) - DoRequest(*http.Request) (*http.Response, error) + DoRequest(*http.Request) (*http.Response, *time.Duration, error) AddDiff(requestView v2.SimpleRequestDefinitionView, diffReport v2.DiffReport) } @@ -44,7 +45,7 @@ func (this *DiffMode) SetArguments(arguments ModeArguments) { this.Arguments = arguments } -//TODO: We should only need one of these two parameters +// TODO: We should only need one of these two parameters func (this *DiffMode) Process(request *http.Request, details models.RequestDetails) (ProcessResult, error) { this.DiffReport = v2.DiffReport{Timestamp: time.Now().Format(time.RFC3339)} @@ -60,7 +61,7 @@ func (this *DiffMode) Process(request *http.Request, details models.RequestDetai return ReturnErrorAndLog(request, err, &actualPair, "There was an error when reconstructing the request.", Diff) } - actualResponse, err := this.Hoverfly.DoRequest(modifiedRequest) + actualResponse, duration, err := this.Hoverfly.DoRequest(modifiedRequest) if err != nil { return ReturnErrorAndLog(request, err, &actualPair, "There was an error when forwarding the request to the intended destination", Diff) } @@ -74,9 +75,10 @@ func (this *DiffMode) Process(request *http.Request, details models.RequestDetai respHeaders := util.GetResponseHeaders(actualResponse) actualResponseDetails := &models.ResponseDetails{ - Status: actualResponse.StatusCode, - Body: respBody, - Headers: respHeaders, + Status: actualResponse.StatusCode, + Body: respBody, + Headers: respHeaders, + FixedDelay: int(math.Ceil(duration.Seconds())), } this.diffResponse(simResponse, actualResponseDetails, this.Arguments.Headers) diff --git a/core/modes/diff_mode_test.go b/core/modes/diff_mode_test.go index 44eef9bd2..e9c5cc5a1 100644 --- a/core/modes/diff_mode_test.go +++ b/core/modes/diff_mode_test.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "net/http" "testing" + "time" "bytes" "encoding/json" @@ -17,40 +18,41 @@ import ( type hoverflyDiffStub struct{} -func (this hoverflyDiffStub) DoRequest(request *http.Request) (*http.Response, error) { +func (this hoverflyDiffStub) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) { + duration := 1 * time.Second switch request.Host { case "error.com": - return nil, fmt.Errorf("Could not reach error.com") + return nil, nil, fmt.Errorf("Could not reach error.com") case "positive-match-with-same-response.com": return &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString("expected")), Header: map[string][]string{"header": {"expected"}, "source": {"service"}}, - }, nil + }, &duration, nil case "positive-match-with-different-response.com": return &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString("actual")), Header: map[string][]string{"header": {"actual"}, "source": {"service"}}, - }, nil + }, &duration, nil case "negative-match.com": return &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString("actual")), Header: map[string][]string{"header": {"actual"}, "source": {"service"}}, - }, nil + }, &duration, nil case "positive-match-with-different-trailers.com": return &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString("actual")), Header: map[string][]string{"header": {"actual"}}, Trailer: map[string][]string{"trailer1": {"actual"}}, - }, nil + }, &duration, nil default: return &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString("test")), - }, nil + }, &duration, nil } } diff --git a/core/modes/modify_mode.go b/core/modes/modify_mode.go index 4ec4bef3b..89dff0954 100644 --- a/core/modes/modify_mode.go +++ b/core/modes/modify_mode.go @@ -2,7 +2,9 @@ package modes import ( "io/ioutil" + "math" "net/http" + "time" "github.com/SpectoLabs/hoverfly/core/handlers/v2" "github.com/SpectoLabs/hoverfly/core/models" @@ -10,7 +12,7 @@ import ( type HoverflyModify interface { ApplyMiddleware(models.RequestResponsePair) (models.RequestResponsePair, error) - DoRequest(*http.Request) (*http.Response, error) + DoRequest(*http.Request) (*http.Response, *time.Duration, error) } type ModifyMode struct { @@ -36,7 +38,7 @@ func (this ModifyMode) Process(request *http.Request, details models.RequestDeta return ReturnErrorAndLog(request, err, &pair, "There was an error when rebuilding the modified http request", Modify) } - resp, err := this.Hoverfly.DoRequest(modifiedRequest) + resp, duration, err := this.Hoverfly.DoRequest(modifiedRequest) if err != nil { return ReturnErrorAndLog(request, err, &pair, "There was an error when forwarding the request to the intended destination", Modify) } @@ -47,9 +49,10 @@ func (this ModifyMode) Process(request *http.Request, details models.RequestDeta } pair.Response = models.ResponseDetails{ - Status: resp.StatusCode, - Body: string(bodyBytes), - Headers: resp.Header, + Status: resp.StatusCode, + Body: string(bodyBytes), + Headers: resp.Header, + FixedDelay: int(math.Ceil(duration.Seconds())), } pair, err = this.Hoverfly.ApplyMiddleware(pair) diff --git a/core/modes/modify_mode_test.go b/core/modes/modify_mode_test.go index e98c27845..a40347439 100644 --- a/core/modes/modify_mode_test.go +++ b/core/modes/modify_mode_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" "testing" + "time" "github.com/SpectoLabs/hoverfly/core/models" "github.com/SpectoLabs/hoverfly/core/modes" @@ -14,10 +15,10 @@ import ( type hoverflyModifyStub struct{} -func (this hoverflyModifyStub) DoRequest(request *http.Request) (*http.Response, error) { +func (this hoverflyModifyStub) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) { response := &http.Response{} if request.Host == "error.com" { - return nil, errors.New("Could not reach error.com") + return nil, nil, errors.New("Could not reach error.com") } request.Host = "modified.com" @@ -25,7 +26,8 @@ func (this hoverflyModifyStub) DoRequest(request *http.Request) (*http.Response, response.StatusCode = 200 response.Body = ioutil.NopCloser(bytes.NewBufferString("test")) - return response, nil + duration := 1 * time.Second + return response, &duration, nil } func (this hoverflyModifyStub) ApplyMiddleware(pair models.RequestResponsePair) (models.RequestResponsePair, error) { diff --git a/core/modes/spy_mode.go b/core/modes/spy_mode.go index 18166fc06..8e9fb8c8e 100644 --- a/core/modes/spy_mode.go +++ b/core/modes/spy_mode.go @@ -1,7 +1,9 @@ package modes import ( + "math" "net/http" + "time" "github.com/SpectoLabs/hoverfly/core/errors" v2 "github.com/SpectoLabs/hoverfly/core/handlers/v2" @@ -15,7 +17,7 @@ import ( type HoverflySpy interface { GetResponse(models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) ApplyMiddleware(models.RequestResponsePair) (models.RequestResponsePair, error) - DoRequest(*http.Request) (*http.Response, error) + DoRequest(*http.Request) (*http.Response, *time.Duration, error) Save(*models.RequestDetails, *models.ResponseDetails, *ModeArguments) error } @@ -67,7 +69,7 @@ func (this SpyMode) Process(request *http.Request, details models.RequestDetails if err != nil { return ReturnErrorAndLog(request, err, &pair, "There was an error when reconstructing the request.", Spy) } - response, err := this.Hoverfly.DoRequest(modifiedRequest) + response, duration, err := this.Hoverfly.DoRequest(modifiedRequest) if err == nil { if this.Arguments.CaptureOnMiss { @@ -75,9 +77,10 @@ func (this SpyMode) Process(request *http.Request, details models.RequestDetails respHeaders := util.GetResponseHeaders(response) responseObj := &models.ResponseDetails{ - Status: response.StatusCode, - Body: respBody, - Headers: respHeaders, + Status: response.StatusCode, + Body: respBody, + Headers: respHeaders, + FixedDelay: int(math.Ceil(duration.Seconds())), } if this.Arguments.Headers == nil { this.Arguments.Headers = []string{} diff --git a/core/modes/spy_mode_test.go b/core/modes/spy_mode_test.go index b43ff614f..d2ee50110 100644 --- a/core/modes/spy_mode_test.go +++ b/core/modes/spy_mode_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" "testing" + "time" "github.com/SpectoLabs/hoverfly/core/errors" "github.com/SpectoLabs/hoverfly/core/models" @@ -16,16 +17,17 @@ import ( type hoverflySpyStub struct{} // DoRequest - Stub implementation of modes.HoverflySpy interface -func (this hoverflySpyStub) DoRequest(request *http.Request) (*http.Response, error) { +func (this hoverflySpyStub) DoRequest(request *http.Request) (*http.Response, *time.Duration, error) { response := &http.Response{} if request.Host == "error.com" { - return nil, fmt.Errorf("Could not reach error.com") + return nil, nil, fmt.Errorf("Could not reach error.com") } response.StatusCode = 200 response.Body = ioutil.NopCloser(bytes.NewBufferString("test")) - return response, nil + duration := 1 * time.Second + return response, &duration, nil } func (this hoverflySpyStub) GetResponse(requestDetails models.RequestDetails) (*models.ResponseDetails, *errors.HoverflyError) { diff --git a/functional-tests/core/ft_capture_mode_test.go b/functional-tests/core/ft_capture_mode_test.go index bde93b5a8..91fa9ca37 100644 --- a/functional-tests/core/ft_capture_mode_test.go +++ b/functional-tests/core/ft_capture_mode_test.go @@ -22,10 +22,9 @@ import ( type FormData struct { FirstName string `url:"first_name"` - LastName string `url:"last_name"` + LastName string `url:"last_name"` } - var _ = Describe("When I run Hoverfly", func() { var ( @@ -111,7 +110,8 @@ var _ = Describe("When I run Hoverfly", func() { "Date": {"date"}, "Hoverfly": {"Was-Here"}, }, - Templated: false, + FixedDelay: 1, + Templated: false, })) }) @@ -455,7 +455,6 @@ var _ = Describe("When I run Hoverfly", func() { LastName: "Doe", } - resp := hoverfly.Proxy(sling.New().Post(fakeServer.URL).BodyForm(formData)) Expect(resp.StatusCode).To(Equal(200)) @@ -494,7 +493,7 @@ var _ = Describe("When I run Hoverfly", func() { { Matcher: "form", Value: map[string]interface{}{ - "first_name":[]interface{}{ + "first_name": []interface{}{ map[string]interface{}{ "matcher": matchers.Exact, "value": "John", @@ -521,7 +520,8 @@ var _ = Describe("When I run Hoverfly", func() { "Date": {"date"}, "Hoverfly": {"Was-Here"}, }, - Templated: false, + FixedDelay: 1, + Templated: false, })) }) From 14e9197acfa4f446e83aaf5e3244a3489edcdc68 Mon Sep 17 00:00:00 2001 From: kapishmalik Date: Tue, 8 Oct 2024 21:07:28 +0530 Subject: [PATCH 2/4] convert delay to ms --- core/modes/capture_mode.go | 3 +-- core/modes/diff_mode.go | 3 +-- core/modes/modify_mode.go | 3 +-- core/modes/spy_mode.go | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/modes/capture_mode.go b/core/modes/capture_mode.go index eb7f2b723..2040103ca 100644 --- a/core/modes/capture_mode.go +++ b/core/modes/capture_mode.go @@ -3,7 +3,6 @@ package modes import ( "bytes" "io/ioutil" - "math" "net/http" "time" @@ -73,7 +72,7 @@ func (this CaptureMode) Process(request *http.Request, details models.RequestDet Status: response.StatusCode, Body: respBody, Headers: respHeaders, - FixedDelay: int(math.Ceil(duration.Seconds())), + FixedDelay: int(duration.Milliseconds()), } if this.Arguments.Headers == nil { diff --git a/core/modes/diff_mode.go b/core/modes/diff_mode.go index 5426f40cc..43b2e5516 100644 --- a/core/modes/diff_mode.go +++ b/core/modes/diff_mode.go @@ -14,7 +14,6 @@ import ( log "github.com/sirupsen/logrus" "io" "io/ioutil" - "math" "net/http" "reflect" "time" @@ -78,7 +77,7 @@ func (this *DiffMode) Process(request *http.Request, details models.RequestDetai Status: actualResponse.StatusCode, Body: respBody, Headers: respHeaders, - FixedDelay: int(math.Ceil(duration.Seconds())), + FixedDelay: int(duration.Milliseconds()), } this.diffResponse(simResponse, actualResponseDetails, this.Arguments.Headers) diff --git a/core/modes/modify_mode.go b/core/modes/modify_mode.go index 89dff0954..e5b443a2e 100644 --- a/core/modes/modify_mode.go +++ b/core/modes/modify_mode.go @@ -2,7 +2,6 @@ package modes import ( "io/ioutil" - "math" "net/http" "time" @@ -52,7 +51,7 @@ func (this ModifyMode) Process(request *http.Request, details models.RequestDeta Status: resp.StatusCode, Body: string(bodyBytes), Headers: resp.Header, - FixedDelay: int(math.Ceil(duration.Seconds())), + FixedDelay: int(duration.Milliseconds()), } pair, err = this.Hoverfly.ApplyMiddleware(pair) diff --git a/core/modes/spy_mode.go b/core/modes/spy_mode.go index 8e9fb8c8e..75eb29248 100644 --- a/core/modes/spy_mode.go +++ b/core/modes/spy_mode.go @@ -1,7 +1,6 @@ package modes import ( - "math" "net/http" "time" @@ -80,7 +79,7 @@ func (this SpyMode) Process(request *http.Request, details models.RequestDetails Status: response.StatusCode, Body: respBody, Headers: respHeaders, - FixedDelay: int(math.Ceil(duration.Seconds())), + FixedDelay: int(duration.Milliseconds()), } if this.Arguments.Headers == nil { this.Arguments.Headers = []string{} From 61cb8f852b0d5dfc9f3f2cd1c71f9f59da699d5b Mon Sep 17 00:00:00 2001 From: kapishmalik Date: Tue, 8 Oct 2024 21:11:18 +0530 Subject: [PATCH 3/4] revert test changes --- functional-tests/core/ft_capture_mode_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/functional-tests/core/ft_capture_mode_test.go b/functional-tests/core/ft_capture_mode_test.go index 91fa9ca37..74fd0eeb4 100644 --- a/functional-tests/core/ft_capture_mode_test.go +++ b/functional-tests/core/ft_capture_mode_test.go @@ -110,8 +110,7 @@ var _ = Describe("When I run Hoverfly", func() { "Date": {"date"}, "Hoverfly": {"Was-Here"}, }, - FixedDelay: 1, - Templated: false, + Templated: false, })) }) @@ -520,8 +519,7 @@ var _ = Describe("When I run Hoverfly", func() { "Date": {"date"}, "Hoverfly": {"Was-Here"}, }, - FixedDelay: 1, - Templated: false, + Templated: false, })) }) From 953bdf65df7a02bcec351aaae6799609a50bacf8 Mon Sep 17 00:00:00 2001 From: kapishmalik Date: Thu, 10 Oct 2024 23:59:25 +0530 Subject: [PATCH 4/4] review comment changes --- core/handlers/v2/views.go | 1 + core/hoverfly_funcs.go | 2 +- core/hoverfly_service.go | 1 + core/modes/capture_mode.go | 8 +++++++- core/modes/diff_mode.go | 9 ++++----- core/modes/modes.go | 1 + core/modes/modify_mode.go | 9 ++++----- core/modes/spy_mode.go | 9 +++++++-- hoverctl/cmd/mode.go | 10 ++++++++++ 9 files changed, 36 insertions(+), 14 deletions(-) diff --git a/core/handlers/v2/views.go b/core/handlers/v2/views.go index c7feb994e..b29a419ed 100644 --- a/core/handlers/v2/views.go +++ b/core/handlers/v2/views.go @@ -39,6 +39,7 @@ type ModeArgumentsView struct { Stateful bool `json:"stateful,omitempty"` OverwriteDuplicate bool `json:"overwriteDuplicate,omitempty"` CaptureOnMiss bool `json:"captureOnMiss,omitempty"` + CaptureDelay bool `json:"captureDelay,omitempty"` } type IsWebServerView struct { diff --git a/core/hoverfly_funcs.go b/core/hoverfly_funcs.go index 66c483c64..f6e5824bc 100644 --- a/core/hoverfly_funcs.go +++ b/core/hoverfly_funcs.go @@ -31,6 +31,7 @@ func (hf *Hoverfly) DoRequest(request *http.Request) (*http.Response, *time.Dura } start := time.Now() resp, err := client.Do(request) + elapsed := time.Since(start) if err != nil { return nil, nil, err @@ -42,7 +43,6 @@ func (hf *Hoverfly) DoRequest(request *http.Request) (*http.Response, *time.Dura resp.Header.Add("Hoverfly", "Forwarded") } - elapsed := time.Since(start) return resp, &elapsed, nil } diff --git a/core/hoverfly_service.go b/core/hoverfly_service.go index cd9b33c67..2533fde61 100644 --- a/core/hoverfly_service.go +++ b/core/hoverfly_service.go @@ -109,6 +109,7 @@ func (hf *Hoverfly) SetModeWithArguments(modeView v2.ModeView) error { Stateful: modeView.Arguments.Stateful, OverwriteDuplicate: modeView.Arguments.OverwriteDuplicate, CaptureOnMiss: modeView.Arguments.CaptureOnMiss, + CaptureDelay: modeView.Arguments.CaptureDelay, } hf.modeMap[hf.Cfg.GetMode()].SetArguments(modeArguments) diff --git a/core/modes/capture_mode.go b/core/modes/capture_mode.go index 2040103ca..25f4c1a4e 100644 --- a/core/modes/capture_mode.go +++ b/core/modes/capture_mode.go @@ -31,6 +31,7 @@ func (this *CaptureMode) View() v2.ModeView { Headers: this.Arguments.Headers, Stateful: this.Arguments.Stateful, OverwriteDuplicate: this.Arguments.OverwriteDuplicate, + CaptureDelay: this.Arguments.CaptureDelay, }, } } @@ -68,11 +69,16 @@ func (this CaptureMode) Process(request *http.Request, details models.RequestDet respBody, _ := util.GetResponseBody(response) respHeaders := util.GetResponseHeaders(response) + delayInMs := 0 + if this.Arguments.CaptureDelay { + delayInMs = int(duration.Milliseconds()) + } + responseObj := &models.ResponseDetails{ Status: response.StatusCode, Body: respBody, Headers: respHeaders, - FixedDelay: int(duration.Milliseconds()), + FixedDelay: delayInMs, } if this.Arguments.Headers == nil { diff --git a/core/modes/diff_mode.go b/core/modes/diff_mode.go index 43b2e5516..1db97dbd4 100644 --- a/core/modes/diff_mode.go +++ b/core/modes/diff_mode.go @@ -60,7 +60,7 @@ func (this *DiffMode) Process(request *http.Request, details models.RequestDetai return ReturnErrorAndLog(request, err, &actualPair, "There was an error when reconstructing the request.", Diff) } - actualResponse, duration, err := this.Hoverfly.DoRequest(modifiedRequest) + actualResponse, _, err := this.Hoverfly.DoRequest(modifiedRequest) if err != nil { return ReturnErrorAndLog(request, err, &actualPair, "There was an error when forwarding the request to the intended destination", Diff) } @@ -74,10 +74,9 @@ func (this *DiffMode) Process(request *http.Request, details models.RequestDetai respHeaders := util.GetResponseHeaders(actualResponse) actualResponseDetails := &models.ResponseDetails{ - Status: actualResponse.StatusCode, - Body: respBody, - Headers: respHeaders, - FixedDelay: int(duration.Milliseconds()), + Status: actualResponse.StatusCode, + Body: respBody, + Headers: respHeaders, } this.diffResponse(simResponse, actualResponseDetails, this.Arguments.Headers) diff --git a/core/modes/modes.go b/core/modes/modes.go index 36468cf84..8d8d2c634 100644 --- a/core/modes/modes.go +++ b/core/modes/modes.go @@ -46,6 +46,7 @@ type ModeArguments struct { Stateful bool OverwriteDuplicate bool CaptureOnMiss bool + CaptureDelay bool } type ProcessResult struct { diff --git a/core/modes/modify_mode.go b/core/modes/modify_mode.go index e5b443a2e..ae5c25614 100644 --- a/core/modes/modify_mode.go +++ b/core/modes/modify_mode.go @@ -37,7 +37,7 @@ func (this ModifyMode) Process(request *http.Request, details models.RequestDeta return ReturnErrorAndLog(request, err, &pair, "There was an error when rebuilding the modified http request", Modify) } - resp, duration, err := this.Hoverfly.DoRequest(modifiedRequest) + resp, _, err := this.Hoverfly.DoRequest(modifiedRequest) if err != nil { return ReturnErrorAndLog(request, err, &pair, "There was an error when forwarding the request to the intended destination", Modify) } @@ -48,10 +48,9 @@ func (this ModifyMode) Process(request *http.Request, details models.RequestDeta } pair.Response = models.ResponseDetails{ - Status: resp.StatusCode, - Body: string(bodyBytes), - Headers: resp.Header, - FixedDelay: int(duration.Milliseconds()), + Status: resp.StatusCode, + Body: string(bodyBytes), + Headers: resp.Header, } pair, err = this.Hoverfly.ApplyMiddleware(pair) diff --git a/core/modes/spy_mode.go b/core/modes/spy_mode.go index 75eb29248..f31f05d99 100644 --- a/core/modes/spy_mode.go +++ b/core/modes/spy_mode.go @@ -34,6 +34,7 @@ func (this *SpyMode) View() v2.ModeView { Stateful: this.Arguments.Stateful, Headers: this.Arguments.Headers, OverwriteDuplicate: this.Arguments.OverwriteDuplicate, + CaptureDelay: this.Arguments.CaptureDelay, }, } } @@ -51,6 +52,7 @@ func (this *SpyMode) SetArguments(arguments ModeArguments) { Stateful: arguments.Stateful, OverwriteDuplicate: arguments.OverwriteDuplicate, CaptureOnMiss: arguments.CaptureOnMiss, + CaptureDelay: arguments.CaptureDelay, } } @@ -74,12 +76,15 @@ func (this SpyMode) Process(request *http.Request, details models.RequestDetails if this.Arguments.CaptureOnMiss { respBody, _ := util.GetResponseBody(response) respHeaders := util.GetResponseHeaders(response) - + delayInMs := 0 + if this.Arguments.CaptureDelay { + delayInMs = int(duration.Milliseconds()) + } responseObj := &models.ResponseDetails{ Status: response.StatusCode, Body: respBody, Headers: respHeaders, - FixedDelay: int(duration.Milliseconds()), + FixedDelay: delayInMs, } if this.Arguments.Headers == nil { this.Arguments.Headers = []string{} diff --git a/hoverctl/cmd/mode.go b/hoverctl/cmd/mode.go index 5795c184e..637d42fd4 100644 --- a/hoverctl/cmd/mode.go +++ b/hoverctl/cmd/mode.go @@ -16,6 +16,7 @@ var stateful bool var overwriteDuplicate bool var matchingStrategy string var captureOnMiss bool +var captureDelay bool var modeCmd = &cobra.Command{ Use: "mode [capture|diff|simulate|spy|modify|synthesize (optional)]", @@ -51,6 +52,7 @@ mode is shown. case modes.Capture: modeView.Arguments.Stateful = stateful modeView.Arguments.OverwriteDuplicate = overwriteDuplicate + modeView.Arguments.CaptureDelay = captureDelay setHeaderArgument(modeView) break case modes.Diff: @@ -61,6 +63,7 @@ mode is shown. modeView.Arguments.Stateful = stateful modeView.Arguments.OverwriteDuplicate = overwriteDuplicate modeView.Arguments.CaptureOnMiss = captureOnMiss + modeView.Arguments.CaptureDelay = captureDelay setHeaderArgument(modeView) break } @@ -98,6 +101,9 @@ func getExtraInfo(mode *v2.ModeView) string { extraInfo = fmt.Sprintf("and will capture the following request headers: %s", mode.Arguments.Headers) } } + if captureDelay { + extraInfo = fmt.Sprintf(" and will also capture the delay") + } break case modes.Diff: if len(mode.Arguments.Headers) > 0 { @@ -119,6 +125,9 @@ func getExtraInfo(mode *v2.ModeView) string { extraInfo = fmt.Sprintf("and also will capture the following request headers: %s", mode.Arguments.Headers) } } + if captureDelay { + extraInfo = fmt.Sprintf(" and will also capture the delay") + } break } @@ -139,4 +148,5 @@ func init() { modeCmd.PersistentFlags().BoolVar(&overwriteDuplicate, "overwrite-duplicate", false, "Overwrite duplicate requests in capture mode") modeCmd.PersistentFlags().BoolVar(&captureOnMiss, "capture-on-miss", false, "Capture the request on miss in spy mode") + modeCmd.PersistentFlags().BoolVar(&captureDelay, "capture-delay", false, "Capture the request delay in capture and spy mode") }