From 9d7b48c5af785feda12e8a5180bd78c7f9e3a43a Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Sat, 20 Jul 2024 15:26:19 +0300 Subject: [PATCH 1/2] fix lower method name --- .github/workflows/integration-test.yml | 4 + .../docker-compose/docker-compose.infra.yml | 11 - deployments/docker-compose/docker-compose.yml | 6 + example/strictmode/client/main.go | 52 +++ example/strictmode/entrypoint.sh | 12 + example/strictmode/method.proto | 24 ++ example/strictmode/stub/lower.yaml | 9 + example/strictmode/stub/title.yaml | 9 + protoc-gen-gripmock/generator.go | 51 ++- protoc-gen-gripmock/server.tmpl | 16 +- protogen/example/strictmode/demo/server.go | 235 ++++++++++++ protogen/example/strictmode/method.pb.go | 349 ++++++++++++++++++ protogen/example/strictmode/method.proto | 25 ++ protogen/example/strictmode/method_grpc.pb.go | 148 ++++++++ 14 files changed, 919 insertions(+), 32 deletions(-) delete mode 100644 deployments/docker-compose/docker-compose.infra.yml create mode 100644 example/strictmode/client/main.go create mode 100755 example/strictmode/entrypoint.sh create mode 100644 example/strictmode/method.proto create mode 100644 example/strictmode/stub/lower.yaml create mode 100644 example/strictmode/stub/title.yaml create mode 100644 protogen/example/strictmode/demo/server.go create mode 100644 protogen/example/strictmode/method.pb.go create mode 100644 protogen/example/strictmode/method.proto create mode 100644 protogen/example/strictmode/method_grpc.pb.go diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 5f832e91..0a2fa766 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -56,3 +56,7 @@ jobs: HTTP_PORT: 6000 with: entrypoint: example/ms/entrypoint.sh + - name: Run strict mode example + uses: ./ + with: + entrypoint: example/strictmode/entrypoint.sh diff --git a/deployments/docker-compose/docker-compose.infra.yml b/deployments/docker-compose/docker-compose.infra.yml deleted file mode 100644 index 09c6ecb6..00000000 --- a/deployments/docker-compose/docker-compose.infra.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: '3.8' - -services: - jaeger: - image: jaegertracing/all-in-one:1.52 - ports: - - "16686:16686" - - "4317:4317" # grpc - environment: - - COLLECTOR_OTLP_ENABLED=true - - LOG_LEVEL=debug diff --git a/deployments/docker-compose/docker-compose.yml b/deployments/docker-compose/docker-compose.yml index e617f033..d4f14d68 100644 --- a/deployments/docker-compose/docker-compose.yml +++ b/deployments/docker-compose/docker-compose.yml @@ -40,3 +40,9 @@ services: entrypoint: example/well_known_types/entrypoint.sh volumes: - ./../../protogen/example/well_known_types:/go/src/github.com/bavix/gripmock/protogen/example/well_known_types + strict-mode: + image: bavix/gripmock:latest + entrypoint: example/strictmode/entrypoint.sh + volumes: + - ./../../protogen/example/strictmode:/go/src/github.com/bavix/gripmock/protogen/example/strictmode + \ No newline at end of file diff --git a/example/strictmode/client/main.go b/example/strictmode/client/main.go new file mode 100644 index 00000000..97bfcf32 --- /dev/null +++ b/example/strictmode/client/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "log" + "os" + "time" + + grpcinterceptors "github.com/gripmock/grpc-interceptors" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + strictmode "github.com/bavix/gripmock/protogen/example/strictmode" +) + +//nolint:mnd +func main() { + // Set up a connection to the server. + conn, err := grpc.NewClient("localhost:4770", + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithChainUnaryInterceptor(grpcinterceptors.UnaryTimeoutInterceptor(5*time.Second)), + grpc.WithChainStreamInterceptor(grpcinterceptors.StreamTimeoutInterceptor(5*time.Second))) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + + c := strictmode.NewGripMockClient(conn) + + // Contact the server and print out its response. + name := "GripMock Request" + if len(os.Args) > 1 { + name = os.Args[1] + } + r1, err := c.SayLowerHello(context.Background(), &strictmode.SayLowerHelloRequest{Name: name}, grpc.WaitForReady(true)) + if err != nil { + log.Fatalf("error from grpc: %v", err) + } + + if r1.GetMessage() != "ok" { + log.Fatalf("message is not ok: %s", r1.GetMessage()) + } + + r2, err := c.SayTitleHello(context.Background(), &strictmode.SayTitleHelloRequest{Name: name}, grpc.WaitForReady(true)) + if err != nil { + log.Fatalf("error from grpc: %v", err) + } + + if r2.GetMessage() != "OK" { + log.Fatalf("message is not ok: %s", r2.GetMessage()) + } +} diff --git a/example/strictmode/entrypoint.sh b/example/strictmode/entrypoint.sh new file mode 100755 index 00000000..23129669 --- /dev/null +++ b/example/strictmode/entrypoint.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +# this file is used by .github/workflows/integration-test.yml + +STRICT_METHOD_TITLE=false gripmock \ + --stub=example/strictmode/stub \ + example/strictmode/method.proto & + +# wait for generated files to be available and gripmock is up +gripmock check --silent --timeout=30s + +go run example/strictmode/client/*.go \ No newline at end of file diff --git a/example/strictmode/method.proto b/example/strictmode/method.proto new file mode 100644 index 00000000..093bb5c6 --- /dev/null +++ b/example/strictmode/method.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package strictmode; + +service GripMock { + rpc SayTitleHello (SayTitleHelloRequest) returns (SayTitleHelloReply); + rpc sayLowerHello (sayLowerHelloRequest) returns (sayLowerHelloReply); +} + +message sayLowerHelloRequest { + string name = 1; +} + +message sayLowerHelloReply { + string message = 1; +} + +message SayTitleHelloRequest { + string name = 1; +} + +message SayTitleHelloReply { + string message = 1; +} diff --git a/example/strictmode/stub/lower.yaml b/example/strictmode/stub/lower.yaml new file mode 100644 index 00000000..e745e82a --- /dev/null +++ b/example/strictmode/stub/lower.yaml @@ -0,0 +1,9 @@ +service: GripMock +method: sayLowerHello +input: + ignoreArrayOrder: true + equals: + name: "GripMock Request" +output: + data: + message: "ok" diff --git a/example/strictmode/stub/title.yaml b/example/strictmode/stub/title.yaml new file mode 100644 index 00000000..1bd2c81d --- /dev/null +++ b/example/strictmode/stub/title.yaml @@ -0,0 +1,9 @@ +service: GripMock +method: SayTitleHello +input: + ignoreArrayOrder: true + equals: + name: "GripMock Request" +output: + data: + message: "OK" diff --git a/protoc-gen-gripmock/generator.go b/protoc-gen-gripmock/generator.go index 66df4719..050d2459 100644 --- a/protoc-gen-gripmock/generator.go +++ b/protoc-gen-gripmock/generator.go @@ -105,19 +105,28 @@ type Service struct { Methods []methodTemplate `json:"methods"` } +// methodTemplate represents a method in a gRPC service. // methodTemplate represents a method in a gRPC service. type methodTemplate struct { // SvcPackage is the package name of the service. + // For example, if the service name is "Greeter", SvcPackage would be "github.com/bavix/gripmock/protogen/example/Greeter". SvcPackage string `json:"svc_package"` - // Name is the name of the method. - Name string `json:"name"` + // RpcName is the name of the RPC method, without the "Greeter/" prefix. + // For example, if the RPC method is "Greeter.SayHello", RpcName would be "SayHello". + RpcName string `json:"rpc_name"` + // TitleName is the name of the method, without the "Say" prefix. + // For example, if the method is "SayHello", TitleName would be "Hello". + TitleName string `json:"title_name"` // ServiceName is the name of the service. + // For example, if the service name is "Greeter", ServiceName would be "Greeter". ServiceName string `json:"service_name"` // MethodType is the type of the method, which can be "standard", "server-stream", "client-stream", or "bidirectional". MethodType string `json:"method_type"` // Input is the name of the input message for the method. + // For example, if the input message is "HelloRequest", Input would be "HelloRequest". Input string `json:"input"` // Output is the name of the output message for the method. + // For example, if the output message is "HelloResponse", Output would be "HelloResponse". Output string `json:"output"` } @@ -237,7 +246,7 @@ func resolveDependencies(protos []*descriptorpb.FileDescriptorProto) map[string] var ( // aliases is a map that keeps track of package aliases. The key is the alias and the value // is a boolean indicating whether the alias is used or not. - aliases = map[string]bool{} + aliases = make(map[string]struct{}, 128) // aliasNum is an integer that keeps track of the number of used aliases. It is used to // generate new unique aliases. @@ -246,7 +255,7 @@ var ( // packages is a map that stores the package names as keys and their corresponding aliases // as values. The package names are the full go package names and the aliases are the // generated or specified aliases for the packages. - packages = map[string]string{} + packages = make(map[string]string, 32) ) // getGoPackage returns the go package alias and the go package name @@ -262,6 +271,7 @@ var ( // // The go_package option format is: package_name;alias. func getGoPackage(proto *descriptorpb.FileDescriptorProto) (alias string, goPackage string) { + // Get the go_package option from the file descriptor. goPackage = proto.GetOptions().GetGoPackage() if goPackage == "" { return @@ -292,13 +302,16 @@ func getGoPackage(proto *descriptorpb.FileDescriptorProto) (alias string, goPack } // If the alias already exists, append a number to it. - if ok := aliases[alias]; ok { + if _, ok := aliases[alias]; ok { alias = fmt.Sprintf("%s%d", alias, aliasNum) aliasNum++ } + // Add the alias to the aliases map. + aliases[alias] = struct{}{} + + // Add the package to the packages map with its alias. packages[goPackage] = alias - aliases[alias] = true return } @@ -307,10 +320,11 @@ func getGoPackage(proto *descriptorpb.FileDescriptorProto) (alias string, goPack // a slice of Service structs, each representing a gRPC service. // // The function iterates over each file descriptor and extracts the services -// defined in each file. It then populates the Services struct with relevant -// information like the service name, package name, and methods. The methods -// include information such as the method name, input and output types, and the -// type of method (standard, server-stream, client-stream, or bidirectional). +// defined in each file. It populates the Service struct with relevant +// information like the service name, package name, and methods. Each method +// represents a gRPC method and includes information such as the method name, +// input and output types, and the type of method (standard, server-stream, +// client-stream, or bidirectional). // // Parameters: // - protos: A slice of FileDescriptorProto structs representing the file @@ -319,6 +333,7 @@ func getGoPackage(proto *descriptorpb.FileDescriptorProto) (alias string, goPack // Returns: // - svcTmp: A slice of Service structs representing the extracted services. func extractServices(protos []*descriptorpb.FileDescriptorProto) []Service { + // svcTmp will hold the extracted services var svcTmp []Service title := cases.Title(language.English, cases.NoLower) @@ -350,7 +365,8 @@ func extractServices(protos []*descriptorpb.FileDescriptorProto) []Service { // Populate the methodTemplate struct methods[j] = methodTemplate{ - Name: title.String(*method.Name), + RpcName: method.GetName(), + TitleName: title.String(method.GetName()), SvcPackage: s.Package, ServiceName: svc.GetName(), Input: getMessageType(protos, method.GetInputType()), @@ -367,7 +383,16 @@ func extractServices(protos []*descriptorpb.FileDescriptorProto) []Service { return svcTmp } +// getMessageType takes a slice of file descriptors and a type string, +// and returns a fully qualified message type. +// +// The message type is split into package and type parts, and the +// function iterates over the protos to find the target message. +// If the target message is found, the function returns the fully +// qualified message type, otherwise it returns the target type. func getMessageType(protos []*descriptorpb.FileDescriptorProto, tipe string) string { + title := cases.Title(language.English, cases.NoLower) + // Split the message type into package and type parts split := strings.Split(tipe, ".")[1:] targetPackage := strings.Join(split[:len(split)-1], ".") @@ -391,13 +416,13 @@ func getMessageType(protos []*descriptorpb.FileDescriptorProto, tipe string) str } // Return the fully qualified message type - return fmt.Sprintf("%s%s", alias, msg.GetName()) + return fmt.Sprintf("%s%s", alias, title.String(msg.GetName())) } } } // Return the target type if no match was found - return targetType + return targetPackage + "." + title.String(targetType) } // keywords is a map that contains all the reserved keywords in Go. diff --git a/protoc-gen-gripmock/server.tmpl b/protoc-gen-gripmock/server.tmpl index babb3767..054969e7 100644 --- a/protoc-gen-gripmock/server.tmpl +++ b/protoc-gen-gripmock/server.tmpl @@ -149,7 +149,7 @@ type {{.Name}} struct{ {{end}} {{ define "standard_method" }} -func (s *{{.ServiceName}}) {{.Name}}(ctx context.Context, in *{{.Input}}) (*{{.Output}},error){ +func (s *{{.ServiceName}}) {{.TitleName}}(ctx context.Context, in *{{.Input}}) (*{{.Output}},error){ out := &{{.Output}}{} // Retrieve metadata from the incoming context. // The metadata is used to find the stub for the method being called. @@ -159,7 +159,7 @@ func (s *{{.ServiceName}}) {{.Name}}(ctx context.Context, in *{{.Input}}) (*{{.O // The stub defines the input and output messages for the method. // If the stub is found, its output message is returned. // If the stub is not found, an error is returned. - err := findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}", "{{.Name}}", md, in, out) + err := findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}", "{{.RpcName}}", md, in, out) // Return the output message and any error encountered while finding the stub. return out, err @@ -167,7 +167,7 @@ func (s *{{.ServiceName}}) {{.Name}}(ctx context.Context, in *{{.Input}}) (*{{.O {{ end }} {{ define "server_stream_method" }} -func (s *{{.ServiceName}}) {{.Name}}(in *{{.Input}},srv {{.SvcPackage}}{{.ServiceName}}_{{.Name}}Server) error { +func (s *{{.ServiceName}}) {{.TitleName}}(in *{{.Input}},srv {{.SvcPackage}}{{.ServiceName}}_{{.TitleName}}Server) error { out := &{{.Output}}{} // Retrieve metadata from the incoming context. // The metadata is used to find the stub for the method being called. @@ -178,7 +178,7 @@ func (s *{{.ServiceName}}) {{.Name}}(in *{{.Input}},srv {{.SvcPackage}}{{.Servic // The stub defines the input and output messages for the method. // If the stub is found, its output message is returned. // If the stub is not found, an error is returned. - err := findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}", "{{.Name}}", md, in, out) + err := findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}", "{{.RpcName}}", md, in, out) if err != nil { // Return the error encountered while finding the stub. return err @@ -192,7 +192,7 @@ func (s *{{.ServiceName}}) {{.Name}}(in *{{.Input}},srv {{.SvcPackage}}{{.Servic {{ end }} {{ define "client_stream_method"}} -func (s *{{.ServiceName}}) {{.Name}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.Name}}Server) error { +func (s *{{.ServiceName}}) {{.TitleName}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.TitleName}}Server) error { out := &{{.Output}}{} // Handle the client-streaming RPC. // This loop will continue until the client closes the RPC. @@ -214,7 +214,7 @@ func (s *{{.ServiceName}}) {{.Name}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.Name // The stub defines the input and output messages for the method. // If the stub is found, its output message is returned. // If the stub is not found, an error is returned. - err = findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}","{{.Name}}", md, input, out) + err = findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}","{{.RpcName}}", md, input, out) if err != nil { // If there is an error finding the stub, return the error. return err @@ -224,7 +224,7 @@ func (s *{{.ServiceName}}) {{.Name}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.Name {{ end }} {{ define "bidirectional_method"}} -func (s *{{.ServiceName}}) {{.Name}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.Name}}Server) error { +func (s *{{.ServiceName}}) {{.TitleName}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.TitleName}}Server) error { // Handle the bidirectional RPC. // This loop will continue until the client closes the RPC. // For each input message received from the client, it will find the stub @@ -252,7 +252,7 @@ func (s *{{.ServiceName}}) {{.Name}}(srv {{.SvcPackage}}{{.ServiceName}}_{{.Name // The stub defines the input and output messages for the method. // If the stub is found, its output message is returned. // If the stub is not found, an error is returned. - err = findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}","{{.Name}}", md, input, out) + err = findStub(ctx, s.__builder__.Config().HTTPAddr, "{{.ServiceName}}","{{.RpcName}}", md, input, out) if err != nil { return err } diff --git a/protogen/example/strictmode/demo/server.go b/protogen/example/strictmode/demo/server.go new file mode 100644 index 00000000..10f6a44f --- /dev/null +++ b/protogen/example/strictmode/demo/server.go @@ -0,0 +1,235 @@ +// Code generated by GripMock. DO NOT EDIT. +// +// This file is generated by GripMock, a tool for generating gRPC mock servers. +// GripMock is a mock server for gRPC services. It's using a .proto file to generate implementation of gRPC service for you. +// You can use GripMock for setting up end-to-end testing or as a dummy server in a software development phase. +// The server implementation is in GoLang but the client can be any programming language that support gRPC. +// +// See https://github.com/bavix/gripmock for more information. +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "net" + "net/http" + "os/signal" + "slices" + "strings" + "syscall" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + _ "google.golang.org/grpc/encoding/gzip" + "google.golang.org/grpc/health" + healthgrpc "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/reflection" + "google.golang.org/grpc/status" + jsonpb "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/reflect/protoreflect" + + sdk "github.com/bavix/gripmock-sdk-go" + "github.com/bavix/gripmock/pkg/deps" + "github.com/bavix/gripmock/pkg/grpccontext" + + strictmode "github.com/bavix/gripmock/protogen/example/strictmode" +) + +type GripMock struct { + strictmode.UnsafeGripMockServer + __builder__ *deps.Builder +} + +func (s *GripMock) SayTitleHello(ctx context.Context, in *strictmode.SayTitleHelloRequest) (*strictmode.SayTitleHelloReply, error) { + out := &strictmode.SayTitleHelloReply{} + // Retrieve metadata from the incoming context. + // The metadata is used to find the stub for the method being called. + md, _ := metadata.FromIncomingContext(ctx) + + // Find the stub for the given service name, method name, and metadata. + // The stub defines the input and output messages for the method. + // If the stub is found, its output message is returned. + // If the stub is not found, an error is returned. + err := findStub(ctx, s.__builder__.Config().HTTPAddr, "GripMock", "SayTitleHello", md, in, out) + + // Return the output message and any error encountered while finding the stub. + return out, err +} + +func (s *GripMock) SayLowerHello(ctx context.Context, in *strictmode.SayLowerHelloRequest) (*strictmode.SayLowerHelloReply, error) { + out := &strictmode.SayLowerHelloReply{} + // Retrieve metadata from the incoming context. + // The metadata is used to find the stub for the method being called. + md, _ := metadata.FromIncomingContext(ctx) + + // Find the stub for the given service name, method name, and metadata. + // The stub defines the input and output messages for the method. + // If the stub is found, its output message is returned. + // If the stub is not found, an error is returned. + err := findStub(ctx, s.__builder__.Config().HTTPAddr, "GripMock", "sayLowerHello", md, in, out) + + // Return the output message and any error encountered while finding the stub. + return out, err +} + +func main() { + ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) + defer cancel() + + builder, err := deps.New(ctx) + if err != nil { + log.Fatal(err) + } + + lis, err := net.Listen(builder.Config().GRPCNetwork, builder.Config().GRPCAddr) + if err != nil { + builder.Logger().Fatal().Err(err).Msg("failed to listen") + } + + s := grpc.NewServer( + grpc.UnaryInterceptor(grpccontext.UnaryInterceptor(builder.Logger())), + grpc.StreamInterceptor(grpccontext.StreamInterceptor(builder.Logger())), + ) + + healthcheck := health.NewServer() + healthcheck.SetServingStatus("gripmock", healthgrpc.HealthCheckResponse_NOT_SERVING) + + strictmode.RegisterGripMockServer(s, &GripMock{__builder__: builder}) + + healthgrpc.RegisterHealthServer(s, healthcheck) + reflection.Register(s) + + builder.Logger().Info(). + Str("addr", builder.Config().GRPCAddr). + Str("network", builder.Config().GRPCNetwork). + Msg("Serving gRPC") + + // Health check goroutine to wait for the HTTP server to become ready. + // Once the HTTP server is ready, it sets the gRPC server to SERVING state. + go func() { + // Create a new client to interact with the HTTP server API. + api, err := sdk.NewClientWithResponses( + fmt.Sprintf("http://%s/api", builder.Config().HTTPAddr), + sdk.WithHTTPClient(http.DefaultClient), + ) + if err != nil { + return + } + + // Create a context with a timeout of 120 seconds. + ctx, cancel := context.WithTimeout(ctx, 120*time.Second) + defer cancel() + + // Create a ticker to periodically check the readiness of the HTTP server. + tick := time.NewTicker(250 * time.Millisecond) + defer tick.Stop() + + for { + select { + // Check if the context is done. + case <-ctx.Done(): + return + + // Check if the ticker has fired. + case <-tick.C: + // Call the Readiness API on the HTTP server. + resp, err := api.ReadinessWithResponse(ctx) + + // If the API call is successful and the response is not nil, + // set the gRPC server to SERVING state and log a message. + if err == nil && resp.JSON200 != nil { + healthcheck.SetServingStatus("gripmock", healthgrpc.HealthCheckResponse_SERVING) + + builder.Logger().Info().Msg("gRPC server is ready to accept requests") + + return + } + } + } + }() + + if err := s.Serve(lis); err != nil { + builder.Logger().Fatal().Err(err).Msg("failed to serve") + } +} + +func findStub(ctx context.Context, addr string, service, method string, md metadata.MD, in, out protoreflect.ProtoMessage) error { + // Create a new client with the configured HTTP address. + // Add the default HTTP client as the transport. + api, err := sdk.NewClientWithResponses(fmt.Sprintf("http://%s/api", addr), + sdk.WithHTTPClient(http.DefaultClient), + ) + if err != nil { + return err + } + + // Exclude headers that are not relevant for matching stubs. + excludes := []string{":authority", "content-type", "grpc-accept-encoding", "user-agent"} + + // Create a map of headers to match with the input metadata. + headers := make(map[string]string, len(md)) + for h, v := range md { + // Exclude headers that are not relevant for matching stubs. + if slices.Contains(excludes, h) { + continue + } + + // Join the values of the header with a semicolon. + headers[h] = strings.Join(v, ";") + } + + // Search for a stub that matches the given service, method, and headers. + searchStub, err := api.SearchStubsWithResponse(ctx, sdk.SearchStubsJSONRequestBody{ + Service: service, // The name of the service. + Method: method, // The name of the method. + Headers: headers, // The headers to match. + Data: in, // The input message. + }) + if err != nil { + return err + } + + // If the search was unsuccessful, return an error with the response body. + if searchStub.JSON200 == nil { + return fmt.Errorf(string(searchStub.Body)) + } + + // If the search returned an error, return an error with the error code and message. + if searchStub.JSON200.Error != "" || searchStub.JSON200.Code != nil { + if searchStub.JSON200.Code == nil { + return status.Error(codes.Aborted, searchStub.JSON200.Error) + } + + if *searchStub.JSON200.Code != codes.OK { + return status.Error(*searchStub.JSON200.Code, searchStub.JSON200.Error) + } + } + + // Convert the search result to JSON. + data, err := json.Marshal(searchStub.JSON200.Data) + if err != nil { + return err + } + + // Create a map of headers to set in the context. + mdResp := make(metadata.MD, len(searchStub.JSON200.Headers)) + for k, v := range searchStub.JSON200.Headers { + // Split the values of the header by semicolon and trim each value. + splits := strings.Split(v, ";") + for i, s := range splits { + splits[i] = strings.TrimSpace(s) + } + + mdResp[k] = splits + } + + // Set the headers in the context. + grpc.SetHeader(ctx, mdResp) + + // Unmarshal the search result into the output message. + return jsonpb.Unmarshal(data, out) +} diff --git a/protogen/example/strictmode/method.pb.go b/protogen/example/strictmode/method.pb.go new file mode 100644 index 00000000..be1f8a64 --- /dev/null +++ b/protogen/example/strictmode/method.pb.go @@ -0,0 +1,349 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc v5.27.2 +// source: method.proto + +package strictmode + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SayLowerHelloRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *SayLowerHelloRequest) Reset() { + *x = SayLowerHelloRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_method_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SayLowerHelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayLowerHelloRequest) ProtoMessage() {} + +func (x *SayLowerHelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_method_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayLowerHelloRequest.ProtoReflect.Descriptor instead. +func (*SayLowerHelloRequest) Descriptor() ([]byte, []int) { + return file_method_proto_rawDescGZIP(), []int{0} +} + +func (x *SayLowerHelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type SayLowerHelloReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *SayLowerHelloReply) Reset() { + *x = SayLowerHelloReply{} + if protoimpl.UnsafeEnabled { + mi := &file_method_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SayLowerHelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayLowerHelloReply) ProtoMessage() {} + +func (x *SayLowerHelloReply) ProtoReflect() protoreflect.Message { + mi := &file_method_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayLowerHelloReply.ProtoReflect.Descriptor instead. +func (*SayLowerHelloReply) Descriptor() ([]byte, []int) { + return file_method_proto_rawDescGZIP(), []int{1} +} + +func (x *SayLowerHelloReply) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type SayTitleHelloRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *SayTitleHelloRequest) Reset() { + *x = SayTitleHelloRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_method_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SayTitleHelloRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayTitleHelloRequest) ProtoMessage() {} + +func (x *SayTitleHelloRequest) ProtoReflect() protoreflect.Message { + mi := &file_method_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayTitleHelloRequest.ProtoReflect.Descriptor instead. +func (*SayTitleHelloRequest) Descriptor() ([]byte, []int) { + return file_method_proto_rawDescGZIP(), []int{2} +} + +func (x *SayTitleHelloRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type SayTitleHelloReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *SayTitleHelloReply) Reset() { + *x = SayTitleHelloReply{} + if protoimpl.UnsafeEnabled { + mi := &file_method_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SayTitleHelloReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SayTitleHelloReply) ProtoMessage() {} + +func (x *SayTitleHelloReply) ProtoReflect() protoreflect.Message { + mi := &file_method_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SayTitleHelloReply.ProtoReflect.Descriptor instead. +func (*SayTitleHelloReply) Descriptor() ([]byte, []int) { + return file_method_proto_rawDescGZIP(), []int{3} +} + +func (x *SayTitleHelloReply) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_method_proto protoreflect.FileDescriptor + +var file_method_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, + 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x2a, 0x0a, 0x14, 0x73, 0x61, + 0x79, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2e, 0x0a, 0x12, 0x73, 0x61, 0x79, 0x4c, 0x6f, 0x77, + 0x65, 0x72, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2a, 0x0a, 0x14, 0x53, 0x61, 0x79, 0x54, 0x69, 0x74, + 0x6c, 0x65, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0x2e, 0x0a, 0x12, 0x53, 0x61, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x48, 0x65, + 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x32, 0xb0, 0x01, 0x0a, 0x08, 0x47, 0x72, 0x69, 0x70, 0x4d, 0x6f, 0x63, 0x6b, 0x12, + 0x51, 0x0a, 0x0d, 0x53, 0x61, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x12, 0x20, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x53, 0x61, + 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6d, 0x6f, 0x64, 0x65, 0x2e, + 0x53, 0x61, 0x79, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x51, 0x0a, 0x0d, 0x73, 0x61, 0x79, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x48, 0x65, + 0x6c, 0x6c, 0x6f, 0x12, 0x20, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6d, 0x6f, 0x64, 0x65, + 0x2e, 0x73, 0x61, 0x79, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6d, 0x6f, + 0x64, 0x65, 0x2e, 0x73, 0x61, 0x79, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x76, 0x69, 0x78, 0x2f, 0x67, 0x72, 0x69, 0x70, 0x6d, 0x6f, + 0x63, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6d, 0x6f, 0x64, 0x65, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_method_proto_rawDescOnce sync.Once + file_method_proto_rawDescData = file_method_proto_rawDesc +) + +func file_method_proto_rawDescGZIP() []byte { + file_method_proto_rawDescOnce.Do(func() { + file_method_proto_rawDescData = protoimpl.X.CompressGZIP(file_method_proto_rawDescData) + }) + return file_method_proto_rawDescData +} + +var file_method_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_method_proto_goTypes = []any{ + (*SayLowerHelloRequest)(nil), // 0: strictmode.sayLowerHelloRequest + (*SayLowerHelloReply)(nil), // 1: strictmode.sayLowerHelloReply + (*SayTitleHelloRequest)(nil), // 2: strictmode.SayTitleHelloRequest + (*SayTitleHelloReply)(nil), // 3: strictmode.SayTitleHelloReply +} +var file_method_proto_depIdxs = []int32{ + 2, // 0: strictmode.GripMock.SayTitleHello:input_type -> strictmode.SayTitleHelloRequest + 0, // 1: strictmode.GripMock.sayLowerHello:input_type -> strictmode.sayLowerHelloRequest + 3, // 2: strictmode.GripMock.SayTitleHello:output_type -> strictmode.SayTitleHelloReply + 1, // 3: strictmode.GripMock.sayLowerHello:output_type -> strictmode.sayLowerHelloReply + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_method_proto_init() } +func file_method_proto_init() { + if File_method_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_method_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*SayLowerHelloRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_method_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*SayLowerHelloReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_method_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*SayTitleHelloRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_method_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*SayTitleHelloReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_method_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_method_proto_goTypes, + DependencyIndexes: file_method_proto_depIdxs, + MessageInfos: file_method_proto_msgTypes, + }.Build() + File_method_proto = out.File + file_method_proto_rawDesc = nil + file_method_proto_goTypes = nil + file_method_proto_depIdxs = nil +} diff --git a/protogen/example/strictmode/method.proto b/protogen/example/strictmode/method.proto new file mode 100644 index 00000000..a617dcda --- /dev/null +++ b/protogen/example/strictmode/method.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +option go_package = "github.com/bavix/gripmock/protogen/example/strictmode"; + +package strictmode; + +service GripMock { + rpc SayTitleHello (SayTitleHelloRequest) returns (SayTitleHelloReply); + rpc sayLowerHello (sayLowerHelloRequest) returns (sayLowerHelloReply); +} + +message sayLowerHelloRequest { + string name = 1; +} + +message sayLowerHelloReply { + string message = 1; +} + +message SayTitleHelloRequest { + string name = 1; +} + +message SayTitleHelloReply { + string message = 1; +} diff --git a/protogen/example/strictmode/method_grpc.pb.go b/protogen/example/strictmode/method_grpc.pb.go new file mode 100644 index 00000000..3b470b13 --- /dev/null +++ b/protogen/example/strictmode/method_grpc.pb.go @@ -0,0 +1,148 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.4.0 +// - protoc v5.27.2 +// source: method.proto + +package strictmode + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 + +const ( + GripMock_SayTitleHello_FullMethodName = "/strictmode.GripMock/SayTitleHello" + GripMock_SayLowerHello_FullMethodName = "/strictmode.GripMock/sayLowerHello" +) + +// GripMockClient is the client API for GripMock service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type GripMockClient interface { + SayTitleHello(ctx context.Context, in *SayTitleHelloRequest, opts ...grpc.CallOption) (*SayTitleHelloReply, error) + SayLowerHello(ctx context.Context, in *SayLowerHelloRequest, opts ...grpc.CallOption) (*SayLowerHelloReply, error) +} + +type gripMockClient struct { + cc grpc.ClientConnInterface +} + +func NewGripMockClient(cc grpc.ClientConnInterface) GripMockClient { + return &gripMockClient{cc} +} + +func (c *gripMockClient) SayTitleHello(ctx context.Context, in *SayTitleHelloRequest, opts ...grpc.CallOption) (*SayTitleHelloReply, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SayTitleHelloReply) + err := c.cc.Invoke(ctx, GripMock_SayTitleHello_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *gripMockClient) SayLowerHello(ctx context.Context, in *SayLowerHelloRequest, opts ...grpc.CallOption) (*SayLowerHelloReply, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SayLowerHelloReply) + err := c.cc.Invoke(ctx, GripMock_SayLowerHello_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GripMockServer is the server API for GripMock service. +// All implementations must embed UnimplementedGripMockServer +// for forward compatibility +type GripMockServer interface { + SayTitleHello(context.Context, *SayTitleHelloRequest) (*SayTitleHelloReply, error) + SayLowerHello(context.Context, *SayLowerHelloRequest) (*SayLowerHelloReply, error) + mustEmbedUnimplementedGripMockServer() +} + +// UnimplementedGripMockServer must be embedded to have forward compatible implementations. +type UnimplementedGripMockServer struct { +} + +func (UnimplementedGripMockServer) SayTitleHello(context.Context, *SayTitleHelloRequest) (*SayTitleHelloReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayTitleHello not implemented") +} +func (UnimplementedGripMockServer) SayLowerHello(context.Context, *SayLowerHelloRequest) (*SayLowerHelloReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayLowerHello not implemented") +} +func (UnimplementedGripMockServer) mustEmbedUnimplementedGripMockServer() {} + +// UnsafeGripMockServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GripMockServer will +// result in compilation errors. +type UnsafeGripMockServer interface { + mustEmbedUnimplementedGripMockServer() +} + +func RegisterGripMockServer(s grpc.ServiceRegistrar, srv GripMockServer) { + s.RegisterService(&GripMock_ServiceDesc, srv) +} + +func _GripMock_SayTitleHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SayTitleHelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GripMockServer).SayTitleHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: GripMock_SayTitleHello_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GripMockServer).SayTitleHello(ctx, req.(*SayTitleHelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _GripMock_SayLowerHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SayLowerHelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GripMockServer).SayLowerHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: GripMock_SayLowerHello_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GripMockServer).SayLowerHello(ctx, req.(*SayLowerHelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// GripMock_ServiceDesc is the grpc.ServiceDesc for GripMock service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var GripMock_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "strictmode.GripMock", + HandlerType: (*GripMockServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayTitleHello", + Handler: _GripMock_SayTitleHello_Handler, + }, + { + MethodName: "sayLowerHello", + Handler: _GripMock_SayLowerHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "method.proto", +} From 8833fc0208f50c822ed25496274392968bf9de64 Mon Sep 17 00:00:00 2001 From: Maxim Babichev Date: Sat, 20 Jul 2024 15:37:30 +0300 Subject: [PATCH 2/2] deadcode --- protogen/example/strictmode/demo/server.go | 235 --------------------- 1 file changed, 235 deletions(-) delete mode 100644 protogen/example/strictmode/demo/server.go diff --git a/protogen/example/strictmode/demo/server.go b/protogen/example/strictmode/demo/server.go deleted file mode 100644 index 10f6a44f..00000000 --- a/protogen/example/strictmode/demo/server.go +++ /dev/null @@ -1,235 +0,0 @@ -// Code generated by GripMock. DO NOT EDIT. -// -// This file is generated by GripMock, a tool for generating gRPC mock servers. -// GripMock is a mock server for gRPC services. It's using a .proto file to generate implementation of gRPC service for you. -// You can use GripMock for setting up end-to-end testing or as a dummy server in a software development phase. -// The server implementation is in GoLang but the client can be any programming language that support gRPC. -// -// See https://github.com/bavix/gripmock for more information. -package main - -import ( - "context" - "encoding/json" - "fmt" - "log" - "net" - "net/http" - "os/signal" - "slices" - "strings" - "syscall" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - _ "google.golang.org/grpc/encoding/gzip" - "google.golang.org/grpc/health" - healthgrpc "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/reflection" - "google.golang.org/grpc/status" - jsonpb "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/reflect/protoreflect" - - sdk "github.com/bavix/gripmock-sdk-go" - "github.com/bavix/gripmock/pkg/deps" - "github.com/bavix/gripmock/pkg/grpccontext" - - strictmode "github.com/bavix/gripmock/protogen/example/strictmode" -) - -type GripMock struct { - strictmode.UnsafeGripMockServer - __builder__ *deps.Builder -} - -func (s *GripMock) SayTitleHello(ctx context.Context, in *strictmode.SayTitleHelloRequest) (*strictmode.SayTitleHelloReply, error) { - out := &strictmode.SayTitleHelloReply{} - // Retrieve metadata from the incoming context. - // The metadata is used to find the stub for the method being called. - md, _ := metadata.FromIncomingContext(ctx) - - // Find the stub for the given service name, method name, and metadata. - // The stub defines the input and output messages for the method. - // If the stub is found, its output message is returned. - // If the stub is not found, an error is returned. - err := findStub(ctx, s.__builder__.Config().HTTPAddr, "GripMock", "SayTitleHello", md, in, out) - - // Return the output message and any error encountered while finding the stub. - return out, err -} - -func (s *GripMock) SayLowerHello(ctx context.Context, in *strictmode.SayLowerHelloRequest) (*strictmode.SayLowerHelloReply, error) { - out := &strictmode.SayLowerHelloReply{} - // Retrieve metadata from the incoming context. - // The metadata is used to find the stub for the method being called. - md, _ := metadata.FromIncomingContext(ctx) - - // Find the stub for the given service name, method name, and metadata. - // The stub defines the input and output messages for the method. - // If the stub is found, its output message is returned. - // If the stub is not found, an error is returned. - err := findStub(ctx, s.__builder__.Config().HTTPAddr, "GripMock", "sayLowerHello", md, in, out) - - // Return the output message and any error encountered while finding the stub. - return out, err -} - -func main() { - ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) - defer cancel() - - builder, err := deps.New(ctx) - if err != nil { - log.Fatal(err) - } - - lis, err := net.Listen(builder.Config().GRPCNetwork, builder.Config().GRPCAddr) - if err != nil { - builder.Logger().Fatal().Err(err).Msg("failed to listen") - } - - s := grpc.NewServer( - grpc.UnaryInterceptor(grpccontext.UnaryInterceptor(builder.Logger())), - grpc.StreamInterceptor(grpccontext.StreamInterceptor(builder.Logger())), - ) - - healthcheck := health.NewServer() - healthcheck.SetServingStatus("gripmock", healthgrpc.HealthCheckResponse_NOT_SERVING) - - strictmode.RegisterGripMockServer(s, &GripMock{__builder__: builder}) - - healthgrpc.RegisterHealthServer(s, healthcheck) - reflection.Register(s) - - builder.Logger().Info(). - Str("addr", builder.Config().GRPCAddr). - Str("network", builder.Config().GRPCNetwork). - Msg("Serving gRPC") - - // Health check goroutine to wait for the HTTP server to become ready. - // Once the HTTP server is ready, it sets the gRPC server to SERVING state. - go func() { - // Create a new client to interact with the HTTP server API. - api, err := sdk.NewClientWithResponses( - fmt.Sprintf("http://%s/api", builder.Config().HTTPAddr), - sdk.WithHTTPClient(http.DefaultClient), - ) - if err != nil { - return - } - - // Create a context with a timeout of 120 seconds. - ctx, cancel := context.WithTimeout(ctx, 120*time.Second) - defer cancel() - - // Create a ticker to periodically check the readiness of the HTTP server. - tick := time.NewTicker(250 * time.Millisecond) - defer tick.Stop() - - for { - select { - // Check if the context is done. - case <-ctx.Done(): - return - - // Check if the ticker has fired. - case <-tick.C: - // Call the Readiness API on the HTTP server. - resp, err := api.ReadinessWithResponse(ctx) - - // If the API call is successful and the response is not nil, - // set the gRPC server to SERVING state and log a message. - if err == nil && resp.JSON200 != nil { - healthcheck.SetServingStatus("gripmock", healthgrpc.HealthCheckResponse_SERVING) - - builder.Logger().Info().Msg("gRPC server is ready to accept requests") - - return - } - } - } - }() - - if err := s.Serve(lis); err != nil { - builder.Logger().Fatal().Err(err).Msg("failed to serve") - } -} - -func findStub(ctx context.Context, addr string, service, method string, md metadata.MD, in, out protoreflect.ProtoMessage) error { - // Create a new client with the configured HTTP address. - // Add the default HTTP client as the transport. - api, err := sdk.NewClientWithResponses(fmt.Sprintf("http://%s/api", addr), - sdk.WithHTTPClient(http.DefaultClient), - ) - if err != nil { - return err - } - - // Exclude headers that are not relevant for matching stubs. - excludes := []string{":authority", "content-type", "grpc-accept-encoding", "user-agent"} - - // Create a map of headers to match with the input metadata. - headers := make(map[string]string, len(md)) - for h, v := range md { - // Exclude headers that are not relevant for matching stubs. - if slices.Contains(excludes, h) { - continue - } - - // Join the values of the header with a semicolon. - headers[h] = strings.Join(v, ";") - } - - // Search for a stub that matches the given service, method, and headers. - searchStub, err := api.SearchStubsWithResponse(ctx, sdk.SearchStubsJSONRequestBody{ - Service: service, // The name of the service. - Method: method, // The name of the method. - Headers: headers, // The headers to match. - Data: in, // The input message. - }) - if err != nil { - return err - } - - // If the search was unsuccessful, return an error with the response body. - if searchStub.JSON200 == nil { - return fmt.Errorf(string(searchStub.Body)) - } - - // If the search returned an error, return an error with the error code and message. - if searchStub.JSON200.Error != "" || searchStub.JSON200.Code != nil { - if searchStub.JSON200.Code == nil { - return status.Error(codes.Aborted, searchStub.JSON200.Error) - } - - if *searchStub.JSON200.Code != codes.OK { - return status.Error(*searchStub.JSON200.Code, searchStub.JSON200.Error) - } - } - - // Convert the search result to JSON. - data, err := json.Marshal(searchStub.JSON200.Data) - if err != nil { - return err - } - - // Create a map of headers to set in the context. - mdResp := make(metadata.MD, len(searchStub.JSON200.Headers)) - for k, v := range searchStub.JSON200.Headers { - // Split the values of the header by semicolon and trim each value. - splits := strings.Split(v, ";") - for i, s := range splits { - splits[i] = strings.TrimSpace(s) - } - - mdResp[k] = splits - } - - // Set the headers in the context. - grpc.SetHeader(ctx, mdResp) - - // Unmarshal the search result into the output message. - return jsonpb.Unmarshal(data, out) -}