diff --git a/cmd/ghz/main.go b/cmd/ghz/main.go index e1c48fdd..3d6182c7 100644 --- a/cmd/ghz/main.go +++ b/cmd/ghz/main.go @@ -266,6 +266,10 @@ var ( maxSendMsgSize = kingpin.Flag("max-send-message-size", "Maximum message size the client can send."). PlaceHolder(" ").IsSetByUser(&isMaxSendMsgSizeSet).String() + isDisableTemplateFuncsSet = false + 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() + // host main argument isHostSet = false host = kingpin.Arg("host", "Host and port to test.").String() @@ -507,6 +511,7 @@ func createConfigFromArgs(cfg *runner.Config) error { cfg.LBStrategy = *lbStrategy cfg.MaxCallRecvMsgSize = *maxRecvMsgSize cfg.MaxCallSendMsgSize = *maxSendMsgSize + cfg.DisableTemplateFuncs = *disableTemplateFuncs return nil } @@ -760,6 +765,11 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error { dest.MaxCallSendMsgSize = src.MaxCallSendMsgSize } + // call data template behavior + if isDisableTemplateFuncsSet { + dest.DisableTemplateFuncs = src.DisableTemplateFuncs + } + return nil } diff --git a/runner/config.go b/runner/config.go index a320233c..b666dbff 100644 --- a/runner/config.go +++ b/runner/config.go @@ -116,6 +116,7 @@ type Config struct { LBStrategy string `json:"lb-strategy" toml:"lb-strategy" yaml:"lb-strategy"` 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"` } func checkData(data interface{}) error { diff --git a/runner/data.go b/runner/data.go index 3e1223a2..4da80f81 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, - funcs template.FuncMap) (*dataProvider, error) { + withFuncs bool, funcs template.FuncMap) (*dataProvider, error) { dp := dataProvider{ binary: binary, @@ -98,7 +98,7 @@ func newDataProvider(mtd *desc.MethodDescriptor, } // Test if we can preseed data - ctd := newCallData(mtd, "", 0, true, funcs) + ctd := newCallData(mtd, "", 0, withFuncs, funcs) ha := false if !dp.binary { ha, err = ctd.hasAction(string(dp.data)) @@ -221,9 +221,9 @@ func (dp *dataProvider) getMessages(ctd *CallData, i int, inputData []byte) ([]* return inputs, nil } -func newMetadataProvider(mtd *desc.MethodDescriptor, mdData []byte, funcs template.FuncMap) (*mdProvider, error) { +func newMetadataProvider(mtd *desc.MethodDescriptor, mdData []byte, withFuncs bool, funcs template.FuncMap) (*mdProvider, error) { // Test if we can preseed data - ctd := newCallData(mtd, "", 0, true, funcs) + ctd := newCallData(mtd, "", 0, withFuncs, funcs) ha, err := ctd.hasAction(string(mdData)) if err != nil { return nil, err @@ -389,7 +389,7 @@ type dynamicMessageProvider struct { indexCounter uint } -func newDynamicMessageProvider(mtd *desc.MethodDescriptor, data []byte, streamCallCount uint) (*dynamicMessageProvider, error) { +func newDynamicMessageProvider(mtd *desc.MethodDescriptor, data []byte, streamCallCount uint, withFuncs bool) (*dynamicMessageProvider, error) { mp := dynamicMessageProvider{ mtd: mtd, data: data, @@ -419,7 +419,7 @@ func newDynamicMessageProvider(mtd *desc.MethodDescriptor, data []byte, streamCa mp.arrayLen = uint(len(mp.arrayJSONData)) // Test if we have actions - ctd := newCallData(mtd, "", 0, true, nil) + ctd := newCallData(mtd, "", 0, withFuncs, nil) ha, err := ctd.hasAction(string(mp.data)) if err != nil { return nil, err diff --git a/runner/data_test.go b/runner/data_test.go index ba264ada..c761eaa7 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"}`), nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), 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 }}"}`), nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), true, nil) assert.NoError(t, err) assert.NotNil(t, mdp) assert.Nil(t, mdp.preseed) @@ -304,7 +304,7 @@ func TestMetadata_getMetadataForCall(t *testing.T) { nil) assert.NoError(t, err) - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"asdf"}`), true, nil) assert.NoError(t, err) assert.NotNil(t, mdp.preseed) @@ -324,7 +324,7 @@ func TestMetadata_getMetadataForCall(t *testing.T) { nil) assert.NoError(t, err) - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), nil) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ .RequestNumber }}"}`), true, nil) assert.NoError(t, err) assert.Nil(t, mdp.preseed) @@ -359,7 +359,7 @@ func TestMetadata_getMetadataForCall(t *testing.T) { }, } - mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ customFunc }}"}`), funcs) + mdp, err := newMetadataProvider(mtdUnary, []byte(`{"token":"{{ customFunc }}"}`), true, funcs) assert.NoError(t, err) assert.Nil(t, mdp.preseed) diff --git a/runner/options.go b/runner/options.go index 84271e2f..41d3ab27 100644 --- a/runner/options.go +++ b/runner/options.go @@ -124,6 +124,9 @@ type RunConfig struct { hasLog bool log Logger + // template call data + disableTemplateFuncs bool + // misc name string cpus int @@ -1095,6 +1098,15 @@ func WithDefaultCallOptions(opts []grpc.CallOption) Option { } } +// WithDisableTemplateFuncs disables template functions in call data +func WithDisableTemplateFuncs(v bool) Option { + return func(o *RunConfig) error { + o.disableTemplateFuncs = v + + return nil + } +} + func createClientTransportCredentials(skipVerify bool, cacertFile, clientCertFile, clientKeyFile, cname string) (credentials.TransportCredentials, error) { var tlsConf tls.Config @@ -1187,6 +1199,7 @@ func fromConfig(cfg *Config) []Option { WithConcurrencyStepDuration(time.Duration(cfg.CStepDuration)), WithConcurrencyDuration(time.Duration(cfg.CMaxDuration)), WithCountErrors(cfg.CountErrors), + WithDisableTemplateFuncs(cfg.DisableTemplateFuncs), func(o *RunConfig) error { o.call = cfg.Call return nil diff --git a/runner/requester.go b/runner/requester.go index a3a5f6fd..d890d616 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.funcs) + defaultDataProvider, err := newDataProvider(reqr.mtd, c.binary, c.dataFunc, c.data, !c.disableTemplateFuncs, 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.funcs) + defaultMDProvider, err := newMetadataProvider(reqr.mtd, c.metadata, !c.disableTemplateFuncs, c.funcs) if err != nil { return nil, err } diff --git a/runner/run_test.go b/runner/run_test.go index b60f233d..15dbb9c5 100644 --- a/runner/run_test.go +++ b/runner/run_test.go @@ -3,6 +3,7 @@ package runner import ( "fmt" "strconv" + "strings" "testing" "text/template" "time" @@ -217,6 +218,39 @@ func TestRunUnary(t *testing.T) { assert.NotEmpty(t, parsed) }) + t.Run("test disabled template functions", func(t *testing.T) { + gs.ResetCounters() + + data := make(map[string]interface{}) + data["name"] = "{{ newUUID }}" + + 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.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) + + // calls := gs.GetCalls(callType) + // assert.NotNil(t, calls) + // assert.Len(t, calls, 1) + + // msg := calls[0][0] + // assert.Equal(t, "{{ newUUID }}", msg.GetName()) + }) + t.Run("test skip first N", func(t *testing.T) { gs.ResetCounters() diff --git a/runner/worker.go b/runner/worker.go index 93b2d659..2f80e029 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, true, w.config.funcs) + ctd := newCallData(w.mtd, w.workerID, reqNum, !w.config.disableTemplateFuncs, 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) + mp, err := newDynamicMessageProvider(w.mtd, w.config.data, w.config.streamCallCount, !w.config.disableTemplateFuncs) if err != nil { return err }