Skip to content

Commit

Permalink
[feature] [option] adding a func as a option to randomize each request (
Browse files Browse the repository at this point in the history
#236)

* addition of randomized func for every binary request
add some tests and todo and change signature

* rename type struct and add parameter

* expose callData
  • Loading branch information
Nam Nguyen authored Oct 25, 2020
1 parent 47cc6be commit 10117a4
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 19 deletions.
16 changes: 8 additions & 8 deletions runner/call_template_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano()))

// call template data
type callTemplateData struct {
type CallData struct {
WorkerID string // unique worker ID
RequestNumber int64 // unique incremented request number for each request
FullyQualifiedName string // fully-qualified name of the method call
Expand All @@ -42,11 +42,11 @@ var tmplFuncMap = template.FuncMap{
"randomString": randomString,
}

// newCallTemplateData returns new call template data
func newCallTemplateData(
// newCallData returns new callData
func newCallData(
mtd *desc.MethodDescriptor,
funcs template.FuncMap,
workerID string, reqNum int64) *callTemplateData {
workerID string, reqNum int64) *CallData {
now := time.Now()
newUUID, _ := uuid.NewRandom()

Expand All @@ -61,7 +61,7 @@ func newCallTemplateData(
}
}

return &callTemplateData{
return &CallData{
WorkerID: workerID,
RequestNumber: reqNum,
FullyQualifiedName: mtd.GetFullyQualifiedName(),
Expand All @@ -80,14 +80,14 @@ func newCallTemplateData(
}
}

func (td *callTemplateData) execute(data string) (*bytes.Buffer, error) {
func (td *CallData) execute(data string) (*bytes.Buffer, error) {
t := template.Must(template.New("call_template_data").Funcs(td.templateFuncs).Parse(data))
var tpl bytes.Buffer
err := t.Execute(&tpl, td)
return &tpl, err
}

func (td *callTemplateData) executeData(data string) ([]byte, error) {
func (td *CallData) executeData(data string) ([]byte, error) {
if len(data) > 0 {
input := []byte(data)
tpl, err := td.execute(data)
Expand All @@ -101,7 +101,7 @@ func (td *callTemplateData) executeData(data string) ([]byte, error) {
return []byte{}, nil
}

func (td *callTemplateData) executeMetadata(metadata string) (map[string]string, error) {
func (td *CallData) executeMetadata(metadata string) (map[string]string, error) {
var mdMap map[string]string

if len(metadata) > 0 {
Expand Down
10 changes: 5 additions & 5 deletions runner/call_template_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestCallTemplateData_New(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, md)

ctd := newCallTemplateData(md, nil, "worker_id_123", 100)
ctd := newCallData(md, nil, "worker_id_123", 100)

assert.NotNil(t, ctd)
assert.Equal(t, "worker_id_123", ctd.WorkerID)
Expand All @@ -41,7 +41,7 @@ func TestCallTemplateData_ExecuteData(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, md)

ctd := newCallTemplateData(md, nil, "worker_id_123", 200)
ctd := newCallData(md, nil, "worker_id_123", 200)

assert.NotNil(t, ctd)

Expand Down Expand Up @@ -92,7 +92,7 @@ func TestCallTemplateData_ExecuteMetadata(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, md)

ctd := newCallTemplateData(md, nil, "worker_id_123", 200)
ctd := newCallData(md, nil, "worker_id_123", 200)

assert.NotNil(t, ctd)

Expand Down Expand Up @@ -138,7 +138,7 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, md)

ctd := newCallTemplateData(md, nil, "worker_id_123", 200)
ctd := newCallData(md, nil, "worker_id_123", 200)

assert.NotNil(t, ctd)

Expand Down Expand Up @@ -249,7 +249,7 @@ func TestCallTemplateData_ExecuteFuncs(t *testing.T) {
})

t.Run("custom functions", func(t *testing.T) {
ctd = newCallTemplateData(md, template.FuncMap{
ctd = newCallData(md, template.FuncMap{
"getSKU": func() string {
return "custom-sku"
},
Expand Down
20 changes: 18 additions & 2 deletions runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"text/template"
"time"

"github.com/jhump/protoreflect/desc"
"github.com/pkg/errors"
"google.golang.org/grpc/credentials"
)
Expand Down Expand Up @@ -58,7 +59,11 @@ type RunConfig struct {
streamInterval time.Duration

// data
data []byte
data []byte

// data func
dataFunc func(mtd *desc.MethodDescriptor, callData *CallData) []byte

binary bool
metadata []byte
rmd map[string]string
Expand Down Expand Up @@ -300,6 +305,17 @@ func WithBinaryData(data []byte) Option {
}
}

// WithBinaryDataFunc specifies the binary data func which will be called on each request
// WithBinaryDataFunc(changeFunc)
func WithBinaryDataFunc(data func(mtd *desc.MethodDescriptor, callData *CallData) []byte) Option {
return func(o *RunConfig) error {
o.dataFunc = data
o.binary = true

return nil
}
}

// WithBinaryDataFromFile specifies the binary data
// WithBinaryDataFromFile("request_data.bin")
func WithBinaryDataFromFile(path string) Option {
Expand Down Expand Up @@ -557,7 +573,7 @@ func WithLogger(log Logger) Option {
}
}

// WithTemplateFuncs adds additional tempalte functions
// WithTemplateFuncs adds additional template functions
func WithTemplateFuncs(funcMap template.FuncMap) Option {
return func(o *RunConfig) error {
o.funcs = funcMap
Expand Down
5 changes: 5 additions & 0 deletions runner/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"math"
"os"
"reflect"
"runtime"
"testing"
"time"
Expand Down Expand Up @@ -124,6 +125,7 @@ func TestRunConfig_newRunConfig(t *testing.T) {
WithDialTimeout(time.Duration(30*time.Second)),
WithName("asdf"),
WithCPUs(4),
WithBinaryDataFunc(changeFunc),
WithBinaryData([]byte("asdf1234foobar")),
WithMetadataFromFile("../testdata/metadata.json"),
WithProtoset("testdata/bundle.protoset"),
Expand All @@ -150,6 +152,9 @@ func TestRunConfig_newRunConfig(t *testing.T) {
assert.Equal(t, 4, c.cpus)
assert.Equal(t, "asdf", c.name)
assert.Equal(t, []byte("asdf1234foobar"), c.data)
funcName1 := runtime.FuncForPC(reflect.ValueOf(changeFunc).Pointer()).Name()
funcName2 := runtime.FuncForPC(reflect.ValueOf(c.dataFunc).Pointer()).Name()
assert.Equal(t, funcName1, funcName2)
assert.Equal(t, `{"request-id": "{{.RequestNumber}}"}`, string(c.metadata))
assert.Equal(t, "", string(c.proto))
assert.Equal(t, "testdata/bundle.protoset", string(c.protoset))
Expand Down
52 changes: 52 additions & 0 deletions runner/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,17 @@ import (
"github.com/bojand/ghz/internal"
"github.com/bojand/ghz/internal/helloworld"
"github.com/golang/protobuf/proto"
"github.com/jhump/protoreflect/desc"
"github.com/stretchr/testify/assert"
)

func changeFunc(mtd *desc.MethodDescriptor, cd *CallData) []byte {
msg := &helloworld.HelloRequest{}
msg.Name = "bob"
binData, _ := proto.Marshal(msg)
return binData
}

func TestRunUnary(t *testing.T) {
callType := helloworld.Unary

Expand Down Expand Up @@ -352,6 +360,50 @@ func TestRunUnary(t *testing.T) {
assert.Equal(t, 1, connCount)
})

t.Run("test binary with func", func(t *testing.T) {

gs.ResetCounters()

report, err := Run(
"helloworld.Greeter.SayHello",
internal.TestLocalhost,
WithProtoFile("../testdata/greeter.proto", []string{}),
WithTotalRequests(5),
WithBinaryDataFunc(changeFunc),
WithConcurrency(1),
WithTimeout(time.Duration(20*time.Second)),
WithDialTimeout(time.Duration(20*time.Second)),
WithInsecure(true),
)

assert.NoError(t, err)

assert.NotNil(t, report)

assert.Equal(t, 5, int(report.Count))
assert.NotZero(t, report.Average)
assert.NotZero(t, report.Fastest)
assert.NotZero(t, report.Slowest)
assert.NotZero(t, report.Rps)
assert.Empty(t, report.Name)
assert.NotEmpty(t, report.Date)
assert.NotEmpty(t, report.Options)
assert.NotEmpty(t, report.Details)
assert.NotEmpty(t, report.LatencyDistribution)
assert.Equal(t, ReasonNormalEnd, report.EndReason)
assert.Empty(t, report.ErrorDist)

assert.NotEqual(t, report.Average, report.Slowest)
assert.NotEqual(t, report.Average, report.Fastest)
assert.NotEqual(t, report.Slowest, report.Fastest)

count := gs.GetCount(callType)
assert.Equal(t, 5, count)

connCount := gs.GetConnectionCount()
assert.Equal(t, 1, connCount)
})

t.Run("test connections", func(t *testing.T) {
gs.ResetCounters()

Expand Down
13 changes: 9 additions & 4 deletions runner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (w *Worker) makeRequest() error {

reqNum := atomic.AddInt64(w.reqCounter, 1)

ctd := newCallTemplateData(w.mtd, w.config.funcs, w.workerID, reqNum)
ctd := newCallData(w.mtd, w.config.funcs, w.workerID, reqNum)

var inputs []*dynamic.Message
var err error
Expand Down Expand Up @@ -167,7 +167,7 @@ func (w *Worker) makeRequest() error {
return err
}

func (w *Worker) getMessages(ctd *callTemplateData, inputData []byte) ([]*dynamic.Message, error) {
func (w *Worker) getMessages(ctd *CallData, inputData []byte) ([]*dynamic.Message, error) {
var inputs []*dynamic.Message

if w.cachedMessages != nil {
Expand All @@ -186,12 +186,17 @@ func (w *Worker) getMessages(ctd *callTemplateData, inputData []byte) ([]*dynami
// Json messages are not cached due to templating
} else {
var err error
if w.config.dataFunc != nil {
inputData = w.config.dataFunc(w.mtd, ctd)
}
inputs, err = createPayloadsFromBin(inputData, w.mtd)
if err != nil {
return nil, err
}

w.cachedMessages = inputs
// We only cache in case we don't dynamically change the binary message
if w.config.dataFunc == nil {
w.cachedMessages = inputs
}
}

return inputs, nil
Expand Down

0 comments on commit 10117a4

Please sign in to comment.