diff --git a/core/hoverfly.go b/core/hoverfly.go index a8cc16cbc..e5d41e76f 100644 --- a/core/hoverfly.go +++ b/core/hoverfly.go @@ -53,15 +53,16 @@ func NewHoverfly() *Hoverfly { authBackend := backends.NewCacheBasedAuthBackend(cache.NewInMemoryCache(), cache.NewInMemoryCache()) + newJournal := journal.NewJournal() hoverfly := &Hoverfly{ Simulation: models.NewSimulation(), Authentication: authBackend, Counter: metrics.NewModeCounter([]string{modes.Simulate, modes.Synthesize, modes.Modify, modes.Capture, modes.Spy, modes.Diff}), StoreLogsHook: NewStoreLogsHook(), - Journal: journal.NewJournal(), + Journal: newJournal, Cfg: InitSettings(), state: state.NewState(), - templator: templating.NewTemplator(), + templator: templating.NewEnrichedTemplator(newJournal), responsesDiff: make(map[v2.SimpleRequestDefinitionView][]v2.DiffReport), PostServeActionDetails: action.NewPostServeActionDetails(), } diff --git a/core/hoverfly_funcs.go b/core/hoverfly_funcs.go index 776ab79fd..da97baa6a 100644 --- a/core/hoverfly_funcs.go +++ b/core/hoverfly_funcs.go @@ -224,7 +224,7 @@ func (hf *Hoverfly) applyTransitionsStateTemplating(requestDetails *models.Reque state := make(map[string]string) for k, v := range stateTemplates { - state[k], err = hf.templator.RenderTemplate(v, requestDetails, response, hf.Simulation.Literals, hf.Simulation.Vars, hf.state.State, hf.Journal) + state[k], err = hf.templator.RenderTemplate(v, requestDetails, response, hf.Simulation.Literals, hf.Simulation.Vars, hf.state.State) if err != nil { return nil, err } @@ -245,7 +245,7 @@ func (hf *Hoverfly) applyBodyTemplating(requestDetails *models.RequestDetails, r } } - return hf.templator.RenderTemplate(template, requestDetails, response, hf.Simulation.Literals, hf.Simulation.Vars, hf.state.State, hf.Journal) + return hf.templator.RenderTemplate(template, requestDetails, response, hf.Simulation.Literals, hf.Simulation.Vars, hf.state.State) } func (hf *Hoverfly) applyHeadersTemplating(requestDetails *models.RequestDetails, response *models.ResponseDetails, cachedResponse *models.CachedResponse) (map[string][]string, error) { @@ -280,7 +280,7 @@ func (hf *Hoverfly) applyHeadersTemplating(requestDetails *models.RequestDetails for k, v := range headersTemplates { header = make([]string, len(v)) for i, h := range v { - header[i], err = hf.templator.RenderTemplate(h, requestDetails, response, hf.Simulation.Literals, hf.Simulation.Vars, hf.state.State, hf.Journal) + header[i], err = hf.templator.RenderTemplate(h, requestDetails, response, hf.Simulation.Literals, hf.Simulation.Vars, hf.state.State) if err != nil { return nil, err diff --git a/core/templating/template_helpers.go b/core/templating/template_helpers.go index f3f8460f8..c545e068a 100644 --- a/core/templating/template_helpers.go +++ b/core/templating/template_helpers.go @@ -26,6 +26,7 @@ type templateHelpers struct { now func() time.Time fakerSource *gofakeit.Faker TemplateDataSource *TemplateDataSource + journal *journal.Journal } func (t templateHelpers) nowHelper(offset string, format string) string { @@ -466,8 +467,7 @@ func (t templateHelpers) csvSqlCommand(commandString string) []RowMap { } func (t templateHelpers) parseJournalBasedOnIndex(indexName, keyValue, dataSource, queryType, lookupQuery string, options *raymond.Options) interface{} { - journalDetails := options.Value("Journal").(Journal) - if journalEntry, err := getIndexEntry(journalDetails, indexName, keyValue); err == nil { + if journalEntry, err := getIndexEntry(t.journal, indexName, keyValue); err == nil { if body := getBodyDataToParse(dataSource, journalEntry); body != "" { data := util.FetchFromRequestBody(queryType, lookupQuery, body) if _, ok := data.(error); ok { @@ -481,9 +481,9 @@ func (t templateHelpers) parseJournalBasedOnIndex(indexName, keyValue, dataSourc return getEvaluationString("journal", options) } -func (t templateHelpers) hasJournalKey(indexName, keyValue string, options *raymond.Options) bool { - journalDetails := options.Value("Journal").(Journal) - journalEntry, _ := getIndexEntry(journalDetails, indexName, keyValue) +func (t templateHelpers) hasJournalKey(indexName, keyValue string) bool { + + journalEntry, _ := getIndexEntry(t.journal, indexName, keyValue) return journalEntry != nil } @@ -615,25 +615,25 @@ func formatNumber(number float64, format string) string { return fmt.Sprintf("%."+strconv.Itoa(decimalPlaces)+"f", rounded) } -func getIndexEntry(journalIndexDetails Journal, indexName, indexValue string) (*JournalEntry, error) { +func getIndexEntry(journal *journal.Journal, indexName, indexValue string) (*journal.JournalEntry, error) { - for _, index := range journalIndexDetails.indexes { - if index.name == indexName { - if journalEntry, exists := index.entries[indexValue]; exists { - return &journalEntry, nil + for _, index := range journal.Indexes { + if index.Name == indexName { + if journalEntry, exists := index.Entries[indexValue]; exists { + return journalEntry, nil } } } return nil, fmt.Errorf("no entry found for index %s", indexName) } -func getBodyDataToParse(source string, journalEntry *JournalEntry) string { +func getBodyDataToParse(source string, journalEntry *journal.JournalEntry) string { if strings.EqualFold(source, "request") { - return journalEntry.requestBody + return journalEntry.Request.Body } if strings.EqualFold(source, "response") { - return journalEntry.responseBody + return journalEntry.Response.Body } return "" } diff --git a/core/templating/templating.go b/core/templating/templating.go index 527308b91..801122d3e 100644 --- a/core/templating/templating.go +++ b/core/templating/templating.go @@ -25,7 +25,6 @@ type TemplatingData struct { CurrentDateTime func(string, string, string) string Literals map[string]interface{} Vars map[string]interface{} - Journal Journal Kvs map[string]interface{} InternalVars map[string]interface{} // data store used internally by templating helpers } @@ -42,19 +41,6 @@ type Request struct { Host string } -type JournalEntry struct { - requestBody string - responseBody string -} - -type Journal struct { - indexes []JournalIndex -} - -type JournalIndex struct { - name string - entries map[string]JournalEntry -} type Templator struct { SupportedMethodMap map[string]interface{} @@ -65,6 +51,10 @@ var helpersRegistered = false var helperMethodMap = make(map[string]interface{}) func NewTemplator() *Templator { + return NewEnrichedTemplator(journal.NewJournal()) +} + +func NewEnrichedTemplator(journal *journal.Journal) *Templator { templateDataSource := NewTemplateDataSource() @@ -72,6 +62,7 @@ func NewTemplator() *Templator { now: time.Now, fakerSource: gofakeit.New(0), TemplateDataSource: templateDataSource, + journal: journal, } helperMethodMap["now"] = t.nowHelper @@ -148,12 +139,12 @@ func (*Templator) ParseTemplate(responseBody string) (*raymond.Template, error) return raymond.Parse(responseBody) } -func (t *Templator) RenderTemplate(tpl *raymond.Template, requestDetails *models.RequestDetails, response *models.ResponseDetails, literals *models.Literals, vars *models.Variables, state map[string]string, journal *journal.Journal) (string, error) { +func (t *Templator) RenderTemplate(tpl *raymond.Template, requestDetails *models.RequestDetails, response *models.ResponseDetails, literals *models.Literals, vars *models.Variables, state map[string]string) (string, error) { if tpl == nil { return "", fmt.Errorf("template cannot be nil") } - ctx := t.NewTemplatingData(requestDetails, response, literals, vars, state, journal) + ctx := t.NewTemplatingData(requestDetails, literals, vars, state) result, err := tpl.Exec(ctx) if err == nil { statusCode, ok := ctx.InternalVars["statusCode"] @@ -168,7 +159,7 @@ func (templator *Templator) GetSupportedMethodMap() map[string]interface{} { return templator.SupportedMethodMap } -func (t *Templator) NewTemplatingData(requestDetails *models.RequestDetails, response *models.ResponseDetails, literals *models.Literals, vars *models.Variables, state map[string]string, journal *journal.Journal) *TemplatingData { +func (t *Templator) NewTemplatingData(requestDetails *models.RequestDetails, literals *models.Literals, vars *models.Variables, state map[string]string) *TemplatingData { literalMap := make(map[string]interface{}) if literals != nil { @@ -178,32 +169,6 @@ func (t *Templator) NewTemplatingData(requestDetails *models.RequestDetails, res } variableMap := t.getVariables(vars, requestDetails) - templateJournal := Journal{} - if journal != nil { - - indexes := make([]JournalIndex, 0, len(journal.Indexes)) - for _, index := range journal.Indexes { - - journalIndexEntries := make(map[string]JournalEntry) - for indexKey, entry := range index.Entries { - - journalEntry := JournalEntry{ - requestBody: entry.Request.Body, - responseBody: entry.Response.Body, - } - journalIndexEntries[indexKey] = journalEntry - } - journalIndex := JournalIndex{ - name: index.Name, - entries: journalIndexEntries, - } - indexes = append(indexes, journalIndex) - } - templateJournal = Journal{ - indexes: indexes, - } - - } kvs := make(map[string]interface{}) return &TemplatingData{ @@ -211,7 +176,6 @@ func (t *Templator) NewTemplatingData(requestDetails *models.RequestDetails, res Literals: literalMap, Vars: variableMap, State: state, - Journal: templateJournal, CurrentDateTime: func(a1, a2, a3 string) string { return a1 + " " + a2 + " " + a3 }, diff --git a/core/templating/templating_test.go b/core/templating/templating_test.go index 071e182a6..14345e68a 100644 --- a/core/templating/templating_test.go +++ b/core/templating/templating_test.go @@ -3,8 +3,6 @@ package templating_test import ( "testing" - "github.com/SpectoLabs/hoverfly/core/journal" - "github.com/SpectoLabs/hoverfly/core/models" "github.com/SpectoLabs/hoverfly/core/templating" . "github.com/onsi/gomega" @@ -297,7 +295,7 @@ func Test_ShouldCreateTemplatingDataPathsFromRequest(t *testing.T) { Scheme: "http", Destination: "test.com", Path: "/foo/bar", - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.Path).To(ConsistOf("foo", "bar")) } @@ -308,7 +306,7 @@ func Test_ShouldCreateTemplatingDataPathsFromRequestWithNoPaths(t *testing.T) { actual := templating.NewTemplator().NewTemplatingData(&models.RequestDetails{ Scheme: "http", Destination: "test.com", - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.Path).To(BeEmpty()) } @@ -323,7 +321,7 @@ func Test_ShouldCreateTemplatingDataQueryParamsFromRequest(t *testing.T) { "cheese": {"1", "3"}, "ham": {"2"}, }, - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.QueryParam).To(HaveKeyWithValue("cheese", []string{"1", "3"})) Expect(actual.Request.QueryParam).To(HaveKeyWithValue("ham", []string{"2"})) @@ -336,7 +334,7 @@ func Test_ShouldCreateTemplatingDataQueryParamsFromRequestWithNoQueryParams(t *t actual := templating.NewTemplator().NewTemplatingData(&models.RequestDetails{ Scheme: "http", Destination: "test.com", - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.QueryParam).To(BeEmpty()) } @@ -347,7 +345,7 @@ func Test_ShouldCreateTemplatingDataHttpScheme(t *testing.T) { actual := templating.NewTemplator().NewTemplatingData(&models.RequestDetails{ Scheme: "http", Destination: "test.com", - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.Scheme).To(Equal("http")) } @@ -362,7 +360,7 @@ func Test_ShouldCreateTemplatingDataHeaderFromRequest(t *testing.T) { "cheese": {"1", "3"}, "ham": {"2"}, }, - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.Header).To(HaveKeyWithValue("cheese", []string{"1", "3"})) Expect(actual.Request.Header).To(HaveKeyWithValue("ham", []string{"2"})) @@ -375,7 +373,7 @@ func Test_ShouldCreateTemplatingDataHeaderFromRequestWithNoHeader(t *testing.T) actual := templating.NewTemplator().NewTemplatingData(&models.RequestDetails{ Scheme: "http", Destination: "test.com", - }, nil, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(actual.Request.Header).To(BeEmpty()) } @@ -702,7 +700,7 @@ func Test_VarSetToNilInCaseOfInvalidArgsPassed(t *testing.T) { actual := templator.NewTemplatingData(&models.RequestDetails{ Scheme: "http", Destination: "test.com", - }, nil, &models.Literals{}, vars, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, vars, make(map[string]string)) Expect(actual.Vars["varOne"]).To(BeNil()) @@ -722,7 +720,7 @@ func Test_VarSetToProperValueInCaseOfRequestDetailsPassedAsArgument(t *testing.T actual := templator.NewTemplatingData(&models.RequestDetails{ Path: "/part1/foo,bar", - }, nil, &models.Literals{}, vars, make(map[string]string), &journal.Journal{}) + }, &models.Literals{}, vars, make(map[string]string)) Expect(actual.Vars["splitRequestPath"]).ToNot(BeNil()) Expect(len(actual.Vars["splitRequestPath"].([]string))).To(Equal(2)) @@ -823,13 +821,13 @@ func Test_ApplyTemplate_Arithmetic_Ops_With_Each_Block(t *testing.T) { template, _ := templator.ParseTemplate(responseBody) state := make(map[string]string) - result, err := templator.RenderTemplate(template, requestDetails, nil, &models.Literals{}, &models.Variables{}, state, &journal.Journal{}) + result, err := templator.RenderTemplate(template, requestDetails, nil, &models.Literals{}, &models.Variables{}, state) Expect(err).To(BeNil()) Expect(result).To(Equal(` 3.5 9 total: 12.50`)) // Running the second time should produce the same result because each execution has its own context data. - result, err = templator.RenderTemplate(template, requestDetails, nil, &models.Literals{}, &models.Variables{}, state, &journal.Journal{}) + result, err = templator.RenderTemplate(template, requestDetails, nil, &models.Literals{}, &models.Variables{}, state) Expect(err).To(BeNil()) Expect(result).To(Equal(` 3.5 9 total: 12.50`)) } @@ -867,7 +865,7 @@ func Test_ApplyTemplate_setStatusCode(t *testing.T) { Expect(err).To(BeNil()) response := &models.ResponseDetails{} - result, err := templator.RenderTemplate(template, &models.RequestDetails{}, response, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + result, err := templator.RenderTemplate(template, &models.RequestDetails{}, response, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(err).To(BeNil()) Expect(result).To(Equal("")) @@ -883,7 +881,7 @@ func Test_ApplyTemplate_setStatusCode_should_ignore_invalid_code(t *testing.T) { Expect(err).To(BeNil()) response := &models.ResponseDetails{} - result, err := templator.RenderTemplate(template, &models.RequestDetails{}, response, &models.Literals{}, &models.Variables{}, make(map[string]string), &journal.Journal{}) + result, err := templator.RenderTemplate(template, &models.RequestDetails{}, response, &models.Literals{}, &models.Variables{}, make(map[string]string)) Expect(err).To(BeNil()) Expect(result).To(Equal("")) @@ -920,7 +918,7 @@ func ApplyTemplate(requestDetails *models.RequestDetails, state map[string]strin func renderTemplate(requestDetails *models.RequestDetails, state map[string]string, responseBody string, templator *templating.Templator) (string, error) { template, err := templator.ParseTemplate(responseBody) Expect(err).To(BeNil()) - return templator.RenderTemplate(template, requestDetails, nil, &models.Literals{}, &models.Variables{}, state, &journal.Journal{}) + return templator.RenderTemplate(template, requestDetails, nil, &models.Literals{}, &models.Variables{}, state) } func initiateTemplator() *templating.Templator {