From 98ad332404877598e265ffaad75fa415a1382c09 Mon Sep 17 00:00:00 2001 From: Naveen Ramanathan Date: Thu, 8 Apr 2021 14:08:13 +0530 Subject: [PATCH] added output parameter to keep server stream open --- Dockerfile | 27 ++++++++++++--------- protoc-gen-gripmock/generator.go | 22 +++++++++++------- protoc-gen-gripmock/server.tmpl | 40 +++++++++++++++++++------------- stub/stub.go | 13 ++++++----- stub/stub_test.go | 35 ++++++++++++++++------------ 5 files changed, 81 insertions(+), 56 deletions(-) diff --git a/Dockerfile b/Dockerfile index b46bf010..e2ea28bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,23 @@ -FROM golang:alpine - +FROM golang:1.15.3 RUN mkdir /proto RUN mkdir /stubs -RUN apk -U --no-cache add git protobuf - -RUN go get -u -v github.com/golang/protobuf/protoc-gen-go \ - google.golang.org/grpc \ - google.golang.org/grpc/reflection \ - golang.org/x/net/context \ - github.com/go-chi/chi \ - github.com/lithammer/fuzzysearch/fuzzy \ - golang.org/x/tools/imports +# System setup +RUN apt-get update && apt-get install -y unzip git curl + +# Install protoc +ENV PATH $PATH:$(go env GOPATH)/bin +ENV PROTOBUF_URL https://github.com/protocolbuffers/protobuf/releases/download/v3.12.2/protoc-3.12.2-linux-x86_64.zip +RUN curl -L -o /tmp/protobuf.tar.gz $PROTOBUF_URL +WORKDIR /tmp/ +RUN unzip protobuf.tar.gz +RUN mv /tmp/bin/protoc /usr/bin + +RUN git clone --depth 1 --branch v1.3.5 https://github.com/golang/protobuf +RUN cd /tmp/protobuf/protoc-gen-go && go build -o protoc-gen-go +RUN cp /tmp/protobuf/protoc-gen-go/protoc-gen-go $(go env GOPATH)/bin +RUN rm -rf /tmp/protobuf/ RUN go get github.com/markbates/pkger/cmd/pkger diff --git a/protoc-gen-gripmock/generator.go b/protoc-gen-gripmock/generator.go index 6f523ec6..d21d0dea 100644 --- a/protoc-gen-gripmock/generator.go +++ b/protoc-gen-gripmock/generator.go @@ -61,8 +61,10 @@ func main() { } file := plugin.NewGeneratedFile("server.go", ".") - file.Write(buf.Bytes()) - + _, err = file.Write(buf.Bytes()) + if err != nil { + log.Fatalf("Unable to write to file %v", err) + } // Generate a response from our plugin and marshall as protobuf out, err := proto.Marshal(plugin.Response()) if err != nil { @@ -70,15 +72,19 @@ func main() { } // Write the response to stdout, to be picked up by protoc - os.Stdout.Write(out) + _, err = os.Stdout.Write(out) + if err != nil { + log.Printf("Error %v writing to stdout", err) + } } type generatorParam struct { - Services []Service - Dependencies map[string]string - GrpcAddr string - AdminPort string - PbPath string + Services []Service + Dependencies map[string]string + GrpcAddr string + AdminPort string + PbPath string + KeepServerStreamOpen bool } type Service struct { diff --git a/protoc-gen-gripmock/server.tmpl b/protoc-gen-gripmock/server.tmpl index 4cd75e68..7adf2838 100644 --- a/protoc-gen-gripmock/server.tmpl +++ b/protoc-gen-gripmock/server.tmpl @@ -72,20 +72,27 @@ type {{.Name}} struct{} {{ define "standard_method" }} func (s *{{.ServiceName}}) {{.Name}}(ctx context.Context, in *{{.Input}}) (*{{.Output}},error){ out := &{{.Output}}{} - err := findStub("{{.ServiceName}}", "{{.Name}}", in, out) + _, err := findStub("{{.ServiceName}}", "{{.Name}}", in, out) return out, err } {{ end }} {{ define "server_stream_method" }} func (s *{{.ServiceName}}) {{.Name}}(in *{{.Input}},stream {{.ServiceName}}_{{.Name}}Server) error { - out := &{{.Output}}{} - err := findStub("{{.ServiceName}}", "{{.Name}}", in, out) - if err!=nil { - return err + for { + out := &{{.Output}}{} + KeepServerStreamOpen, err := findStub("{{.ServiceName}}", "{{.Name}}", in, out) + if err!=nil { + return err + } + if err := stream.Send(out); err != nil { + return err + } + if !KeepServerStreamOpen { + return nil + } + time.Sleep(25 * time.Second) } - - return stream.Send(out) } {{ end }} @@ -142,11 +149,12 @@ type payload struct { } type response struct { - Data interface{} `json:"data"` - Error string `json:"error"` + Data interface{} `json:"data"` + Error string `json:"error"` + KeepServerStreamOpen bool `json:"keepServerStreamOpen"` } -func findStub(service, method string, in, out protoiface.MessageV1) error { +func findStub(service, method string, in, out protoiface.MessageV1) (bool, error) { url := fmt.Sprintf("http://localhost%s/find", HTTP_PORT) pyl := payload{ Service: service, @@ -155,30 +163,30 @@ func findStub(service, method string, in, out protoiface.MessageV1) error { } byt, err := json.Marshal(pyl) if err != nil { - return err + return false, err } reader := bytes.NewReader(byt) resp, err := http.DefaultClient.Post(url, "application/json", reader) if err != nil { - return fmt.Errorf("Error request to stub server %v",err) + return false, fmt.Errorf("Error request to stub server %v",err) } if resp.StatusCode != http.StatusOK { body, _ := ioutil.ReadAll(resp.Body) - return fmt.Errorf(string(body)) + return false, fmt.Errorf(string(body)) } respRPC := new(response) err = json.NewDecoder(resp.Body).Decode(respRPC) if err != nil { - return fmt.Errorf("decoding json response %v",err) + return false, fmt.Errorf("decoding json response %v",err) } if respRPC.Error != "" { - return fmt.Errorf(respRPC.Error) + return false, fmt.Errorf(respRPC.Error) } data, _ := json.Marshal(respRPC.Data) - return jsonpb.Unmarshal(bytes.NewReader(data), out) + return respRPC.KeepServerStreamOpen, jsonpb.Unmarshal(bytes.NewReader(data), out) } {{ end }} \ No newline at end of file diff --git a/stub/stub.go b/stub/stub.go index 819b317f..5018f701 100644 --- a/stub/stub.go +++ b/stub/stub.go @@ -7,7 +7,7 @@ import ( "log" "net/http" "strings" - + "github.com/go-chi/chi" ) @@ -60,8 +60,9 @@ type Input struct { } type Output struct { - Data map[string]interface{} `json:"data"` - Error string `json:"error"` + Data map[string]interface{} `json:"data"` + Error string `json:"error"` + KeepServerStreamOpen bool `json:"keepServerStreamOpen"` } func addStub(w http.ResponseWriter, r *http.Request) { @@ -106,7 +107,7 @@ func validateStub(stub *Stub) error { if stub.Method == "" { return fmt.Errorf("Method name can't be emtpy") } - + // due to golang implementation // method name must capital stub.Method = strings.Title(stub.Method) @@ -143,11 +144,11 @@ func handleFindStub(w http.ResponseWriter, r *http.Request) { responseError(err, w) return } - + // due to golang implementation // method name must capital stub.Method = strings.Title(stub.Method) - + output, err := findStub(stub) if err != nil { log.Println(err) diff --git a/stub/stub_test.go b/stub/stub_test.go index 9871f6ef..1dd87222 100644 --- a/stub/stub_test.go +++ b/stub/stub_test.go @@ -48,7 +48,7 @@ func TestStub(t *testing.T) { return httptest.NewRequest("GET", "/", nil) }, handler: listStub, - expect: "{\"Testing\":{\"TestMethod\":[{\"Input\":{\"equals\":{\"Hola\":\"Mundo\"},\"contains\":null,\"matches\":null},\"Output\":{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}}]}}\n", + expect: "{\"Testing\":{\"TestMethod\":[{\"Input\":{\"equals\":{\"Hola\":\"Mundo\"},\"contains\":null,\"matches\":null},\"Output\":{\"data\":{\"Hello\":\"World\"},\"error\":\"\",\"keepServerStreamOpen\":false}}]}}\n", }, { name: "find stub equals", @@ -57,7 +57,7 @@ func TestStub(t *testing.T) { return httptest.NewRequest("POST", "/find", bytes.NewReader([]byte(payload))) }, handler: handleFindStub, - expect: "{\"data\":{\"Hello\":\"World\"},\"error\":\"\"}\n", + expect: "{\"data\":{\"Hello\":\"World\"},\"error\":\"\",\"keepServerStreamOpen\":false}\n", }, { name: "add stub contains", @@ -74,7 +74,8 @@ func TestStub(t *testing.T) { "output":{ "data":{ "hello":"world" - } + }, + "keepServerStreamOpen": true } }` return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload))) @@ -97,8 +98,9 @@ func TestStub(t *testing.T) { return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) }, handler: handleFindStub, - expect: "{\"data\":{\"hello\":\"world\"},\"error\":\"\"}\n", - }, { + expect: "{\"data\":{\"hello\":\"world\"},\"error\":\"\",\"keepServerStreamOpen\":true}\n", + }, + { name: "add stub matches regex", mock: func() *http.Request { payload := `{ @@ -119,21 +121,23 @@ func TestStub(t *testing.T) { }, handler: addStub, expect: "Success add stub", - }, { + }, + { name: "find stub matches regex", mock: func() *http.Request { payload := `{ - "service":"Testing2", - "method":"TestMethod", - "data":{ - "field1":"hello" - } - }` + "service":"Testing2", + "method":"TestMethod", + "data":{ + "field1":"hello" + } + }` return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload))) }, handler: handleFindStub, - expect: "{\"data\":{\"reply\":\"OK\"},\"error\":\"\"}\n", - }, { + expect: "{\"data\":{\"reply\":\"OK\"},\"error\":\"\",\"keepServerStreamOpen\":false}\n", + }, + { name: "error find stub contains", mock: func() *http.Request { payload := `{ @@ -149,7 +153,8 @@ func TestStub(t *testing.T) { }, handler: handleFindStub, expect: "Can't find stub \n\nService: Testing \n\nMethod: TestMethod \n\nInput\n\n{\n\tfield1: hello field1\n\tfield2: hello field2\n\tfield3: hello field4\n}\n\nClosest Match \n\ncontains:{\n\tfield1: hello field1\n\tfield3: hello field3\n}", - }, { + }, + { name: "error find stub equals", mock: func() *http.Request { payload := `{"service":"Testing","method":"TestMethod","data":{"Hola":"Dunia"}}`