From d9b49ecf311790b6ae80109e4526f4554d92a8c7 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Wed, 17 Apr 2019 16:48:56 +0200 Subject: [PATCH 01/13] added .idea files to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3b36470d..261d25f8 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ build node_modules .cache coverage.html + +.idea From 37b92abbe1363142b206102eff2786e1c94659c8 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Wed, 17 Apr 2019 16:50:48 +0200 Subject: [PATCH 02/13] made functional tests stable --- internal/helloworld/greeter_server.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/helloworld/greeter_server.go b/internal/helloworld/greeter_server.go index 47c76165..9a4a175d 100644 --- a/internal/helloworld/greeter_server.go +++ b/internal/helloworld/greeter_server.go @@ -3,7 +3,9 @@ package helloworld import ( "fmt" "io" + "math/rand" "sync" + "time" context "golang.org/x/net/context" "google.golang.org/grpc/stats" @@ -35,12 +37,19 @@ type Greeter struct { callCounts map[CallType]int } +func RandomSleep() { + msCount := rand.Intn(4) + 1 + time.Sleep(time.Millisecond * time.Duration(msCount)) +} + // SayHello implements helloworld.GreeterServer func (s *Greeter) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, error) { s.mutex.Lock() s.callCounts[Unary]++ s.mutex.Unlock() + RandomSleep() + return &HelloReply{Message: "Hello " + in.Name}, nil } @@ -50,6 +59,8 @@ func (s *Greeter) SayHellos(req *HelloRequest, stream Greeter_SayHellosServer) e s.callCounts[ServerStream]++ s.mutex.Unlock() + RandomSleep() + for _, msg := range s.streamData { if err := stream.Send(msg); err != nil { return err @@ -65,6 +76,8 @@ func (s *Greeter) SayHelloCS(stream Greeter_SayHelloCSServer) error { s.callCounts[ClientStream]++ s.mutex.Unlock() + RandomSleep() + msgCount := 0 for { @@ -86,6 +99,8 @@ func (s *Greeter) SayHelloBidi(stream Greeter_SayHelloBidiServer) error { s.callCounts[Bidi]++ s.mutex.Unlock() + RandomSleep() + for { in, err := stream.Recv() if err == io.EOF { @@ -197,4 +212,4 @@ func (c *HWStatsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { // TagRPC implements per-RPC context management. func (c *HWStatsHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context { return ctx -} +} \ No newline at end of file From 107b29cb32c436e83f03eebd056e13ee108863f9 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Thu, 18 Apr 2019 16:24:42 +0200 Subject: [PATCH 03/13] fixed some typos in comments --- runner/call_template_data.go | 2 +- runner/data.go | 4 ++-- runner/reporter.go | 2 +- runner/requester.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/runner/call_template_data.go b/runner/call_template_data.go index adaa71f5..7dae8bd2 100644 --- a/runner/call_template_data.go +++ b/runner/call_template_data.go @@ -12,7 +12,7 @@ import ( // call template data type callTemplateData struct { WorkerID string // unique worker ID - RequestNumber int64 // unique incrememnted request number for each request + RequestNumber int64 // unique incremented request number for each request FullyQualifiedName string // fully-qualified name of the method call MethodName string // shorter call method name ServiceName string // the service name diff --git a/runner/data.go b/runner/data.go index 0519e88e..fa27ef99 100644 --- a/runner/data.go +++ b/runner/data.go @@ -12,8 +12,8 @@ import ( ) // creates a message from a map -// marshal to JSON then use jsonb to marshal to message -// this way we follow protobuf more closely and allow cammelCase properties. +// marshal to JSON then use jsonpb to marshal to message +// this way we follow protobuf more closely and allow camelCase properties. func messageFromMap(input *dynamic.Message, data *map[string]interface{}) error { strData, err := json.Marshal(data) if err != nil { diff --git a/runner/reporter.go b/runner/reporter.go index 891a3459..44b1f7e1 100644 --- a/runner/reporter.go +++ b/runner/reporter.go @@ -6,7 +6,7 @@ import ( "time" ) -// Reporter gethers all the results +// Reporter gathers all the results type Reporter struct { config *RunConfig diff --git a/runner/requester.go b/runner/requester.go index b0fb2acb..83b1c7c3 100644 --- a/runner/requester.go +++ b/runner/requester.go @@ -77,7 +77,7 @@ func newRequester(c *RunConfig) (*Requester, error) { } else if c.protoset != "" { mtd, err = protodesc.GetMethodDescFromProtoSet(c.call, c.protoset) } else { - // use reflection to get method decriptor + // use reflection to get method descriptor var cc *grpc.ClientConn // temporary connection for reflection, do not store as requester connections cc, err = reqr.newClientConn(false) From 83c25fe70001ce3902d336c23fa7e0b7e1011f88 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Thu, 18 Apr 2019 17:37:43 +0200 Subject: [PATCH 04/13] createPayloads doesn't care about streaming --- runner/data.go | 52 +++++++++++--------------------- runner/data_test.go | 73 +++++++++++++++++++++++---------------------- runner/worker.go | 17 +++++------ 3 files changed, 64 insertions(+), 78 deletions(-) diff --git a/runner/data.go b/runner/data.go index fa27ef99..e5aacbeb 100644 --- a/runner/data.go +++ b/runner/data.go @@ -28,71 +28,55 @@ func messageFromMap(input *dynamic.Message, data *map[string]interface{}) error return nil } -func createPayloads(data string, mtd *desc.MethodDescriptor) (*dynamic.Message, *[]*dynamic.Message, error) { +func createPayloads(data string, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { md := mtd.GetInputType() - var input *dynamic.Message - var streamInput []*dynamic.Message + var inputs []*dynamic.Message if len(data) > 0 { if strings.IndexRune(data, '[') == 0 { dataArray := make([]map[string]interface{}, 5) err := json.Unmarshal([]byte(data), &dataArray) if err != nil { - return nil, nil, fmt.Errorf("Error unmarshalling payload. Data: '%v' Error: %v", data, err.Error()) + return nil, fmt.Errorf("Error unmarshalling payload. Data: '%v' Error: %v", data, err.Error()) } elems := len(dataArray) if elems > 0 { - streamInput = make([]*dynamic.Message, elems) + inputs = make([]*dynamic.Message, elems) } for i, elem := range dataArray { elemMsg := dynamic.NewMessage(md) err := messageFromMap(elemMsg, &elem) if err != nil { - return nil, nil, fmt.Errorf("Error creating message: %v", err.Error()) + return nil, fmt.Errorf("Error creating message: %v", err.Error()) } - streamInput[i] = elemMsg + inputs[i] = elemMsg } } else { - input = dynamic.NewMessage(md) - err := jsonpb.UnmarshalString(data, input) + inputs = make([]*dynamic.Message, 1) + inputs[0] = dynamic.NewMessage(md) + err := jsonpb.UnmarshalString(data, inputs[0]) if err != nil { - return nil, nil, fmt.Errorf("Error creating message from data. Data: '%v' Error: %v", data, err.Error()) + return nil, fmt.Errorf("Error creating message from data. Data: '%v' Error: %v", data, err.Error()) } } } - if mtd.IsClientStreaming() && len(streamInput) == 0 && input != nil { - streamInput = make([]*dynamic.Message, 1) - streamInput[0] = input - input = nil - } - - if !mtd.IsClientStreaming() && input == nil && len(streamInput) > 0 { - input = streamInput[0] - streamInput = nil - } - - return input, &streamInput, nil + return &inputs, nil } -func createPayloadsFromBin(binData []byte, mtd *desc.MethodDescriptor) (*dynamic.Message, *[]*dynamic.Message, error) { +func createPayloadsFromBin(binData []byte, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { md := mtd.GetInputType() - input := dynamic.NewMessage(md) - streamInput := make([]*dynamic.Message, 1) - err := proto.Unmarshal(binData, input) - if err != nil { - return nil, nil, fmt.Errorf("Error creating message from binary data: %v", err.Error()) - } + inputs := make([]*dynamic.Message, 1) + inputs[0] = dynamic.NewMessage(md) - if mtd.IsClientStreaming() && input != nil { - streamInput = make([]*dynamic.Message, 1) - streamInput[0] = input - input = nil + err := proto.Unmarshal(binData, inputs[0]) + if err != nil { + return nil, fmt.Errorf("Error creating message from binary data: %v", err.Error()) } - return input, &streamInput, nil + return &inputs, nil } diff --git a/runner/data_test.go b/runner/data_test.go index 25c880c5..d8a6e6d0 100644 --- a/runner/data_test.go +++ b/runner/data_test.go @@ -43,10 +43,9 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, mtdTestUnaryTwo) t.Run("get nil, empty when empty", func(t *testing.T) { - single, streaming, err := createPayloads("", mtdUnary) + inputs, err := createPayloads("", mtdUnary) assert.NoError(t, err) - assert.Nil(t, single) - assert.Empty(t, streaming) + assert.Empty(t, inputs) }) t.Run("fail for invalid data shape", func(t *testing.T) { @@ -56,22 +55,24 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdUnary) + inputs, err := createPayloads(string(jsonData), mtdUnary) assert.Error(t, err) - assert.Nil(t, single) - assert.Nil(t, streaming) + assert.Nil(t, inputs) }) + // TODO: update tests below that comment + t.Run("create single object from map for unary", func(t *testing.T) { m1 := make(map[string]interface{}) m1["name"] = "bob" jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdUnary) + inputs, err := createPayloads(string(jsonData), mtdUnary) assert.NoError(t, err) - assert.NotNil(t, single) - assert.Empty(t, streaming) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.NotNil(t, (*inputs)[0]) }) t.Run("create array from map for client streaming", func(t *testing.T) { @@ -80,11 +81,11 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdClientStreaming) + inputs, err := createPayloads(string(jsonData), mtdClientStreaming) assert.NoError(t, err) - assert.Nil(t, single) - assert.NotNil(t, streaming) - assert.Len(t, *streaming, 1) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.NotNil(t, (*inputs)[0]) }) t.Run("create slice of messages from slice for client streaming", func(t *testing.T) { @@ -98,11 +99,10 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - single, streaming, err := createPayloads(string(jsonData), mtdClientStreaming) + inputs, err := createPayloads(string(jsonData), mtdClientStreaming) assert.NoError(t, err) - assert.Nil(t, single) - assert.NotNil(t, streaming) - assert.Len(t, *streaming, 2) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 2) }) t.Run("fail on invalid shape of data in slice for client streaming", func(t *testing.T) { @@ -120,10 +120,9 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - single, streaming, err := createPayloads(string(jsonData), mtdClientStreaming) + inputs, err := createPayloads(string(jsonData), mtdClientStreaming) assert.Error(t, err) - assert.Nil(t, single) - assert.Nil(t, streaming) + assert.Nil(t, inputs) }) t.Run("get object for slice and unary", func(t *testing.T) { @@ -140,10 +139,10 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - single, streaming, err := createPayloads(string(jsonData), mtdUnary) + inputs, err := createPayloads(string(jsonData), mtdUnary) assert.NoError(t, err) - assert.NotNil(t, single) - assert.Empty(t, streaming) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 3) }) t.Run("create single object from map for unary with camelCase property", func(t *testing.T) { @@ -152,10 +151,11 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdTestUnary) + inputs, err := createPayloads(string(jsonData), mtdTestUnary) assert.NoError(t, err) - assert.NotNil(t, single) - assert.Empty(t, streaming) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.NotNil(t, (*inputs)[0]) }) t.Run("create single object from map for unary with snake_case property", func(t *testing.T) { @@ -164,10 +164,11 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdTestUnary) + inputs, err := createPayloads(string(jsonData), mtdTestUnary) assert.NoError(t, err) - assert.NotNil(t, single) - assert.Empty(t, streaming) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.NotNil(t, (*inputs)[0]) }) t.Run("create single object from map for unary with nested camelCase property", func(t *testing.T) { @@ -179,10 +180,11 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdTestUnaryTwo) + inputs, err := createPayloads(string(jsonData), mtdTestUnaryTwo) assert.NoError(t, err) - assert.NotNil(t, single) - assert.Empty(t, streaming) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.NotNil(t, (*inputs)[0]) }) t.Run("create single object from map for unary with nested snake_case property", func(t *testing.T) { @@ -194,9 +196,10 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - single, streaming, err := createPayloads(string(jsonData), mtdTestUnaryTwo) + inputs, err := createPayloads(string(jsonData), mtdTestUnaryTwo) assert.NoError(t, err) - assert.NotNil(t, single) - assert.Empty(t, streaming) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.NotNil(t, (*inputs)[0]) }) } diff --git a/runner/worker.go b/runner/worker.go index 8b9cf81a..b6e4b724 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -13,7 +13,7 @@ import ( "google.golang.org/grpc/metadata" ) -// Worker is used for doing a single stream of requests in parallerl +// Worker is used for doing a single stream of requests in parallel type Worker struct { stub grpcdynamic.Stub mtd *desc.MethodDescriptor @@ -57,21 +57,20 @@ func (w *Worker) makeRequest() error { ctd := newCallTemplateData(w.mtd, w.workerID, reqNum) - var input *dynamic.Message - var streamInput *[]*dynamic.Message + var inputs *[]*dynamic.Message if !w.config.binary { data, err := ctd.executeData(string(w.config.data)) if err != nil { return err } - input, streamInput, err = createPayloads(string(data), w.mtd) + inputs, err = createPayloads(string(data), w.mtd) if err != nil { return err } } else { var err error - input, streamInput, err = createPayloadsFromBin(w.config.data, w.mtd) + inputs, err = createPayloadsFromBin(w.config.data, w.mtd) if err != nil { return err } @@ -106,17 +105,17 @@ func (w *Worker) makeRequest() error { // RPC errors are handled via stats handler if w.mtd.IsClientStreaming() && w.mtd.IsServerStreaming() { - _ = w.makeBidiRequest(&ctx, streamInput) + _ = w.makeBidiRequest(&ctx, inputs) } if w.mtd.IsClientStreaming() { - _ = w.makeClientStreamingRequest(&ctx, streamInput) + _ = w.makeClientStreamingRequest(&ctx, inputs) } if w.mtd.IsServerStreaming() { - _ = w.makeServerStreamingRequest(&ctx, input) + _ = w.makeServerStreamingRequest(&ctx, (*inputs)[0]) } // TODO: handle response? - _, _ = w.stub.InvokeRpc(ctx, w.mtd, input) + _, _ = w.stub.InvokeRpc(ctx, w.mtd, (*inputs)[0]) return err } From 4faac03ea54c700ac664da4729bcfda16ddb8fdf Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Thu, 18 Apr 2019 17:52:21 +0200 Subject: [PATCH 05/13] worker selects message in round-robin --- runner/worker.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/runner/worker.go b/runner/worker.go index b6e4b724..cac4b658 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -2,6 +2,7 @@ package runner import ( "context" + "fmt" "io" "sync/atomic" "time" @@ -110,12 +111,19 @@ func (w *Worker) makeRequest() error { if w.mtd.IsClientStreaming() { _ = w.makeClientStreamingRequest(&ctx, inputs) } - if w.mtd.IsServerStreaming() { - _ = w.makeServerStreamingRequest(&ctx, (*inputs)[0]) + + inputsLen := len(*inputs) + if inputsLen == 0 { + return fmt.Errorf("Error: can't create a request without payload. Check your data"); } + inputIdx := int(reqNum % int64(inputsLen)) + if w.mtd.IsServerStreaming() { + _ = w.makeServerStreamingRequest(&ctx, (*inputs)[inputIdx]) + } // TODO: handle response? - _, _ = w.stub.InvokeRpc(ctx, w.mtd, (*inputs)[0]) + _, _ = w.stub.InvokeRpc(ctx, w.mtd, (*inputs)[inputIdx]) + return err } From 983cad0e75f26b806cee4cd9d3292acabbd6dcd4 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Fri, 19 Apr 2019 15:30:41 +0200 Subject: [PATCH 06/13] added tests --- internal/helloworld/greeter_server.go | 82 ++++++++++++++++++-------- runner/data_test.go | 18 +++--- runner/run_test.go | 83 +++++++++++++++++++++++++++ runner/worker.go | 2 +- 4 files changed, 149 insertions(+), 36 deletions(-) diff --git a/internal/helloworld/greeter_server.go b/internal/helloworld/greeter_server.go index 9a4a175d..ed81d633 100644 --- a/internal/helloworld/greeter_server.go +++ b/internal/helloworld/greeter_server.go @@ -15,7 +15,7 @@ import ( // unary, client streaming, server streaming, bidi type CallType string -// Unary is a uniry call +// Unary is a unary call var Unary CallType = "unary" // ClientStream is a client streaming call @@ -35,31 +35,48 @@ type Greeter struct { mutex *sync.RWMutex callCounts map[CallType]int + calls map[CallType][][]*HelloRequest } -func RandomSleep() { +func randomSleep() { msCount := rand.Intn(4) + 1 time.Sleep(time.Millisecond * time.Duration(msCount)) } +func (s *Greeter) recordCall(ct CallType) int { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.callCounts[ct]++ + var messages []*HelloRequest + s.calls[ct] = append(s.calls[ct], messages) + + return len(s.calls[ct]) - 1 +} + +func (s *Greeter) recordMessage(ct CallType, callIdx int, msg *HelloRequest) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.calls[ct][callIdx] = append(s.calls[ct][callIdx], msg) +} + // SayHello implements helloworld.GreeterServer func (s *Greeter) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, error) { - s.mutex.Lock() - s.callCounts[Unary]++ - s.mutex.Unlock() + callIdx := s.recordCall(Unary) + s.recordMessage(Unary, callIdx, in) - RandomSleep() + randomSleep() return &HelloReply{Message: "Hello " + in.Name}, nil } // SayHellos lists all hellos func (s *Greeter) SayHellos(req *HelloRequest, stream Greeter_SayHellosServer) error { - s.mutex.Lock() - s.callCounts[ServerStream]++ - s.mutex.Unlock() + callIdx := s.recordCall(ServerStream) + s.recordMessage(ServerStream, callIdx, req) - RandomSleep() + randomSleep() for _, msg := range s.streamData { if err := stream.Send(msg); err != nil { @@ -72,16 +89,14 @@ func (s *Greeter) SayHellos(req *HelloRequest, stream Greeter_SayHellosServer) e // SayHelloCS is client streaming handler func (s *Greeter) SayHelloCS(stream Greeter_SayHelloCSServer) error { - s.mutex.Lock() - s.callCounts[ClientStream]++ - s.mutex.Unlock() + callIdx := s.recordCall(ClientStream) - RandomSleep() + randomSleep() msgCount := 0 for { - _, err := stream.Recv() + in, err := stream.Recv() if err == io.EOF { msgStr := fmt.Sprintf("Hello count: %d", msgCount) return stream.SendAndClose(&HelloReply{Message: msgStr}) @@ -89,17 +104,16 @@ func (s *Greeter) SayHelloCS(stream Greeter_SayHelloCSServer) error { if err != nil { return err } + s.recordMessage(ClientStream, callIdx, in) msgCount++ } } // SayHelloBidi duplex call handler func (s *Greeter) SayHelloBidi(stream Greeter_SayHelloBidiServer) error { - s.mutex.Lock() - s.callCounts[Bidi]++ - s.mutex.Unlock() + callIdx := s.recordCall(Bidi) - RandomSleep() + randomSleep() for { in, err := stream.Recv() @@ -110,6 +124,7 @@ func (s *Greeter) SayHelloBidi(stream Greeter_SayHelloBidiServer) error { return err } + s.recordMessage(Bidi, callIdx, in) msg := "Hello " + in.Name if err := stream.Send(&HelloReply{Message: msg}); err != nil { return err @@ -120,10 +135,19 @@ func (s *Greeter) SayHelloBidi(stream Greeter_SayHelloBidiServer) error { // ResetCounters resets the call counts func (s *Greeter) ResetCounters() { s.mutex.Lock() + + s.callCounts = make(map[CallType]int) s.callCounts[Unary] = 0 s.callCounts[ServerStream] = 0 s.callCounts[ClientStream] = 0 s.callCounts[Bidi] = 0 + + s.calls = make(map[CallType][][]*HelloRequest) + s.calls[Unary] = make([][]*HelloRequest, 0) + s.calls[ServerStream] = make([][]*HelloRequest, 0) + s.calls[ClientStream] = make([][]*HelloRequest, 0) + s.calls[Bidi] = make([][]*HelloRequest, 0) + s.mutex.Unlock() if s.Stats != nil { @@ -144,6 +168,17 @@ func (s *Greeter) GetCount(key CallType) int { return -1 } +func (s *Greeter) GetCalls(key CallType) [][]*HelloRequest { + s.mutex.Lock() + val, ok := s.calls[key] + s.mutex.Unlock() + + if ok { + return val + } + return nil +} + // GetConnectionCount gets the connection count func (s *Greeter) GetConnectionCount() int { return s.Stats.GetConnectionCount() @@ -158,13 +193,10 @@ func NewGreeter() *Greeter { &HelloReply{Message: "Hello Sara"}, } - m := make(map[CallType]int) - m[Unary] = 0 - m[ServerStream] = 0 - m[ClientStream] = 0 - m[Bidi] = 0 + greeter := &Greeter{streamData: streamData, mutex: &sync.RWMutex{}} + greeter.ResetCounters() - return &Greeter{streamData: streamData, callCounts: m, mutex: &sync.RWMutex{}} + return greeter } // NewHWStats creates new stats handler diff --git a/runner/data_test.go b/runner/data_test.go index d8a6e6d0..c2b7eb81 100644 --- a/runner/data_test.go +++ b/runner/data_test.go @@ -42,7 +42,7 @@ func TestData_createPayloads(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, mtdTestUnaryTwo) - t.Run("get nil, empty when empty", func(t *testing.T) { + t.Run("get empty when empty", func(t *testing.T) { inputs, err := createPayloads("", mtdUnary) assert.NoError(t, err) assert.Empty(t, inputs) @@ -60,9 +60,7 @@ func TestData_createPayloads(t *testing.T) { assert.Nil(t, inputs) }) - // TODO: update tests below that comment - - t.Run("create single object from map for unary", func(t *testing.T) { + t.Run("create slice with single element from map for unary", func(t *testing.T) { m1 := make(map[string]interface{}) m1["name"] = "bob" @@ -75,7 +73,7 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, (*inputs)[0]) }) - t.Run("create array from map for client streaming", func(t *testing.T) { + t.Run("create slice with single element from map for client streaming", func(t *testing.T) { m1 := make(map[string]interface{}) m1["name"] = "bob" @@ -125,7 +123,7 @@ func TestData_createPayloads(t *testing.T) { assert.Nil(t, inputs) }) - t.Run("get object for slice and unary", func(t *testing.T) { + t.Run("create slice of messages from slice for unary", func(t *testing.T) { m1 := make(map[string]interface{}) m1["name"] = "bob" @@ -145,7 +143,7 @@ func TestData_createPayloads(t *testing.T) { assert.Len(t, *inputs, 3) }) - t.Run("create single object from map for unary with camelCase property", func(t *testing.T) { + t.Run("create slice with single object from map for unary with camelCase property", func(t *testing.T) { m1 := make(map[string]interface{}) m1["paramOne"] = "bob" @@ -158,7 +156,7 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, (*inputs)[0]) }) - t.Run("create single object from map for unary with snake_case property", func(t *testing.T) { + t.Run("create slice with single object from map for unary with snake_case property", func(t *testing.T) { m1 := make(map[string]interface{}) m1["param_one"] = "bob" @@ -171,7 +169,7 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, (*inputs)[0]) }) - t.Run("create single object from map for unary with nested camelCase property", func(t *testing.T) { + t.Run("create slice with single object from map for unary with nested camelCase property", func(t *testing.T) { inner := make(map[string]interface{}) inner["paramOne"] = "bob" @@ -187,7 +185,7 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, (*inputs)[0]) }) - t.Run("create single object from map for unary with nested snake_case property", func(t *testing.T) { + t.Run("create slice with single object from map for unary with nested snake_case property", func(t *testing.T) { inner := make(map[string]interface{}) inner["param_one"] = "bob" diff --git a/runner/run_test.go b/runner/run_test.go index 06d1c319..a5caf439 100644 --- a/runner/run_test.go +++ b/runner/run_test.go @@ -1,6 +1,7 @@ package runner import ( + "strconv" "sync" "testing" "time" @@ -266,6 +267,88 @@ func TestRunUnary(t *testing.T) { connCount := gs.GetConnectionCount() assert.Equal(t, 5, connCount) }) + + t.Run("test round-robin c = 2", func(t *testing.T) { + gs.ResetCounters() + + data := make([]map[string]interface{}, 3) + for i:= 0; i < 3; i++ { + data[i] = make(map[string]interface{}) + data[i]["name"] = strconv.Itoa(i) + } + + report, err := Run( + "helloworld.Greeter.SayHello", + internal.TestLocalhost, + WithProtoFile("../testdata/greeter.proto", []string{}), + WithTotalRequests(6), + WithConcurrency(2), + WithTimeout(time.Duration(20*time.Second)), + WithDialTimeout(time.Duration(20*time.Second)), + WithInsecure(true), + WithData(data), + ) + + assert.NoError(t, err) + assert.NotNil(t, report) + + count := gs.GetCount(callType) + assert.Equal(t, 6, count) + + calls := gs.GetCalls(callType) + assert.NotNil(t, calls) + assert.Len(t, calls, 6) + names := make([]string, 0) + for _, msgs := range calls { + for _, msg := range msgs { + names = append(names, msg.GetName()) + } + } + + // we don't expect to have the same order of elements since requests are concurrent + assert.ElementsMatch(t, []string {"0", "1", "2", "0", "1", "2"}, names) + }) + + t.Run("test round-robin c = 1", func(t *testing.T) { + gs.ResetCounters() + + data := make([]map[string]interface{}, 3) + for i:= 0; i < 3; i++ { + data[i] = make(map[string]interface{}) + data[i]["name"] = strconv.Itoa(i) + } + + report, err := Run( + "helloworld.Greeter.SayHello", + internal.TestLocalhost, + WithProtoFile("../testdata/greeter.proto", []string{}), + WithTotalRequests(6), + WithConcurrency(1), + WithTimeout(time.Duration(20*time.Second)), + WithDialTimeout(time.Duration(20*time.Second)), + WithInsecure(true), + WithData(data), + ) + + assert.NoError(t, err) + assert.NotNil(t, report) + + count := gs.GetCount(callType) + assert.Equal(t, 6, count) + + calls := gs.GetCalls(callType) + assert.NotNil(t, calls) + assert.Len(t, calls, 6) + names := make([]string, 0) + for _, msgs := range calls { + for _, msg := range msgs { + names = append(names, msg.GetName()) + } + } + + // we expect the same order of messages with single worker + assert.Equal(t, []string {"0", "1", "2", "0", "1", "2"}, names) + }) } func TestRunServerStreaming(t *testing.T) { diff --git a/runner/worker.go b/runner/worker.go index cac4b658..0bb70b4a 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -116,7 +116,7 @@ func (w *Worker) makeRequest() error { if inputsLen == 0 { return fmt.Errorf("Error: can't create a request without payload. Check your data"); } - inputIdx := int(reqNum % int64(inputsLen)) + inputIdx := int((reqNum - 1) % int64(inputsLen)) // we want to start from inputs[0] so dec reqNum if w.mtd.IsServerStreaming() { _ = w.makeServerStreamingRequest(&ctx, (*inputs)[inputIdx]) From 95f479e966c42c2063c3717967c37da08e45cbf5 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Fri, 19 Apr 2019 17:53:31 +0200 Subject: [PATCH 07/13] implemented count-delimited binary format --- runner/data.go | 47 +++++++++++++++++++++++++++++++++---- runner/data_test.go | 57 ++++++++++++++++++++++++++++++++++++--------- runner/run_test.go | 44 ++++++++++++++++++++++++++++++++++ runner/worker.go | 7 +++--- 4 files changed, 136 insertions(+), 19 deletions(-) diff --git a/runner/data.go b/runner/data.go index e5aacbeb..365b2230 100644 --- a/runner/data.go +++ b/runner/data.go @@ -3,6 +3,7 @@ package runner import ( "encoding/json" "fmt" + "io" "strings" "github.com/golang/protobuf/jsonpb" @@ -28,7 +29,7 @@ func messageFromMap(input *dynamic.Message, data *map[string]interface{}) error return nil } -func createPayloads(data string, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { +func createPayloadsFromJson(data string, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { md := mtd.GetInputType() var inputs []*dynamic.Message @@ -67,16 +68,52 @@ func createPayloads(data string, mtd *desc.MethodDescriptor) (*[]*dynamic.Messag return &inputs, nil } -func createPayloadsFromBin(binData []byte, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { +func createPayloadsFromBinSingleMessage(binData []byte, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { + var inputs []*dynamic.Message md := mtd.GetInputType() - inputs := make([]*dynamic.Message, 1) - inputs[0] = dynamic.NewMessage(md) + // return empty array if no data + if len(binData) == 0 { + return &inputs, nil + } - err := proto.Unmarshal(binData, inputs[0]) + // try to unmarshal input as a single message + singleMessage := dynamic.NewMessage(md) + err := proto.Unmarshal(binData, singleMessage) if err != nil { return nil, fmt.Errorf("Error creating message from binary data: %v", err.Error()) } + inputs = make([]*dynamic.Message, 1) + inputs[0] = singleMessage + + return &inputs, nil +} + +func createPayloadsFromBinCountDelimited(binData []byte, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { + var inputs []*dynamic.Message + md := mtd.GetInputType() + + // return empty array if no data + if len(binData) == 0 { + return &inputs, nil + } + + // try to unmarshal input as several count-delimited messages + buffer := proto.NewBuffer(binData) + for { + msg := dynamic.NewMessage(md) + err := buffer.DecodeMessage(msg) + + if err == io.ErrUnexpectedEOF { + break + } + + if err != nil { + return nil, fmt.Errorf("Error creating message from binary data: %v", err.Error()) + } + + inputs = append(inputs, msg) + } return &inputs, nil } diff --git a/runner/data_test.go b/runner/data_test.go index c2b7eb81..7bc5eee8 100644 --- a/runner/data_test.go +++ b/runner/data_test.go @@ -2,6 +2,8 @@ package runner import ( "encoding/json" + "github.com/bojand/ghz/testdata" + "github.com/golang/protobuf/proto" "testing" "github.com/bojand/ghz/protodesc" @@ -43,7 +45,7 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, mtdTestUnaryTwo) t.Run("get empty when empty", func(t *testing.T) { - inputs, err := createPayloads("", mtdUnary) + inputs, err := createPayloadsFromJson("", mtdUnary) assert.NoError(t, err) assert.Empty(t, inputs) }) @@ -55,7 +57,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdUnary) + inputs, err := createPayloadsFromJson(string(jsonData), mtdUnary) assert.Error(t, err) assert.Nil(t, inputs) }) @@ -66,7 +68,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdUnary) + inputs, err := createPayloadsFromJson(string(jsonData), mtdUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -79,7 +81,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdClientStreaming) + inputs, err := createPayloadsFromJson(string(jsonData), mtdClientStreaming) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -97,7 +99,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - inputs, err := createPayloads(string(jsonData), mtdClientStreaming) + inputs, err := createPayloadsFromJson(string(jsonData), mtdClientStreaming) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 2) @@ -118,7 +120,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - inputs, err := createPayloads(string(jsonData), mtdClientStreaming) + inputs, err := createPayloadsFromJson(string(jsonData), mtdClientStreaming) assert.Error(t, err) assert.Nil(t, inputs) }) @@ -137,7 +139,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - inputs, err := createPayloads(string(jsonData), mtdUnary) + inputs, err := createPayloadsFromJson(string(jsonData), mtdUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 3) @@ -149,7 +151,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdTestUnary) + inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -162,7 +164,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdTestUnary) + inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -178,7 +180,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdTestUnaryTwo) + inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnaryTwo) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -194,10 +196,43 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloads(string(jsonData), mtdTestUnaryTwo) + inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnaryTwo) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) assert.NotNil(t, (*inputs)[0]) }) + + t.Run("create slice from single message binary data", func(t *testing.T) { + msg1 := &helloworld.HelloRequest{} + msg1.Name = "bob" + + binData, err := proto.Marshal(msg1) + + inputs, err := createPayloadsFromBinSingleMessage(binData, mtdUnary) + + assert.NoError(t, err) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 1) + assert.EqualValues(t, msg1.GetName(), (*inputs)[0].GetFieldByName("name")) + }) + + t.Run("create slice from count-delimited binary data", func(t *testing.T) { + msg1 := &helloworld.HelloRequest{} + msg1.Name = "bob" + msg2 := &helloworld.HelloRequest{} + msg2.Name = "alice" + + buf := proto.Buffer{} + _ = buf.EncodeMessage(msg1) + _ = buf.EncodeMessage(msg2) + + inputs, err := createPayloadsFromBinCountDelimited(buf.Bytes(), mtdUnary) + + assert.NoError(t, err) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 2) + assert.EqualValues(t, msg1.GetName(), (*inputs)[0].GetFieldByName("name")) + assert.EqualValues(t, msg2.GetName(), (*inputs)[1].GetFieldByName("name")) + }) } diff --git a/runner/run_test.go b/runner/run_test.go index a5caf439..ff765da4 100644 --- a/runner/run_test.go +++ b/runner/run_test.go @@ -349,6 +349,50 @@ func TestRunUnary(t *testing.T) { // we expect the same order of messages with single worker assert.Equal(t, []string {"0", "1", "2", "0", "1", "2"}, names) }) + + // todo fix this test + //t.Run("test round-robin binary", func(t *testing.T) { + // gs.ResetCounters() + // + // buf := proto.Buffer{} + // for i := 0; i < 3; i++ { + // msg := &helloworld.HelloRequest{} + // msg.Name = strconv.Itoa(i) + // err = buf.EncodeMessage(msg) + // assert.NoError(t, err) + // } + // binData := buf.Bytes() + // + // report, err := Run( + // "helloworld.Greeter.SayHello", + // internal.TestLocalhost, + // WithProtoFile("../testdata/greeter.proto", []string{}), + // WithTotalRequests(6), + // WithConcurrency(1), + // WithTimeout(time.Duration(20*time.Second)), + // WithDialTimeout(time.Duration(20*time.Second)), + // WithInsecure(true), + // WithBinaryDataCountDelimited(binData), + // ) + // + // assert.NoError(t, err) + // assert.NotNil(t, report) + // + // count := gs.GetCount(callType) + // assert.Equal(t, 6, count) + // + // calls := gs.GetCalls(callType) + // assert.NotNil(t, calls) + // assert.Len(t, calls, 6) + // names := make([]string, 0) + // for _, msgs := range calls { + // for _, msg := range msgs { + // names = append(names, msg.GetName()) + // } + // } + // + // assert.Equal(t, []string {"0", "1", "2", "0", "1", "2"}, names) + //}) } func TestRunServerStreaming(t *testing.T) { diff --git a/runner/worker.go b/runner/worker.go index 0bb70b4a..642809c4 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -65,13 +65,14 @@ func (w *Worker) makeRequest() error { if err != nil { return err } - inputs, err = createPayloads(string(data), w.mtd) + inputs, err = createPayloadsFromJson(string(data), w.mtd) if err != nil { return err } } else { var err error - inputs, err = createPayloadsFromBin(w.config.data, w.mtd) + // todo we need an explicit way to choose between binary formats, it's impossible to distinguish from data itself + inputs, err = createPayloadsFromBinSingleMessage(w.config.data, w.mtd) if err != nil { return err } @@ -114,7 +115,7 @@ func (w *Worker) makeRequest() error { inputsLen := len(*inputs) if inputsLen == 0 { - return fmt.Errorf("Error: can't create a request without payload. Check your data"); + return fmt.Errorf("no data provided for request") } inputIdx := int((reqNum - 1) % int64(inputsLen)) // we want to start from inputs[0] so dec reqNum From b70d4f191f09507a2d4e91baa40ef202a4817603 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Tue, 23 Apr 2019 10:48:23 +0200 Subject: [PATCH 08/13] regenerated expired test keys --- testdata/localhost.crt | 33 ++++++++++++++------------- testdata/localhost.key | 52 +++++++++++++++++++++--------------------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/testdata/localhost.crt b/testdata/localhost.crt index 97ac9e34..235c2022 100644 --- a/testdata/localhost.crt +++ b/testdata/localhost.crt @@ -1,18 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIC5TCCAc2gAwIBAgIJANAD3xBGYRogMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV -BAMMCWxvY2FsaG9zdDAeFw0xOTAzMjMyMDQxMTdaFw0xOTA0MjIyMDQxMTdaMBQx -EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBANMQulnt3eaWvihW9aRMOyHHgQRwjlo9zR3vZFNwzq/YRuzIcUng/KLXWkkH -EWEkvtL641hi6QgPHQAzXuQ5JVthamQ4n86fcRseK85v1WZOYg1P1KPFpFxXdcA8 -izDrX7tJuIEosOmapsTj8v7Wkm7LVGWtkUl6FG5BKA+deNnJb7ewadB5HkaCP2c3 -s2JDcqFpuI05EQ1wnSuFYmUIuDa9kiaLYlMs3YfW525sigER03QorxqC0SR2PCW/ -qZ1wFZpmuJRc7B4ihIUiTgY353bRje0ouNV4ZnKlJUswD4EnSFjFD2AXo7ECnNHE -O/3qcaj2MVguswWrS5Q2Vqef0m8CAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo -b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B -AQsFAAOCAQEApghSG3N1fdQVGsoRii9b8mpsldOX0M5cZD2k4e4QKrIXAxyl7KDM -IqOi483NX1XEvBsvBGgNw4QO9koRagcf2oLjVmhSYOkj7qyU8P4AEcm7MnlTiHCL -eRmTxJvnQlDG8vVwzmi9UJm7JyR5en6PBnCt9SYHlakjtV1c4HJNIO2NLs5GukG4 -73xyhCcaazZVzJ7rX5VwnpjcwwNEOGLEZrS5gzUuaGX4AJYbeN5Wweqf6y2H4YqD -BVqB2ChJCOFtmu+49PN3xtdj04MCwMa6zmZSg1eqknkslxrZJuDGBEFCX9j8/XYo -7w+IT4Qgi31pqZMEKWWMymcdyDuW5U3EBA== +MIIDCTCCAfGgAwIBAgIUBFdP+o3pFEAiFP3eIXLd5LibUxIwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MDQyMzA4NDYzOVoXDTIyMDQy +MjA4NDYzOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAz78+udILCGlp6wisUfhh9aVjKT1kfEG3pZhfsYDMvALX +bHYJURkWmuyURcgT0ONhpdtpgjylQQBhXwy4qpFdCwnFea8XwzLySlEMyHIPoWfX +8QYdJZPfZoAlELMuIJ3CErQV025nyNoI8zAng1A3Bn5NIxdQbXFj4RxR8tzqcYyU +DtnZHNQKD3I9g7AvGtMT/tFN257FaqEAveJhhSJAfKY2VFgKGEKdW7nqAKCLtKj2 +kqUHrDcdS4sNmpfLLd0t/ImHJBQRVbqJIjHvaFF316SnMkXImkTMVep53fyvCyo4 +mv7AQCSMHDcD2RabzNeRXNgI6FXMU/Pd4A7wypFRuwIDAQABo1MwUTAdBgNVHQ4E +FgQUK7tKFTosZ7gmNpS5HTbIynkP90YwHwYDVR0jBBgwFoAUK7tKFTosZ7gmNpS5 +HTbIynkP90YwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYLmB +M1UD8VtR5CY2bL0i7c4RgQR4kc3xtrJdTNfDXUIBHvdDISLMmCttiYkq6oLn1jMz +MdCHfiT3IkNS+Y7z966yquxdjCSpKSWJiKxngqCmzc6US1mgHdLeNSQI8xWC8SN1 +8u622Lbjsu4Ho07upE6Bj4Sg5UTEM07kwq93OtJjvxQaUjrWTu9I/E4bVgSsc2W0 +poFhZQ+inCVztE2D34YXZbe6BP9AbCG1UWSPULYAIFUXBDGlkMOa02+2Eh05HNqp +f8VmOQmbBgOtHySi9WnBf138bv+/3UzKAdknFNrwI0jWvelp9hKxykpCzk9RF5S2 +hh804uBR57bA7qlpyg== -----END CERTIFICATE----- diff --git a/testdata/localhost.key b/testdata/localhost.key index 328c380a..2c1c78b0 100644 --- a/testdata/localhost.key +++ b/testdata/localhost.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDTELpZ7d3mlr4o -VvWkTDshx4EEcI5aPc0d72RTcM6v2EbsyHFJ4Pyi11pJBxFhJL7S+uNYYukIDx0A -M17kOSVbYWpkOJ/On3EbHivOb9VmTmINT9SjxaRcV3XAPIsw61+7SbiBKLDpmqbE -4/L+1pJuy1RlrZFJehRuQSgPnXjZyW+3sGnQeR5Ggj9nN7NiQ3KhabiNORENcJ0r -hWJlCLg2vZImi2JTLN2H1udubIoBEdN0KK8agtEkdjwlv6mdcBWaZriUXOweIoSF -Ik4GN+d20Y3tKLjVeGZypSVLMA+BJ0hYxQ9gF6OxApzRxDv96nGo9jFYLrMFq0uU -Nlann9JvAgMBAAECggEBAMB4SadGPYtQPXnlyr0XcvjbyDA3P+jU4J6CtldM0H4U -WKEGLCD11QveHAvqMRQIASe99+Ga2OwrdAPB1K+D2Sgajn10EW7HgMn82m+3Fb/k -jI+dE8iAq+A1NUCnNTrX+QV+NY06gRGVoKx9PhLbss7sBjtuasW5WLYuHo0WyaS2 -31QfZGZDTF+sj/brlocmKkMnq/qpenn1kODLgf7GsOhoh8dKRM2FtxTkyb998nv0 -Lx4b9X2VtYjfSmt3C8Kpxoytm4jWTdhb9KY+wcQTqEAx/9gbSeQTApiQ0mLMfOVl -5tM0+qru4z2DEROyCsda8DjyoNoP9UZRkU65a6dxLUECgYEA71MljjP50SjA6cl6 -xFfPVarwaMLGPQqLQdsLagBC1iXQ9oUtHCXs3qtdFbd7zhaO+OPTesvY4fYtRyWG -fb8WMviNfN35wFf6eTHpnLAGhiUG9TkxguYLw0Pym8KUmmPSo+XQZU0ieRCIwAf3 -9NeMS0psxoVgWMxla2SY9JusMo8CgYEA4cWD9GtGn1Oy3bQicKM5h28rIrnefcJp -Htqxe3Cw9qB8nfYdUlsbm7GPJPk2ihtgHRLkVnq6a9s8TVRYwNcRFJ2ORQKdUEAP -QU08TKkG7sS5JjcRjOuli9n98hoVKxg9AkWgrTXDg8Q/N7Zz6Oespf61lPiTRHmK -T9lq1cXM0iECgYEAm0edhGig3F7O3GGHsEExG2pv1ekaapyewjn3a+2DcCLVND4w -iKTqzYbuPJryT0M/vKlFm9ULgYES26izXH9RTf0LAEueMnhi4aPK6YkkkoEPxKg5 -Qa81TpqVnQ5hENNX5lPEJRYpGdfqgn4pGcmJE4jUjvIXE0Z7P3Tj8UHYNm0CgYEA -ocgZgGIG31Do0TmtnC06ojQlIuMx7cgL79IicCQWiwQBiGe+Jy+mHvEjdAko7dok -C3FoMhgL0hHtqjQQzU7PrIgiVI1FESZ2SAMCfKR6lUpeqmW3q9WIcSiqcnwCQzlB -LomaU8Q88AUGj/OsJ28sJl7Y24Esdlrpo8JWbg0pckECgYEAgo/FQZIeZnKRg3et -BaVZkh2D93Vhi6NTSpdDspxZ53fbX5Dl+q7/f9oh3DroZmrhi8QWLAlBh4w5VA08 -0Vy70PxQtatlo1pKEqdAqUsO5jdmGrJDBh29cUUrzrSVOy0vpHqQ748Ht9Oc+Fdb -JjrW9F/QTmPTfjOENLm139048BI= +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPvz650gsIaWnr +CKxR+GH1pWMpPWR8QbelmF+xgMy8AtdsdglRGRaa7JRFyBPQ42Gl22mCPKVBAGFf +DLiqkV0LCcV5rxfDMvJKUQzIcg+hZ9fxBh0lk99mgCUQsy4gncIStBXTbmfI2gjz +MCeDUDcGfk0jF1BtcWPhHFHy3OpxjJQO2dkc1AoPcj2DsC8a0xP+0U3bnsVqoQC9 +4mGFIkB8pjZUWAoYQp1bueoAoIu0qPaSpQesNx1Liw2al8st3S38iYckFBFVuoki +Me9oUXfXpKcyRciaRMxV6nnd/K8LKjia/sBAJIwcNwPZFpvM15Fc2AjoVcxT893g +DvDKkVG7AgMBAAECggEAIDqECaHLMl/gHaU3znOhBtHEg2ZRy3EKg3cTCV9444Xx +U5MwONOSjTA8hGLYqCRORsO2J40u+dmMQYmgsF1iuM6oQwtlvVOPAPZ37DS9tgV9 +G5geN3EsTCN/HIsfkdHHhM1JQYa0NRWWI9wJlTaBgtFfOB1qzb+0hfy1vd6FxF2K +C8VCTn9zAnZ3pMpGLqT7cClttT4OPNWvvxbr6jzpY0ZKtBkvBW1uCgM7LO/9rcPH +zbRdTAXuK2Y0HM3ARuKmqVsBAY9fiJI6/Jw1wdE3wi0AWDwukIdteJqcQMRG/rmR +x+eadRydmPTMSyL8P0IID7lQolqA9m9usWxDGJOiMQKBgQDx9UTxx8C/0lvHxDuh +sDOJlG+Y5GRIkB5FGoPBX07dGjsNblZwiizfpjUT0WpFps+e/qvIqlYt1D3lPJ/n +tUaC/DnMQQ6yh1X7qmdPIlD6abT9wcrKJMuRDgFhBQw+HQHyBn3Sc1snOL8M5/Da +4FyRIS1Q7a3Iy4O/qauMbVoEqQKBgQDbzbVIVHO290c0bP6WTpGwm/alnVGDzkzv +VlqYxCI1oOwUUSXa9Lr7fQjSp7EVcEoOcc0BdXjWp+njH41AV5rvSbFkZ/wATxdW +lKRrZVNqr5xBFu3K2SJcvmDHYdoc5//THsEtiVQ3TJu2lbazzJIu5ZgGxi3CZSbK +xW8jR3e9wwKBgATfk8vq4g77Ba44XZscGW2j97t0njB39qQdrJmweb4qURYsKsGJ +hu3aQydrCGDuwy/IoV0hUSsLI1QCrJXWKN1qhx9+D/W4lBrFi98kKc1hY6vYw2Te +6Nq7FXwGxgBaRTfCubYLbMKVegOgiFFgQ30I1gjTQLTSpIyvtizV5wJBAoGAYmLe +rUSYEyL2bWIIRxFeJzZ4ncMgVKZIS61UmiLYyTaB1cpI7owzEhTymRBUtKrxiyun +PurtLvA0QeTCnjVYdZl/3NiqtRyx7qBURHozb4Kxp3Ty9aRhvC+/NB/5uIykN0UB +5TceSi5xWLYE9NAx8un0NbwJiYUrawIa8CiyUW8CgYAPcvM50UIpHJUv+BTNhK6K +WqQitWg/JPInBSuMnEVIKlaNtEwNQuXaTq99c5+maL5R1JliRym7OSxpc8G7Q8kb +fWkKo2zGuIDM6rmd0fAfNThRlE9qAlLrfl5DdBwanh7FHAo75Ofm9dCQsSWDPvLn +4QWaxVSGlCRw//FcyHk52Q== -----END PRIVATE KEY----- From b2a6a3e216ceb42d8ac00a4f854620917e8e5bb4 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Tue, 23 Apr 2019 10:50:21 +0200 Subject: [PATCH 09/13] binary format "guessing" --- runner/data.go | 10 ++++++ runner/data_test.go | 13 +++++-- runner/run_test.go | 85 ++++++++++++++++++++++----------------------- runner/worker.go | 3 +- 4 files changed, 64 insertions(+), 47 deletions(-) diff --git a/runner/data.go b/runner/data.go index 365b2230..4305611c 100644 --- a/runner/data.go +++ b/runner/data.go @@ -117,3 +117,13 @@ func createPayloadsFromBinCountDelimited(binData []byte, mtd *desc.MethodDescrip return &inputs, nil } + +func createPayloadsFromBin(binData []byte, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { + inputs, err := createPayloadsFromBinCountDelimited(binData, mtd) + + if err == nil && len(*inputs) > 0 { + return inputs, err + } + + return createPayloadsFromBinSingleMessage(binData, mtd) +} \ No newline at end of file diff --git a/runner/data_test.go b/runner/data_test.go index 7bc5eee8..913be363 100644 --- a/runner/data_test.go +++ b/runner/data_test.go @@ -209,7 +209,7 @@ func TestData_createPayloads(t *testing.T) { binData, err := proto.Marshal(msg1) - inputs, err := createPayloadsFromBinSingleMessage(binData, mtdUnary) + inputs, err := createPayloadsFromBin(binData, mtdUnary) assert.NoError(t, err) assert.NotNil(t, inputs) @@ -227,7 +227,7 @@ func TestData_createPayloads(t *testing.T) { _ = buf.EncodeMessage(msg1) _ = buf.EncodeMessage(msg2) - inputs, err := createPayloadsFromBinCountDelimited(buf.Bytes(), mtdUnary) + inputs, err := createPayloadsFromBin(buf.Bytes(), mtdUnary) assert.NoError(t, err) assert.NotNil(t, inputs) @@ -235,4 +235,13 @@ func TestData_createPayloads(t *testing.T) { assert.EqualValues(t, msg1.GetName(), (*inputs)[0].GetFieldByName("name")) assert.EqualValues(t, msg2.GetName(), (*inputs)[1].GetFieldByName("name")) }) + + t.Run("on empty binary data returns empty slice", func(t *testing.T) { + buf := make([]byte, 0) + inputs, err := createPayloadsFromBin(buf, mtdUnary) + + assert.NoError(t, err) + assert.NotNil(t, inputs) + assert.Len(t, *inputs, 0) + }) } diff --git a/runner/run_test.go b/runner/run_test.go index ff765da4..9c3cfe25 100644 --- a/runner/run_test.go +++ b/runner/run_test.go @@ -350,49 +350,48 @@ func TestRunUnary(t *testing.T) { assert.Equal(t, []string {"0", "1", "2", "0", "1", "2"}, names) }) - // todo fix this test - //t.Run("test round-robin binary", func(t *testing.T) { - // gs.ResetCounters() - // - // buf := proto.Buffer{} - // for i := 0; i < 3; i++ { - // msg := &helloworld.HelloRequest{} - // msg.Name = strconv.Itoa(i) - // err = buf.EncodeMessage(msg) - // assert.NoError(t, err) - // } - // binData := buf.Bytes() - // - // report, err := Run( - // "helloworld.Greeter.SayHello", - // internal.TestLocalhost, - // WithProtoFile("../testdata/greeter.proto", []string{}), - // WithTotalRequests(6), - // WithConcurrency(1), - // WithTimeout(time.Duration(20*time.Second)), - // WithDialTimeout(time.Duration(20*time.Second)), - // WithInsecure(true), - // WithBinaryDataCountDelimited(binData), - // ) - // - // assert.NoError(t, err) - // assert.NotNil(t, report) - // - // count := gs.GetCount(callType) - // assert.Equal(t, 6, count) - // - // calls := gs.GetCalls(callType) - // assert.NotNil(t, calls) - // assert.Len(t, calls, 6) - // names := make([]string, 0) - // for _, msgs := range calls { - // for _, msg := range msgs { - // names = append(names, msg.GetName()) - // } - // } - // - // assert.Equal(t, []string {"0", "1", "2", "0", "1", "2"}, names) - //}) + t.Run("test round-robin binary", func(t *testing.T) { + gs.ResetCounters() + + buf := proto.Buffer{} + for i := 0; i < 3; i++ { + msg := &helloworld.HelloRequest{} + msg.Name = strconv.Itoa(i) + err = buf.EncodeMessage(msg) + assert.NoError(t, err) + } + binData := buf.Bytes() + + report, err := Run( + "helloworld.Greeter.SayHello", + internal.TestLocalhost, + WithProtoFile("../testdata/greeter.proto", []string{}), + WithTotalRequests(6), + WithConcurrency(1), + WithTimeout(time.Duration(20*time.Second)), + WithDialTimeout(time.Duration(20*time.Second)), + WithInsecure(true), + WithBinaryData(binData), + ) + + assert.NoError(t, err) + assert.NotNil(t, report) + + count := gs.GetCount(callType) + assert.Equal(t, 6, count) + + calls := gs.GetCalls(callType) + assert.NotNil(t, calls) + assert.Len(t, calls, 6) + names := make([]string, 0) + for _, msgs := range calls { + for _, msg := range msgs { + names = append(names, msg.GetName()) + } + } + + assert.Equal(t, []string {"0", "1", "2", "0", "1", "2"}, names) + }) } func TestRunServerStreaming(t *testing.T) { diff --git a/runner/worker.go b/runner/worker.go index 642809c4..12d969fe 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -71,8 +71,7 @@ func (w *Worker) makeRequest() error { } } else { var err error - // todo we need an explicit way to choose between binary formats, it's impossible to distinguish from data itself - inputs, err = createPayloadsFromBinSingleMessage(w.config.data, w.mtd) + inputs, err = createPayloadsFromBin(w.config.data, w.mtd) if err != nil { return err } From 430f5a6697e66a9c88acf756d6c7ae67ce056ad2 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Tue, 23 Apr 2019 18:11:11 +0200 Subject: [PATCH 10/13] messages caching --- runner/worker.go | 51 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/runner/worker.go b/runner/worker.go index 12d969fe..04b73057 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -25,6 +25,7 @@ type Worker struct { reqCounter *int64 nReq int workerID string + cachedMessages *[]*dynamic.Message } func (w *Worker) runWorker() error { @@ -58,23 +59,9 @@ func (w *Worker) makeRequest() error { ctd := newCallTemplateData(w.mtd, w.workerID, reqNum) - var inputs *[]*dynamic.Message - - if !w.config.binary { - data, err := ctd.executeData(string(w.config.data)) - if err != nil { - return err - } - inputs, err = createPayloadsFromJson(string(data), w.mtd) - if err != nil { - return err - } - } else { - var err error - inputs, err = createPayloadsFromBin(w.config.data, w.mtd) - if err != nil { - return err - } + inputs, err := w.getMessages(ctd) + if err != nil { + return err } mdMap, err := ctd.executeMetadata(string(w.config.metadata)) @@ -127,6 +114,36 @@ func (w *Worker) makeRequest() error { return err } +func (w *Worker) getMessages(ctd *callTemplateData) (*[]*dynamic.Message, error) { + var inputs *[]*dynamic.Message + + if w.cachedMessages != nil { + return w.cachedMessages, nil + } + + if !w.config.binary { + data, err := ctd.executeData(string(w.config.data)) + if err != nil { + return nil, err + } + inputs, err = createPayloadsFromJson(string(data), w.mtd) + if err != nil { + return nil, err + } + // Json messages are not cached due to templating + } else { + var err error + inputs, err = createPayloadsFromBin(w.config.data, w.mtd) + if err != nil { + return nil, err + } + + w.cachedMessages = inputs + } + + return inputs, nil +} + func (w *Worker) makeClientStreamingRequest(ctx *context.Context, input *[]*dynamic.Message) error { str, err := w.stub.InvokeRpcClientStream(*ctx, w.mtd) counter := 0 From 9f8246b303761c0cdc2c15d87f0b3a7c226a1f8a Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Wed, 24 Apr 2019 15:52:30 +0200 Subject: [PATCH 11/13] Updated the docs --- www/docs/examples.md | 10 ++++++++++ www/docs/options.md | 26 ++++++++++++++++++++++---- www/docs/usage.md | 4 ++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/www/docs/examples.md b/www/docs/examples.md index f9d220be..27311e2b 100644 --- a/www/docs/examples.md +++ b/www/docs/examples.md @@ -50,6 +50,16 @@ ghz --proto ./greeter.proto \ 0.0.0.0:50051 < ./hello_request_data.bin ``` +Round-robin of messages for unary call: + +```sh +ghz --insecure \ + --proto ./greeter.proto \ + --call helloworld.Greeter.SayHello \ + -d '[{"name":"Joe"},{"name":"Bob"}]' \ + 0.0.0.0:50051 +``` + Custom number of requests and concurrency: ```sh diff --git a/www/docs/options.md b/www/docs/options.md index b06169db..2a38c964 100644 --- a/www/docs/options.md +++ b/www/docs/options.md @@ -90,9 +90,9 @@ By default we use a single gRPC connection for the whole test run, and the concu The call data as stringified JSON. If the value is `@` then the request contents are read from standard input (stdin). Example: `-d '{"name":"Bob"}'`. -For unary requests if we get an array of data we take the first element and use that as a single message for all requests in a test run. +For unary requests we accept a single message or an array of messages. In case of a single message we repeat the unary call with this message throughout the test. In case of array the messages will be sent in round-robin fashion. For example with `-d '[{"name":"Joe"},{"name":"Kate"},{"name":"Sara"}]'` the server will get Joe, Kate and Sara requests repeatedly. -For client streaming or bi-directional calls we can accept a JSON array of messages, and each element representing a single message within the stream call. For example: `-d '[{"name":"Joe"},{"name":"Kate"},{"name":"Sara"}]'` can be used as input for a client streaming or bidi call. In case of streaming calls if a single object is given for data then it is automatically converted to an array with single element. For example `-d '{"name":"Joe"}'` is equivalent to `-d '[{"name":"Joe"}]`. +For client streaming or bi-directional calls we accept a JSON array of messages, each element representing a single message within the stream call. For example: `-d '[{"name":"Joe"},{"name":"Kate"},{"name":"Sara"}]'` can be used as input for a client streaming or bidi call. In case of streaming calls if a single object is given for data then it is automatically converted to an array with single element. For example `-d '{"name":"Joe"}'` is equivalent to `-d '[{"name":"Joe"}]`. Round-robin for streaming requests is not supported. In case of client streaming we send all the messages in the input array and then we close and receive. @@ -102,11 +102,29 @@ The path for call data JSON file. For example, `-D /home/user/file.json` or `-D ### `-b`, `--binary` -The call data comes as serialized binary message read from standard input. See [writing a message](https://developers.google.com/protocol-buffers/docs/gotutorial#writing-a-message) on how to generate a bianry file for usage. +The call data comes as serialized protocol buffer messages read from standard input. + +We support two formats of binary data: single message and multiple count-delimited messages. See [writing a message](https://developers.google.com/protocol-buffers/docs/gotutorial#writing-a-message) on how to serialize a single message. + +For multiple messages prefix each message with its length in bytes. See [streaming multiple messages](https://developers.google.com/protocol-buffers/docs/techniques#streaming) in protobuf documentation. + +Code example: +```go +msg1 := &helloworld.HelloRequest{} +msg1.Name = "Alice" +msg2 := &helloworld.HelloRequest{} +msg2.Name = "Bob" + +buf := proto.Buffer{} +_ = buf.EncodeMessage(msg1) +_ = buf.EncodeMessage(msg2) + +binData := buf.Bytes() // pass this as input +``` ### `-B`, `--binary-file` -Path for the call data as serialized binary message. +Path for the call data as serialized binary message. The format is the same as for `-b` switch. ### `-m`, `--metadata` diff --git a/www/docs/usage.md b/www/docs/usage.md index 84029095..28985daa 100644 --- a/www/docs/usage.md +++ b/www/docs/usage.md @@ -30,8 +30,8 @@ Flags: --connections=1 Number of connections to use. Concurrency is distributed evenly among all the connections. Default is 1. -d, --data= The call data as stringified JSON. If the value is '@' then the request contents are read from stdin. -D, --data-file= File path for call data JSON file. Examples: /home/user/file.json or ./file.json. - -b, --binary The call data comes as serialized binary message read from stdin. - -B, --binary-file= File path for the call data as serialized binary message. + -b, --binary The call data comes as serialized binary message or multiple count-prefixed messages read from stdin. + -B, --binary-file= File path for the call data as serialized binary message or multiple count-prefixed messages. -m, --metadata= Request metadata as stringified JSON. -M, --metadata-file= File path for call metadata JSON file. Examples: /home/user/metadata.json or ./metadata.json. --stream-interval=0 Interval for stream requests between message sends. From c92532251981f218a953ae4c854f8e8f6d973d79 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Wed, 24 Apr 2019 16:11:30 +0200 Subject: [PATCH 12/13] made golint happy --- internal/helloworld/greeter_server.go | 1 + runner/data.go | 2 +- runner/data_test.go | 22 +++++++++++----------- runner/worker.go | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/internal/helloworld/greeter_server.go b/internal/helloworld/greeter_server.go index ed81d633..e06246e0 100644 --- a/internal/helloworld/greeter_server.go +++ b/internal/helloworld/greeter_server.go @@ -168,6 +168,7 @@ func (s *Greeter) GetCount(key CallType) int { return -1 } +// GetCalls gets the received messages for specific call type func (s *Greeter) GetCalls(key CallType) [][]*HelloRequest { s.mutex.Lock() val, ok := s.calls[key] diff --git a/runner/data.go b/runner/data.go index 4305611c..f30b88b0 100644 --- a/runner/data.go +++ b/runner/data.go @@ -29,7 +29,7 @@ func messageFromMap(input *dynamic.Message, data *map[string]interface{}) error return nil } -func createPayloadsFromJson(data string, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { +func createPayloadsFromJSON(data string, mtd *desc.MethodDescriptor) (*[]*dynamic.Message, error) { md := mtd.GetInputType() var inputs []*dynamic.Message diff --git a/runner/data_test.go b/runner/data_test.go index 913be363..2766c57c 100644 --- a/runner/data_test.go +++ b/runner/data_test.go @@ -45,7 +45,7 @@ func TestData_createPayloads(t *testing.T) { assert.NotNil(t, mtdTestUnaryTwo) t.Run("get empty when empty", func(t *testing.T) { - inputs, err := createPayloadsFromJson("", mtdUnary) + inputs, err := createPayloadsFromJSON("", mtdUnary) assert.NoError(t, err) assert.Empty(t, inputs) }) @@ -57,7 +57,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdUnary) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdUnary) assert.Error(t, err) assert.Nil(t, inputs) }) @@ -68,7 +68,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdUnary) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -81,7 +81,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdClientStreaming) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdClientStreaming) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -99,7 +99,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - inputs, err := createPayloadsFromJson(string(jsonData), mtdClientStreaming) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdClientStreaming) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 2) @@ -120,7 +120,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - inputs, err := createPayloadsFromJson(string(jsonData), mtdClientStreaming) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdClientStreaming) assert.Error(t, err) assert.Nil(t, inputs) }) @@ -139,7 +139,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(s) - inputs, err := createPayloadsFromJson(string(jsonData), mtdUnary) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 3) @@ -151,7 +151,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnary) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdTestUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -164,7 +164,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnary) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdTestUnary) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -180,7 +180,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnaryTwo) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdTestUnaryTwo) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) @@ -196,7 +196,7 @@ func TestData_createPayloads(t *testing.T) { jsonData, _ := json.Marshal(m1) - inputs, err := createPayloadsFromJson(string(jsonData), mtdTestUnaryTwo) + inputs, err := createPayloadsFromJSON(string(jsonData), mtdTestUnaryTwo) assert.NoError(t, err) assert.NotNil(t, inputs) assert.Len(t, *inputs, 1) diff --git a/runner/worker.go b/runner/worker.go index 04b73057..534aa61f 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -126,7 +126,7 @@ func (w *Worker) getMessages(ctd *callTemplateData) (*[]*dynamic.Message, error) if err != nil { return nil, err } - inputs, err = createPayloadsFromJson(string(data), w.mtd) + inputs, err = createPayloadsFromJSON(string(data), w.mtd) if err != nil { return nil, err } From de50c218d5165557aab3cc37965077b6c6aec8e8 Mon Sep 17 00:00:00 2001 From: "e.zhirov" Date: Thu, 25 Apr 2019 14:30:54 +0200 Subject: [PATCH 13/13] CR fixes --- README.md | 4 ++-- cmd/ghz/main.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8ff1ae4f..6fdde6b9 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ Flags: --connections=1 Number of connections to use. Concurrency is distributed evenly among all the connections. Default is 1. -d, --data= The call data as stringified JSON. If the value is '@' then the request contents are read from stdin. -D, --data-file= File path for call data JSON file. Examples: /home/user/file.json or ./file.json. - -b, --binary The call data comes as serialized binary message read from stdin. - -B, --binary-file= File path for the call data as serialized binary message. + -b, --binary The call data comes as serialized binary message or multiple count-prefixed messages read from stdin. + -B, --binary-file= File path for the call data as serialized binary message or multiple count-prefixed messages. -m, --metadata= Request metadata as stringified JSON. -M, --metadata-file= File path for call metadata JSON file. Examples: /home/user/metadata.json or ./metadata.json. --stream-interval=0 Interval for stream requests between message sends. diff --git a/cmd/ghz/main.go b/cmd/ghz/main.go index 3d5959c0..f85a8362 100644 --- a/cmd/ghz/main.go +++ b/cmd/ghz/main.go @@ -49,8 +49,8 @@ var ( data = kingpin.Flag("data", "The call data as stringified JSON. If the value is '@' then the request contents are read from stdin.").Short('d').PlaceHolder(" ").String() dataPath = kingpin.Flag("data-file", "File path for call data JSON file. Examples: /home/user/file.json or ./file.json.").Short('D').PlaceHolder("PATH").PlaceHolder(" ").String() - binData = kingpin.Flag("binary", "The call data comes as serialized binary message read from stdin.").Short('b').Default("false").Bool() - binPath = kingpin.Flag("binary-file", "File path for the call data as serialized binary message.").Short('B').PlaceHolder(" ").String() + binData = kingpin.Flag("binary", "The call data comes as serialized binary message or multiple count-prefixed messages read from stdin.").Short('b').Default("false").Bool() + binPath = kingpin.Flag("binary-file", "File path for the call data as serialized binary message or multiple count-prefixed messages.").Short('B').PlaceHolder(" ").String() md = kingpin.Flag("metadata", "Request metadata as stringified JSON.").Short('m').PlaceHolder(" ").String() mdPath = kingpin.Flag("metadata-file", "File path for call metadata JSON file. Examples: /home/user/metadata.json or ./metadata.json.").Short('M').PlaceHolder(" ").String() si = kingpin.Flag("stream-interval", "Interval for stream requests between message sends.").Default("0").Duration()