diff --git a/cmd/ghz/main.go b/cmd/ghz/main.go index 3d6182c7..f6fa94b7 100644 --- a/cmd/ghz/main.go +++ b/cmd/ghz/main.go @@ -270,6 +270,10 @@ var ( disableTemplateFuncs = kingpin.Flag("disable-template-functions", "Do not use and execute any template functions in call template data. Useful for better performance"). Default("false").IsSetByUser(&isDisableTemplateFuncsSet).Bool() + isDisableTemplateDataSet = false + disableTemplateData = kingpin.Flag("disable-template-data", "Do not use and execute any call template data. Useful for better performance."). + Default("false").IsSetByUser(&isDisableTemplateDataSet).Bool() + // host main argument isHostSet = false host = kingpin.Arg("host", "Host and port to test.").String() @@ -512,6 +516,7 @@ func createConfigFromArgs(cfg *runner.Config) error { cfg.MaxCallRecvMsgSize = *maxRecvMsgSize cfg.MaxCallSendMsgSize = *maxSendMsgSize cfg.DisableTemplateFuncs = *disableTemplateFuncs + cfg.DisableTemplateData = *disableTemplateData return nil } @@ -765,11 +770,16 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error { dest.MaxCallSendMsgSize = src.MaxCallSendMsgSize } - // call data template behavior + // call data template functions behavior if isDisableTemplateFuncsSet { dest.DisableTemplateFuncs = src.DisableTemplateFuncs } + // call data template behavior + if isDisableTemplateDataSet { + dest.DisableTemplateData = src.DisableTemplateData + } + return nil } diff --git a/runner/calldata.go b/runner/calldata.go index 2404aee9..07b236ce 100644 --- a/runner/calldata.go +++ b/runner/calldata.go @@ -53,23 +53,26 @@ var tmplFuncMap = template.FuncMap{ // newCallData returns new CallData func newCallData( mtd *desc.MethodDescriptor, - workerID string, reqNum int64, withFuncs bool, funcs template.FuncMap) *CallData { + workerID string, reqNum int64, withFuncs, withTemplateData bool, funcs template.FuncMap) *CallData { - t := template.New("call_template_data") + var t *template.Template + if withTemplateData { + t = template.New("call_template_data") - if withFuncs { - t = t. - Funcs(tmplFuncMap). - Funcs(template.FuncMap(sprigFuncMap)) + if withFuncs { + t = t. + Funcs(tmplFuncMap). + Funcs(template.FuncMap(sprigFuncMap)) - if len(funcs) > 0 { - fns := make(template.FuncMap, len(funcs)) + if len(funcs) > 0 { + fns := make(template.FuncMap, len(funcs)) - for k, v := range funcs { - fns[k] = v - } + for k, v := range funcs { + fns[k] = v + } - t = t.Funcs(fns) + t = t.Funcs(fns) + } } } @@ -121,6 +124,10 @@ func (td *CallData) Regenerate() *CallData { } func (td *CallData) execute(data string) (*bytes.Buffer, error) { + if td.t == nil { + return nil, nil + } + t, err := td.t.Parse(data) if err != nil { return nil, err @@ -136,6 +143,10 @@ func (td *CallData) execute(data string) (*bytes.Buffer, error) { // The *parse.Tree field is exported only for use by html/template // and should be treated as unexported by all other clients. func (td *CallData) hasAction(data string) (bool, error) { + if td.t == nil { + return false, nil + } + t, err := td.t.Parse(data) if err != nil { return false, err @@ -167,7 +178,7 @@ func (td *CallData) ExecuteData(data string) ([]byte, error) { if len(data) > 0 { input := []byte(data) tpl, err := td.execute(data) - if err == nil { + if err == nil && tpl != nil { input = tpl.Bytes() } @@ -183,7 +194,7 @@ func (td *CallData) executeMetadata(metadata string) (map[string]string, error) if len(metadata) > 0 { input := []byte(metadata) tpl, err := td.execute(metadata) - if err == nil { + if err == nil && tpl != nil { input = tpl.Bytes() } diff --git a/runner/calldata_test.go b/runner/calldata_test.go index ed34dced..b5404d8b 100644 --- a/runner/calldata_test.go +++ b/runner/calldata_test.go @@ -17,7 +17,7 @@ func TestCallData_New(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, md) - ctd := newCallData(md, "worker_id_123", 100, true, nil) + ctd := newCallData(md, "worker_id_123", 100, true, true, nil) assert.NotNil(t, ctd) assert.Equal(t, "worker_id_123", ctd.WorkerID) @@ -73,7 +73,7 @@ func TestCallData_ExecuteData(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) r, err := ctd.ExecuteData(tt.in) @@ -124,7 +124,7 @@ func TestCallData_ExecuteMetadata(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) r, err := ctd.executeMetadata(tt.in) @@ -146,7 +146,7 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) { t.Run("newUUID", func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) // no template @@ -194,7 +194,7 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) { }) t.Run("randomString", func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) // no template @@ -256,7 +256,7 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) { }) t.Run("randomInt", func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) // no template @@ -295,10 +295,10 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) { t.Run("custom functions", func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) - ctd = newCallData(md, "worker_id_123", 200, true, template.FuncMap{ + ctd = newCallData(md, "worker_id_123", 200, true, true, template.FuncMap{ "getSKU": func() string { return "custom-sku" }, @@ -320,7 +320,7 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) { t.Run("sprig functions", func(t *testing.T) { - ctd := newCallData(md, "worker_id_123", 200, true, nil) + ctd := newCallData(md, "worker_id_123", 200, true, true, nil) assert.NotNil(t, ctd) r, err := ctd.ExecuteData(`{"trace_id":"{{add 1 2}}"}`) diff --git a/runner/config.go b/runner/config.go index b666dbff..b2263375 100644 --- a/runner/config.go +++ b/runner/config.go @@ -117,6 +117,7 @@ type Config struct { MaxCallRecvMsgSize string `json:"max-recv-message-size" toml:"max-recv-message-size" yaml:"max-recv-message-size"` MaxCallSendMsgSize string `json:"max-send-message-size" toml:"max-send-message-size" yaml:"max-send-message-size"` DisableTemplateFuncs bool `json:"disable-template-functions" toml:"disable-template-functions" yaml:"disable-template-functions"` + DisableTemplateData bool `json:"disable-template-data" toml:"disable-template-data" yaml:"disable-template-data"` } func checkData(data interface{}) error { diff --git a/runner/data.go b/runner/data.go index 4da80f81..68ac1337 100644 --- a/runner/data.go +++ b/runner/data.go @@ -65,7 +65,7 @@ type mdProvider struct { func newDataProvider(mtd *desc.MethodDescriptor, binary bool, dataFunc BinaryDataFunc, data []byte, - withFuncs bool, funcs template.FuncMap) (*dataProvider, error) { + withFuncs, withTemplateData bool, funcs template.FuncMap) (*dataProvider, error) { dp := dataProvider{ binary: binary, @@ -98,12 +98,15 @@ func newDataProvider(mtd *desc.MethodDescriptor, } // Test if we can preseed data - ctd := newCallData(mtd, "", 0, withFuncs, funcs) ha := false - if !dp.binary { - ha, err = ctd.hasAction(string(dp.data)) - if err != nil { - return nil, err + ctd := newCallData(mtd, "", 0, withFuncs, withTemplateData, funcs) + + if withTemplateData { + if !dp.binary { + ha, err = ctd.hasAction(string(dp.data)) + if err != nil { + return nil, err + } } } @@ -221,9 +224,9 @@ func (dp *dataProvider) getMessages(ctd *CallData, i int, inputData []byte) ([]* return inputs, nil } -func newMetadataProvider(mtd *desc.MethodDescriptor, mdData []byte, withFuncs bool, funcs template.FuncMap) (*mdProvider, error) { +func newMetadataProvider(mtd *desc.MethodDescriptor, mdData []byte, withFuncs, withTemplateData bool, funcs template.FuncMap) (*mdProvider, error) { // Test if we can preseed data - ctd := newCallData(mtd, "", 0, withFuncs, funcs) + ctd := newCallData(mtd, "", 0, withFuncs, withTemplateData, funcs) ha, err := ctd.hasAction(string(mdData)) if err != nil { return nil, err @@ -389,7 +392,7 @@ type dynamicMessageProvider struct { indexCounter uint } -func newDynamicMessageProvider(mtd *desc.MethodDescriptor, data []byte, streamCallCount uint, withFuncs bool) (*dynamicMessageProvider, error) { +func newDynamicMessageProvider(mtd *desc.MethodDescriptor, data []byte, streamCallCount uint, withFuncs, withTemplateData bool) (*dynamicMessageProvider, error) { mp := dynamicMessageProvider{ mtd: mtd, data: data, @@ -419,10 +422,14 @@ func newDynamicMessageProvider(mtd *desc.MethodDescriptor, data []byte, streamCa mp.arrayLen = uint(len(mp.arrayJSONData)) // Test if we have actions - ctd := newCallData(mtd, "", 0, withFuncs, nil) - ha, err := ctd.hasAction(string(mp.data)) - if err != nil { - return nil, err + ha := false + ctd := newCallData(mtd, "", 0, withFuncs, withTemplateData, nil) + + if withTemplateData { + ha, err = ctd.hasAction(string(mp.data)) + if err != nil { + return nil, err + } } if !ha { diff --git a/runner/data_test.go b/runner/data_test.go index c761eaa7..463635ec 100644 --- a/runner/data_test.go +++ b/runner/data_test.go @@ -275,7 +275,7 @@ func TestMetadata_newMetadataProvider(t *testing.T) { nil) assert.NoError(t, err) - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), true, nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), true, true, nil) assert.NoError(t, err) assert.NotNil(t, mdp) assert.NotNil(t, mdp.preseed) @@ -289,7 +289,7 @@ func TestMetadata_newMetadataProvider(t *testing.T) { nil) assert.NoError(t, err) - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), true, nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), true, true, nil) assert.NoError(t, err) assert.NotNil(t, mdp) assert.Nil(t, mdp.preseed) @@ -304,11 +304,11 @@ func TestMetadata_getMetadataForCall(t *testing.T) { nil) assert.NoError(t, err) - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), true, nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), true, true, nil) assert.NoError(t, err) assert.NotNil(t, mdp.preseed) - cd := newCallData(mtdUnary, "123", 1, true, nil) + cd := newCallData(mtdUnary, "123", 1, true, true, nil) md, err := mdp.getMetadataForCall(cd) assert.NoError(t, err) @@ -324,11 +324,11 @@ func TestMetadata_getMetadataForCall(t *testing.T) { nil) assert.NoError(t, err) - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), true, nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), true, true, nil) assert.NoError(t, err) assert.Nil(t, mdp.preseed) - cd := newCallData(mtdUnary, "123", 1, true, nil) + cd := newCallData(mtdUnary, "123", 1, true, true, nil) md1, err := mdp.getMetadataForCall(cd) assert.NoError(t, err) @@ -336,7 +336,7 @@ func TestMetadata_getMetadataForCall(t *testing.T) { assert.Equal(t, []string{"1"}, md1.Get("token")) assert.NotSame(t, mdp.preseed, md1) - cd = newCallData(mtdUnary, "123", 2, true, nil) + cd = newCallData(mtdUnary, "123", 2, true, true, nil) md2, err := mdp.getMetadataForCall(cd) assert.NoError(t, err) assert.NotNil(t, md2) @@ -359,11 +359,11 @@ func TestMetadata_getMetadataForCall(t *testing.T) { }, } - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ customFunc }}"}`), true, funcs) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ customFunc }}"}`), true, true, funcs) assert.NoError(t, err) assert.Nil(t, mdp.preseed) - cd := newCallData(mtdUnary, "123", 1, true, funcs) + cd := newCallData(mtdUnary, "123", 1, true, true, funcs) md1, err := mdp.getMetadataForCall(cd) assert.NoError(t, err) diff --git a/runner/options.go b/runner/options.go index 41d3ab27..d2d39925 100644 --- a/runner/options.go +++ b/runner/options.go @@ -126,6 +126,7 @@ type RunConfig struct { // template call data disableTemplateFuncs bool + disableTemplateData bool // misc name string @@ -1107,6 +1108,15 @@ func WithDisableTemplateFuncs(v bool) Option { } } +// WithDisableTemplateData disables template data execution in call data +func WithDisableTemplateData(v bool) Option { + return func(o *RunConfig) error { + o.disableTemplateData = v + + return nil + } +} + func createClientTransportCredentials(skipVerify bool, cacertFile, clientCertFile, clientKeyFile, cname string) (credentials.TransportCredentials, error) { var tlsConf tls.Config @@ -1200,6 +1210,7 @@ func fromConfig(cfg *Config) []Option { WithConcurrencyDuration(time.Duration(cfg.CMaxDuration)), WithCountErrors(cfg.CountErrors), WithDisableTemplateFuncs(cfg.DisableTemplateFuncs), + WithDisableTemplateData(cfg.DisableTemplateData), func(o *RunConfig) error { o.call = cfg.Call return nil diff --git a/runner/requester.go b/runner/requester.go index d890d616..03763c5d 100644 --- a/runner/requester.go +++ b/runner/requester.go @@ -131,7 +131,7 @@ func NewRequester(c *RunConfig) (*Requester, error) { if c.dataProviderFunc != nil { reqr.dataProvider = c.dataProviderFunc } else { - defaultDataProvider, err := newDataProvider(reqr.mtd, c.binary, c.dataFunc, c.data, !c.disableTemplateFuncs, c.funcs) + defaultDataProvider, err := newDataProvider(reqr.mtd, c.binary, c.dataFunc, c.data, !c.disableTemplateFuncs, !c.disableTemplateData, c.funcs) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func NewRequester(c *RunConfig) (*Requester, error) { if c.mdProviderFunc != nil { reqr.metadataProvider = c.mdProviderFunc } else { - defaultMDProvider, err := newMetadataProvider(reqr.mtd, c.metadata, !c.disableTemplateFuncs, c.funcs) + defaultMDProvider, err := newMetadataProvider(reqr.mtd, c.metadata, !c.disableTemplateFuncs, !c.disableTemplateData, c.funcs) if err != nil { return nil, err } diff --git a/runner/run_test.go b/runner/run_test.go index 15dbb9c5..33927dff 100644 --- a/runner/run_test.go +++ b/runner/run_test.go @@ -239,16 +239,70 @@ func TestRunUnary(t *testing.T) { assert.Error(t, err) assert.True(t, strings.Contains(err.Error(), `function "newUUID" not defined`)) assert.Nil(t, report) + }) - // count := gs.GetCount(callType) - // assert.Equal(t, 1, count) + t.Run("test disabled template functions with data", func(t *testing.T) { + gs.ResetCounters() + + data := make(map[string]interface{}) + data["name"] = "{{ .RequestNumber }}" + + report, err := Run( + "helloworld.Greeter.SayHello", + internal.TestLocalhost, + WithProtoFile("../testdata/greeter.proto", []string{}), + WithTotalRequests(1), + WithConcurrency(1), + WithTimeout(time.Duration(20*time.Second)), + WithData(data), + WithInsecure(true), + WithDisableTemplateFuncs(true), + ) + + assert.NoError(t, err) + assert.NotNil(t, report) + + count := gs.GetCount(callType) + assert.Equal(t, 1, count) - // calls := gs.GetCalls(callType) - // assert.NotNil(t, calls) - // assert.Len(t, calls, 1) + calls := gs.GetCalls(callType) + assert.NotNil(t, calls) + assert.Len(t, calls, 1) - // msg := calls[0][0] - // assert.Equal(t, "{{ newUUID }}", msg.GetName()) + msg := calls[0][0] + assert.Equal(t, "0", msg.GetName()) + }) + + t.Run("test disabled template data", func(t *testing.T) { + gs.ResetCounters() + + data := make(map[string]interface{}) + data["name"] = "{{ .RequestNumber }}" + + report, err := Run( + "helloworld.Greeter.SayHello", + internal.TestLocalhost, + WithProtoFile("../testdata/greeter.proto", []string{}), + WithTotalRequests(1), + WithConcurrency(1), + WithTimeout(time.Duration(20*time.Second)), + WithData(data), + WithInsecure(true), + WithDisableTemplateData(true), + ) + + assert.NoError(t, err) + assert.NotNil(t, report) + + count := gs.GetCount(callType) + assert.Equal(t, 1, count) + + calls := gs.GetCalls(callType) + assert.NotNil(t, calls) + assert.Len(t, calls, 1) + + msg := calls[0][0] + assert.Equal(t, "{{ .RequestNumber }}", msg.GetName()) }) t.Run("test skip first N", func(t *testing.T) { diff --git a/runner/worker.go b/runner/worker.go index 2f80e029..6198b4df 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -80,7 +80,7 @@ func (w *Worker) Stop() { func (w *Worker) makeRequest(tv TickValue) error { reqNum := int64(tv.reqNumber) - ctd := newCallData(w.mtd, w.workerID, reqNum, !w.config.disableTemplateFuncs, w.config.funcs) + ctd := newCallData(w.mtd, w.workerID, reqNum, !w.config.disableTemplateFuncs, !w.config.disableTemplateData, w.config.funcs) reqMD, err := w.metadataProvider(ctd) if err != nil { @@ -116,7 +116,7 @@ func (w *Worker) makeRequest(tv TickValue) error { msgProvider = w.msgProvider } else if w.mtd.IsClientStreaming() { if w.config.streamDynamicMessages { - mp, err := newDynamicMessageProvider(w.mtd, w.config.data, w.config.streamCallCount, !w.config.disableTemplateFuncs) + mp, err := newDynamicMessageProvider(w.mtd, w.config.data, w.config.streamCallCount, !w.config.disableTemplateFuncs, !w.config.disableTemplateData) if err != nil { return err }