Code Monkey home page Code Monkey logo

gripmock's Introduction

GripMock

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.


Announcement:

The latest version (v1.10) of gripmock is requiring go_package declaration in the .proto file. This is due to the latest update of protoc plugin that being used by gripmock is making the go_package declaration mandatory.

Update Feb 2022:

Version 1.11-beta release is available. It supports NO declaration of go_package, please download and test before it can be tagged as stable.

you can get the docker image using docker pull tkpd/gripmock:v1.11-beta.


Quick Usage

First, prepare your .proto file. Or you can use hello.proto in example/simple/ folder. Suppose you put it in /mypath/hello.proto. We are gonna use Docker image for easier example test. basic syntax to run GripMock is gripmock <protofile>

  • Install Docker
  • Run docker pull tkpd/gripmock to pull the image
  • We are gonna mount /mypath/hello.proto (it must be a fullpath) into a container and also we expose ports needed. Run docker run -p 4770:4770 -p 4771:4771 -v /mypath:/proto tkpd/gripmock /proto/hello.proto
  • On a separate terminal we are gonna add a stub into the stub service. Run curl -X POST -d '{"service":"Gripmock","method":"SayHello","input":{"equals":{"name":"gripmock"}},"output":{"data":{"message":"Hello GripMock"}}}' localhost:4771/add
  • Now we are ready to test it with our client. You can find a client example file under example/simple/client/. Execute one of your preferred language. Example for go: go run example/simple/client/*.go

Check example folder for various usecase of gripmock.


How It Works

Running Gripmock

From client perspective, GripMock has 2 main components:

  1. GRPC server that serves on tcp://localhost:4770. Its main job is to serve incoming rpc call from client and then parse the input so that it can be posted to Stub service to find the perfect stub match.
  2. Stub server that serves on http://localhost:4771. Its main job is to store all the stub mapping. We can add a new stub or list existing stub using http request.

Matched stub will be returned to GRPC service then further parse it to response the rpc call.

From technical perspective, GripMock consists of 2 binaries. The first binary is the gripmock itself, when it will generate the gRPC server using the plugin installed in the system (see Dockerfile). When the server sucessfully generated, it will be invoked in parallel with stub server which ends up opening 2 ports for client to use.

The second binary is the protoc plugin which located in folder protoc-gen-gripmock. This plugin is the one who translates protobuf declaration into a gRPC server in Go programming language.

Inside GripMock


Stubbing

Stubbing is the essential mocking of GripMock. It will match and return the expected result into GRPC service. This is where you put all your request expectation and response

Dynamic stubbing

You could add stubbing on the fly with a simple REST API. HTTP stub server is running on port :4771

  • GET / Will list all stubs mapping.
  • POST /add Will add stub with provided stub data
  • POST /find Find matching stub with provided input. see Input Matching below.
  • GET /clear Clear stub mappings.

Stub Format is JSON text format. It has a skeleton as follows:

{
  "service":"<servicename>", // name of service defined in proto
  "method":"<methodname>", // name of method that we want to mock
  "input":{ // input matching rule. see Input Matching Rule section below
    // put rule here
  },
  "output":{ // output json if input were matched
    "data":{
      // put result fields here
    },
    "error":"<error message>" // Optional. if you want to return error instead.
    "code":"<response code>" // Optional. Grpc response code. if code !=0  return error instead.
  }
}

For our hello service example we put a stub with the text below:

  {
    "service":"Greeter",
    "method":"SayHello",
    "input":{
      "equals":{
        "name":"gripmock"
      }
    },
    "output":{
      "data":{
        "message":"Hello GripMock"
      }
    }
  }

Static stubbing

You could initialize gripmock with stub json files and provide the path using --stub argument. For example you may mount your stub file in /mystubs folder then mount it to docker like

docker run -p 4770:4770 -p 4771:4771 -v /mypath:/proto -v /mystubs:/stub tkpd/gripmock --stub=/stub /proto/hello.proto

Please note that Gripmock still serves http stubbing to modify stored stubs on the fly.

Input Matching

Stub will respond with the expected response only if the request matches any rule. Stub service will serve /find endpoint with format:

{
  "service":"<service name>",
  "method":"<method name>",
  "data":{
    // input that suppose to match with stored stubs
  }
}

So if you do a curl -X POST -d '{"service":"Greeter","method":"SayHello","data":{"name":"gripmock"}}' localhost:4771/find stub service will find a match from listed stubs stored there.

Input Matching Rule

Input matching has 4 rules to match an input: equals, equals_unordered, contains and regex
Nested fields are allowed for input matching too for all JSON data types. (string, bool, array, etc.)
Gripmock recursively goes over the fields and tries to match with given input.
equals will match the exact field name and value of input into expected stub. example stub JSON:

{
  .
  .
  "input":{
    "equals":{
      "name":"gripmock",
      "greetings": {
            "english": "Hello World!",
            "indonesian": "Halo Dunia!",
            "turkish": "Merhaba Dünya!"
      },
      "ok": true,
      "numbers": [4, 8, 15, 16, 23, 42]
      "null": null
    }
  }
  .
  .
}

equals_unordered will match the exact field name and value of input into expected stub, except lists (which are compared as sets). example stub JSON:

{
  .
  .
  "input":{
    "equals_unordered":{
      "name":"gripmock",
      "greetings": {
            "english": "Hello World!",
            "indonesian": "Halo Dunia!",
            "turkish": "Merhaba Dünya!"
      },
      "ok": true,
      "numbers": [4, 8, 15, 16, 23, 42]
      "null": null
    }
  }
  .
  .
}

contains will match input that has the value declared expected fields. example stub JSON:

{
  .
  .
  "input":{
    "contains":{
      "field2":"hello",
      "field4":{
        "field5": "value5"
      } 
    }
  }
  .
  .
}

matches using regex for matching fields expectation. example:

{
  .
  .
  "input":{
    "matches":{
      "name":"^grip.*$",
      "cities": ["Jakarta", "Istanbul", ".*grad$"]
    }
  }
  .
  .
}

gripmock's People

Contributors

guyguy333 avatar hairymike avatar iwanbk avatar jekiapp avatar mytestopia avatar nikolayoskin avatar pmorelli92 avatar thibaultam avatar vincent-raman avatar y-yagi avatar yonasstephen avatar yosiaadijaya avatar zzzz465 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gripmock's Issues

mutiple proto files in docker-compose doesn't work

I am trying to use both flag and non-flag args in docker-compose. It works just fine until I need more than one proto file.

Example of working docker-compose.yml file:

  grpc-server-example-works:
    image: tkpd/gripmock:latest
    command: -stub=/stub /proto/greetV1.proto

Fails, with a log message of "File does not reside within any path specified using --proto_path (or -I). You must specify a --proto_path which encompasses this file..."

  grpc-server-example-fails:
    image: tkpd/gripmock:latest
    command: -stub=/stub /proto/greetV1.proto /proto2/server2Greeting.proto

I am wondering if I am doing something wrong, or if not and it's an issue with go a simple solution would be to accept comma-separated protofiles with a named arg.

Getting TLS handshake error, when trying to mock GRPC service

Getting below error, we are trying to mock the GRPC service using gripmock but when trying to configure the same mock server in code getting below error

Error: rpc error: code = Unavailable desc = last connection error: connection error: desc = "transport: authentication handshake failed: tls: first record does not look like a TLS handshake"

Proposal: Could we generate go_package option at runtime?

Hi there,

The recent change to require the go_package is a breaking change for us. We primarily use nodejs and it doesn't make sense to include it in our protobufs. Our repos are private anyway, so we'd have another step to do to make sure the gripmock image can login to our repos (I believe this triggers a 'go get' under the hood).

I'm wondering if there would be an option to generate the go_package option at runtime? I haven't gone looking at the code just yet, but thought I'd open up a discussion on it.

I'm thinking that before we run the protoc plugin,

  • copy the protobuf file (passed in the arg) to a temporary location
  • parse the file, check for go_package option
  • if we don't find one, generate one and add it to the file
  • use the file in the temporary location to generate the client/server code

Can't handle method name begin with lowercase letters

The tool is really useful and easy to get start with! I found one issue that if the method name defined in proto file begin with lowercase letter, for example I define method 'sayHello' instead of 'SayHello' as below:
#hello.proto
...
service Greeter {
// Sends a greeting
rpc sayHello (HelloRequest) returns (HelloReply) {}
}
...
Then when I start to run docker for gripmock it would report following error:
[root@iz2ze1cb8kqr5kcy80sb9rz mypath]# docker run -p 4770:4770 -p 4771:4771 -v /mypath:/proto ahmadmuzakki/gripmock gripmock /proto/hello.proto
Starting GripMock
Serving stub admin on http://localhost:4771

command-line-arguments

/go/src/grpc/server.go:59:36: cannot use Greeter literal (type *Greeter) as type GreeterServer in argument to RegisterGreeterServer:
*Greeter does not implement GreeterServer (missing SayHello method)
have sayHello("context".Context, *HelloRequest) (*HelloReply, error)
want SayHello("context".Context, *HelloRequest) (*HelloReply, error)

Can you have a look if it's auto-generated code naming issue?

Enum stub

Can you provide an example to stub fields with enum?

GRPC update to latest version

Hello,
We have the requirements for the below updates. Please let me know any plans on this.

  1. Replace github.com/golang/protobuf with google.golang.org/protobuf
  2. Update GRPC lib to the latest version
  3. Add the latest docker images to the repo.
  4. Introduce go modules instead of dep (nice to have)

Thank you,
Harish P

incorrect handling of uint64 \ int64 values from stub json data

service.json in stub folder:

{
    "service": "FriendsAPI",
    "method": "FetchFriends",
    "input": {
        "equals": {
            "user_id": 9223242625195230050
        }
    },
    "output": {
      "data": {
        "friends": [
            {
                "id": 9223242625195229889,
                "sortWeight": 4
            }
        ]
      }
    }
}

Proto file:

syntax = "proto3";

service FriendsAPI {
    rpc FetchFriends (FetchFriendsRequest) returns (FetchFriendsResponse) {}
}

message FetchFriendsRequest {
    uint64 user_id = 1;
}

message FetchFriendsResponse {
    repeated Friend friends = 1;
}

message Friend {
    uint64 id = 1;
    sint32 sort_weight = 2;
}

When requesting FriendsAPI.FetchFriends I got 9223242625195230208 instead of 9223242625195229889.
Smaller values like 922324262519522 or 1307584 are passed to response as thay are.
Problem is only with big values.

Can you fix it please?

migrate gripmock to go modules

Go 1.15 is near(August), and as Go module is becoming the default choice of Go's package manager, should this project also move to the Go module?

Error while running multi protos with docker

Hi ,I'm planning to use gripmock for writing integration test cases but facing issues while executing it .

Starting GripMock Serving stub admin on http://:4771 bar/bar.proto:8:12: "bar.Bar.name" is already defined in file "bar.proto". bar/bar.proto:7:9: "bar.Bar" is already defined in file "bar.proto". hello.proto: Import "bar/bar.proto" was not found or had errors. hello.proto:9:16: "bar.Bar" seems to be defined in "bar.proto", which is not imported by "hello.proto". To use it here, please add the necessary import. 2020/01/14 06:28:56 Fail on protoc exit status 1

This is the error i get while running the command

docker run -p 4770:4770 -p 4771:4771 -v /Desktop/gripmock/example/multi-package:/proto tkpd/gripmock --imports=/proto /proto/bar/bar.proto /proto/hello.proto /proto/foo.proto

Any help ?

Support .proto file imports

Hi,

Is there any way to support mocking a .proto file which in turn imports other proto files defining types, etc?

Support dependencies with package names that include ";"

I noticed that if you try to start a service with a proto file that includes a dependency on something with package like go_package=github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor, it fails with:

2019/09/05 03:16:17 Failed to generate server formatting 20:19: invalid import path: "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor" (and 1 more errors)

This is because server.tmpl just naively uses the package declaration as the import statement, which results in invalid like above. It can be fixed by truncating the package declaration at the semicolon.

Gripmock container fails to build when using protobuf definitions split across multiple files

I am trying to mock a service that has protobuf definitions split across multiple files. However, gripmock throws an error saying either my imports (think file1.proto importing file2.proto) were either not found or or had errors. I know that they don't have any errors because gripmock runs fine when I copy the definitions in file2.proto over to file1.proto. Is multi-file protobuf definitions not supported yet? If it is can you please update your docs to reflect how I can work with them?

How to stub both gRPC and Rest (GET/POST) endpoint?

I have a service that is based on gRPC. But that having both types of downstream:

Web Server - Call them via GET/POST.
gRPC Server - Call them via gRPC.
Can we use gripmock to stub both endpoints? If yes, please share an example.

Add Guidelines for using repeated fields

I have been trying to stub a response which has repeated field of another message. But couldn't make it work. Please add some guidelines for using repeated fields. If it's not supported please add a note in the README about that.

Support for proto3 `optional`

Hey there, great job on making this, it is much needed.

I tried using the package, but it seems optional is not supported. When running the package, I get This file contains proto3 optional fields, but --experimental_allow_proto3_optional was not set., so maybe it's as simple as passing the experimental flag to proto-gen?

Cheers

What is the "M" argument on the command line?

Hi , with latest docker image(v1.10.1), I get a error:

| Please specify either:
|      • a "go_package" option in the .proto source file, or
|      • a "M" argument on the command line.

What is a "M" argument on the command line. and how to pass it to command line?
(I don't want to add go_package to proto file)

Gripmock is unable to bind data if the response message has "_" in one of the field name

I am trying to setup a mock service with response messages that have properties with "_" in their name. However, for these messages gripmock is returning responses without binding what I have put in the "data" property in my stubs for the said properties. For example, if using the following protos

service Gripmock { rpc SayHello (Request) returns (Response); }
message Request { string name = 1; }
message Response { string message_field = 1; }

along with this stub
{ "service": "Gripmock", "method": "SayHello", "input": { "equals": { "name": "Gripmock" } }, "output": { "data": { "message_property": "Hello from gripmock" } } }

the returned response has an empty string in the 'message_property' versus "Hello from gripmock". Also, there are no logs warning me about if something's gone wrong. Are properties with "_" in their names not supported? Or is this a bug?

Docker latest version points to wrong version

Hey, first of thanks for your project!

We are currently trying out gRPC for our internal services and we were evaluating/looking for something to support our test setup and this looked like exactly what we need.
We then used your latest docker image for this and immediately stumbled over this issue where properties stay empty if they have an underscore in their name.

After a long debugging session it turned out that your latest docker image does not point to the actual latest release (v0.8.2, which supposedly fixed that underscore issue) and instead points still to v0.8.1. So just a heads up in case you guys didn't notice yet :)
https://registry.hub.docker.com/r/tkpd/gripmock/tags

Support proto3 canonical encoding

grimock 1.8.2 fails to parse a response with a google.protobuf.Timestamp encoded as a single string, as defined in https://developers.google.com/protocol-buffers/docs/proto3#json:

* 'TimestampField' expected a map, got 'string'

https://github.com/golang/protobuf/blob/v1.0.0/jsonpb/jsonpb.go should be used instead of json.Marshal in:

sed: /go/src/grpc/file_2.pb.go: No such file or directory

We use gripmock with multiple package import in our project's integration tests.

We had two proto files under v1_0_0 folder -
file_1.proto and file_2.proto
and this is how we were using to bring up gripmock

gripmock --stub=/drone/src/integration-tests/docker-mock/gripmock/mappings --imports=/proto /proto/v1_0_0/file_1.proto /proto/v1_0_0/file_2.proto

It use to work fine until we have a change in our proto folder structure -
file_1.proto went under v1_1_0 folder

v1_1_0/file_1.proto

and file_2 is under v1_0_0 folder
v1_0_0/file_2.proto

So, we changed the gripmock statement to following -
gripmock --stub=/drone/src/integration-tests/docker-mock/gripmock/mappings --imports=/proto /proto/v1_1_0/file_1.proto /proto/v1_0_0/file_2.proto

Since then we are unable to bring up gripmock docker container and it throws following error -

cp -r /drone/src/components/xyz/idl/abc/protobuf/grpc/* /proto

  • mkdir /stub
  • cp -r /drone/src/integration-tests/docker-mock/gripmock/mappings/* /stub
  • gripmock --stub=/drone/src/integration-tests/docker-mock/gripmock/mappings --imports=/proto /proto/v1_1_0/file_1.proto /proto/v1_0_0/file_2.proto
    Starting GripMock
    Serving stub admin on http://:4771
    2021/07/09 20:41:29 WARNING: Missing 'go_package' option in "file_1.proto",
    please specify it with the full Go package path as
    a future release of protoc-gen-go will require this be specified.
    See https://developers.google.com/protocol-buffers/docs/reference/go-generated#package for more information.

2021/07/09 20:41:29 WARNING: Missing 'go_package' option in "v1_0_0/file_2.proto",
please specify it with the full Go package path as
a future release of protoc-gen-go will require this be specified.
See https://developers.google.com/protocol-buffers/docs/reference/go-generated#package for more information.

WARNING: Package "github.com/golang/protobuf/protoc-gen-go/generator" is deprecated.
A future release of golang/protobuf will delete this package,
which has long been excluded from the compatibility promise.

sed: /go/src/grpc/file_2.pb.go: No such file or directory
2021/07/09 20:41:29 Fail on sed

This is how our complete gripmock docker container definition looks like -

  • name: abc_service_gripmock
    image: tkpd/gripmock:latest
    commands:
    - cp -r /drone/src/components/xyz/idl/abc/protobuf/grpc/* /proto
    - mkdir /stub
    - cp -r /drone/src/integration-tests/docker-mock/gripmock/mappings/* /stub
    - gripmock --stub=/drone/src/integration-tests/docker-mock/gripmock/mappings --imports=/proto /proto/v1_1_0/file_1.proto /proto/v1_0_0/file_2.proto

Why is it trying to find a go package? We never had auto generated go packages in our project before folder structure change as well and it was working fine.
Could you please help?

Support protoc-gen-validate

PGV makes it possible to define validation rules at the field level. In a RPC context, it's a great way to document the constraints and fail early if a rule is violated, without implementing anything.

In our gRPC services implementation, we chose to automatically return a INVALID_ARGUMENT gRPC error code on the server-side if anything in the request payload violates a rule, with a human-readable representation of the violation as a string.

In the context of a mock, PGV annotations could be enforced in a similar way to mimic this behavior:

  1. at stubbing time, by returning a 400 HTTP response if anything in the request or response payload violates a rule
  2. at serving time, by returning a INVALID_ARGUMENT gRPC error code if anything in the request payload violates a rule

By making (2) configurable (error code, message?), clients of gripmock can then be sure that validation rules will match how the actual implementation will behave.

Support error codes

Currently gripmock only able to expect string error. It would be better if it also support error codes like in closed PR #17. What I had in mind is instead of adding another field it'd be possible to type check wether the error is a string or map[string]interface{}

Note handling protobufs that import other protobufs

If a protobuf imports another protobuf, like:

// a.proto
syntax = "proto3";

package a;

import "b.proto";

service A {
    rpc funA(b.BRequest) returns (b.BResponse) {}
}
// b.proto

syntax = "proto3";

package b;

message BRequest {
}

message BResponse {
}

gripmock fails with:

can't parse proto <source>:3:25: unexpected "." (expected ")" ...)

Unable to use 'go_package' option with full import path in proto file

I am tring to use gripmock with docker, and mount the user.proto file into docker

but the docker exit with:

Starting GripMock
Serving stub admin on http://:4771
sed: /go/src/grpc/user.pb.go: No such file or directory
2021/01/23 03:11:35 Fail on sed

It seems the pb.go file didn't generated.

Check how many times a service method was called

I think it will be worth it if we have a route to check how many times a certain method was called, to make sure our code actually did consume the stubs we added before we clear them in the next test

example

curl -X GET callCount/serviceName/methodName

that should return zero if not called at all or number of calls if any.

may be doable if we appended call count with every call to findStub from Grpc mock server? Excluding calls made to find if a stub exists or not ofcourse

Cannot mock response that includes oneOf

The example proto file in the docs works fine but when I amend it to include a oneOf it does not work for me.
The amended proto file is:
`syntax = "proto3";

package simple;

// The Gripmock service definition.
service Gripmock {
// simple unary method
rpc SayHello (Request) returns (Reply);
}

// The request message containing the user's name.
message Request {
string name = 1;
}

message Reply {
oneof replyType {
Reply1 reply1 = 1;
Reply2 reply2 = 2;
}
}

// usual response type
message Reply1 {
string message = 1;
int32 return_code = 2;
}

// other response type
message Reply2 {
int32 other = 1;
}When I run my gripmock container I add a dynamic stub as follows:curl -X POST -d
'{ "service":"Gripmock",
"method":"SayHello",
"input":{
"equals":{
"name":"tokopedia"
}
},
"output":{
"data":{
"reply1":{
"message":"Hello GripMock"
}
}
}
}' localhost:4881/add`
and the stub is added ok

However when I call out to the mocked gRPC service, a match is returned but the serialized data does not include my reply.
The stringified data returned is:
{"wrappers_":null,"arrayIndexOffset_":-1,"array":[],"pivot_":1.7976931348623157e+308,"convertedPrimitiveFields_":{}}

Note that I am generating typescript stubs and using those to test.

My key questions are:

  1. Has anyone successfuly stubbed a oneOf using gripmock?
  2. If so, what is different to what we have done above?

Can't parse stream fields

I prepared proto file like this:

syntax = "proto3";

package sample;

service CustomerService {
  rpc ListPerson(RequestType) returns (stream Person) {}
}

message ResponseType {
}

message Person {
  string name = 1;
  int32 age = 2;
}

But gripmock can't parse this file, and says an error.

Starting GripMock
Serving stub admin on http://:4771
2019/01/08 05:56:22 can't parse proto <source>:2:47: unexpected "Person" (expected ")" ...)

I think that gripmock can not parse stream keywords, because it can parse when I remove stream keywords.

"bytes" giving error "source data must be an array or slice, got string"

I have a proto with "bytes" (in a repeated wrapper object, though this should be unrelated). From what I can tell this should be represented as a Base64 string, however this is giving the client an error that "source data must be an array or slice, got string"

Am I doing something wrong, or are bytes not currently supported?

Example proto:

syntax = "proto3";

package simple;

service Gripmock {
  rpc SayHello (Request) returns (Reply);
}

message Request {
  string name = 1;
}

message Reply {
  repeated Foo foo = 1;
}

message Foo {
  bytes message = 1;
}

Example stub:

{
  "service": "Gripmock",
  "method": "SayHello",
  "input": {
    "equals": {
      "name": "tokopedia"
    }
  },
  "output": {
    "data": {
      "foo": [{
        "message": "SGVsbG8gVG9rb3BlZGlh"
      }]
    }
  }
}

Not handling methods terminated with semicolon

Hi. First off thanks for your tool.

I had a service defined using the rpc syntax terminated with a colon, as introduced in the protocol buffers documentation:

// my-proto.proto
...
service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);
}
...

Which gives rise to the error:

2019/04/08 18:40:31 can't parse proto <source>:2:59: unexpected ";" (expected "{" ...)

This error goes away when using the alternate syntax (terminating an rpc definition with curly brackets):

// my-proto.proto
...
service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse) {}
}
...

I was pretty confused because I'd never come across the curly brackets syntax before.

Not handling common protobuf message types

I have a proto file like this:

syntax = "proto3";

option optimize_for = SPEED;

package events_store;

import "google/protobuf/wrappers.proto";
import "google/protobuf/empty.proto";

service EventsStore {
    rpc CreateEvent (Event) returns (CreateEventResponse) {}
    rpc GetAllEvents (GetAllEventsRequest) returns (EventsList) {}

    rpc HealthCheck(google.protobuf.Empty) returns (google.protobuf.Empty) {}
}

While passing this proto file to gripmock, it was unable to find the file where common protobuf message types like wrappers.proto and empty.proto are defined. I am getting the following error

Starting GripMock
Serving stub admin on http://:4771
google/protobuf/wrappers.proto: File not found.
google/protobuf/empty.proto: File not found.
events_store.proto: Import "google/protobuf/wrappers.proto" was not found or had errors.
events_store.proto: Import "google/protobuf/empty.proto" was not found or had errors.
events_store.proto:49:3: "google.protobuf.StringValue" is not defined.
2019/01/11 19:45:42 Fail on protoc exit status 1

I got this error while running it on docker image with the command
docker run -p 4770:4770 -p 4771:4771 -v /events_store:/proto ahmadmuzakki/gripmock gripmock -stub=/proto/stubs /proto/events_store.proto

When I ran this in my local using protoc version 3.6.1 it was able to parse the file successfully.

How to run without docker

Our company is an intranet environment,so How to run it without docker.
I tried to compile locally,and the following operations are done,

go get github.com/golang/protobuf/proto
go get google.golang.org/grpc
go get github.com/golang/protobuf/protoc-gen-go

But I can't run it.
It seems that some environment is missing,such as missing proto

need some guide. best wishes

package com/language/v1/language.proto is not in GOROOT

I am trying to stub following example: https://github.com/slavovojacek/blogging.git

But are getting:

/go/src/grpc/hello_service.pb.go:10:2: package com/language/v1/language.proto is not in GOROOT (/usr/local/go/src/com/language/v1/language.proto)
2021/04/18 23:40:00 exit status 1

Using following command line to run it:

docker run -p 4770:4770 -p 4771:4771 -v /tmp/proto/blogging/grpc-node-buf-typescript/proto:/proto tkpd/gripmock -imports=/proto /proto/services/hello/v1/hello_service.proto

I am not too familiar with Go lang and are stuck trying to get more complex examples to work.

Thanks for your help

How can I define mock response data containing "repeated" fields?

I defined stub data below. The field "repeated_items" is "repeated" field.

{
  "service": "SampleService",
  "method": "GetSample",
  "input": {
    "equals": {
      "param" : {"value": "a"}
    }
  },
  "output": {
    "data": {
      "repeated_items": [
           {"item_id": {"value": 1}} 
      ]
    }
  }
}

Then, gripmock responsed a message below. The field "repeated_items" has no data.

{
  "repeated_items": []
}

The stub data definition above Is wrong?
How can I define stub response data containing "repeated" fields?

Generated server.go has wrong types at service methods

Hello, I have a grpc service and in integration tests, I would like to mock that service. Here the one of the pb.go files (auto-generated), The generated server.go file uses the wrong package, therefore the build fails.

We can see thtat AddItemReq is in "main" package, but in "server.go", this type(AddItemReq) is assumed to be in "basketproto" package (which is defined in .proto files).

So I got this error: go/src/grpc/server.go:28:47: undefined: basketproto,

This is my starting shell command.

gripmock --stub=/stub /proto/basket-service.proto /proto/add-item.proto *** other proto files

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: add-item.proto

package main

import (
        fmt "fmt"
        proto "github.com/golang/protobuf/proto"
        math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type AddItemReq struct {
       *
}



Generated server.go


package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "io/ioutil"
        "log"
        "net"
        "net/http"

        "github.com/mitchellh/mapstructure"
        "golang.org/x/net/context"
        "google.golang.org/grpc"
        "google.golang.org/grpc/reflection"

        empty "github.com/golang/protobuf/ptypes/empty"
)

const (
        TCP_ADDRESS = ":4770"
        HTTP_PORT   = ":4771"
)

type Basket struct{}

func (s *Basket) AddItem(ctx context.Context, in *basketproto.AddItemReq) (*empty.Empty, error) {
        out := &empty.Empty{}
        err := findStub("Basket", "AddItem", in, out)
        return out, err
}

func main() {
        lis, err := net.Listen("tcp", TCP_ADDRESS)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }

        s := grpc.NewServer()

        RegisterBasketServer(s, &Basket{})

        reflection.Register(s)
        fmt.Println("Serving gRPC on tcp://" + TCP_ADDRESS)
        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}

type payload struct {
        Service string      `json:"service"`
        Method  string      `json:"method"`
        Data    interface{} `json:"data"`
}

type response struct {
        Data  interface{} `json:"data"`
        Error string      `json:"error"`
}

func findStub(service, method string, in, out interface{}) error {
        url := fmt.Sprintf("http://localhost%s/find", HTTP_PORT)
        pyl := payload{
                Service: service,
                Method:  method,
                Data:    in,
        }
        byt, err := json.Marshal(pyl)
        if err != nil {
                return 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)
        }

        if resp.StatusCode != http.StatusOK {
                body, _ := ioutil.ReadAll(resp.Body)
                return 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)
        }

        if respRPC.Error != "" {
                return fmt.Errorf(respRPC.Error)
        }

        return mapstructure.Decode(respRPC.Data, out)
}

Error happend when execute build.sh

Hi.

If .proto file which import google/api/annotations.proto, happend error.

Starting GripMock
Serving stub admin on http://:4771
google/api/annotations.proto: File not found.
<my proto file>.proto: Import "google/api/annotations.proto" was not found or had errors.
2020/05/21 01:37:06 Fail on protoc exit status 1

So, I tried to fix and build. But failed to build.

$ go mod init example.com/m
$ go mod tidy
$ sh build.sh <my-version>
can't load package: package ..: no Go files in 
<path of parent directory>
Sending build context to Docker daemon  338.4kB
Step 1/20 : FROM golang:alpine
 ---> 459ae5e869df
Step 2/20 : RUN mkdir /proto
 ---> Using cache
 ---> 7ecfc147079b
Step 3/20 : RUN mkdir /stubs
 ---> Using cache
 ---> 8d64db26f6d6
Step 4/20 : RUN apk -U --no-cache add git protobuf
 ---> Using cache
 ---> a04d625d19a7
Step 5/20 : RUN go get -u -v github.com/golang/protobuf/protoc-gen-go   github.com/mitchellh/mapstructure       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
 ---> Using cache
 ---> 2ec138435302
Step 6/20 : RUN go get -u -v github.com/gobuffalo/packr/v2/...                  github.com/gobuffalo/packr/v2/packr2
 ---> Using cache
 ---> 4b5b57890338
Step 7/20 : RUN git clone https://github.com/google/protobuf.git /protobuf-repo
 ---> Using cache
 ---> a79ae88594c7
Step 8/20 : RUN mkdir protobuf
 ---> Using cache
 ---> d44539182ae3
Step 9/20 : RUN mv /protobuf-repo/src/ /protobuf/
 ---> Using cache
 ---> 030d81d7ba6a
Step 10/20 : RUN rm -rf /protobuf-repo
 ---> Using cache
 ---> 3342bee8b2d5
Step 11/20 : RUN mkdir -p /go/src/github.com/tokopedia/gripmock
 ---> Using cache
 ---> 57fbd1784438
Step 12/20 : COPY . /go/src/github.com/tokopedia/gripmock
 ---> d82debd71f6d
Step 13/20 : WORKDIR /go/src/github.com/tokopedia/gripmock/protoc-gen-gripmock
 ---> Running in 2149773aa51d
Removing intermediate container 2149773aa51d
 ---> 209708c2c4b9
Step 14/20 : RUN packr2
 ---> Running in 7cc94d71f970
Removing intermediate container 7cc94d71f970
 ---> 0ca9a2e1a563
Step 15/20 : RUN go install -v
 ---> Running in 5700f2295ccc
go: downloading github.com/golang/protobuf v1.4.2
go: downloading github.com/gobuffalo/packr/v2 v2.8.0
go: downloading golang.org/x/tools v0.0.0-20200520220537-cf2d1e09c845
go: downloading github.com/tokopedia/gripmock v0.8.1
go: finding module for package github.com/tokopedia/gripmock/protoc-gen-gripmock/packrd
go: downloading github.com/gobuffalo/packd v1.0.0
go: downloading github.com/karrick/godirwalk v1.15.3
go: downloading github.com/markbates/safe v1.0.1
go: downloading github.com/gobuffalo/logger v1.0.3
go: downloading github.com/markbates/errx v1.1.0
go: downloading github.com/markbates/oncer v1.0.0
go: downloading golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c
go: downloading github.com/sirupsen/logrus v1.4.2
go: downloading google.golang.org/protobuf v1.23.0
go: downloading golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
go: downloading golang.org/x/mod v0.2.0
go: downloading golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
main-packr.go:8:8: module github.com/tokopedia/gripmock@latest found (v0.8.1), but does not contain package github.com/tokopedia/gripmock/protoc-gen-gripmock/packrd
The command '/bin/sh -c go install -v' returned a non-zero code: 1

can't load package: package ..: no Go files in

Is go build ../. in build.sh correct?

main-packr.go:8:8: module github.com/tokopedia/gripmock@latest found (v0.8.1), but does not contain package github.com/tokopedia/gripmock/protoc-gen-gripmock/packrd

How do I resolve that?

panic: runtime error: index out of range [1] with length 1

docker-compose:

  gripmock:
    image: tkpd/gripmock:0.8
    ports:
      - "4770:4770"
      - "4771:4771"

Error:

panic: runtime error: index out of range [1] with length 1

goroutine 1 [running]:
main.main()
        /go/src/github.com/tokopedia/gripmock/gripmock.go:25 +0xc36

This is also with mounting a single .proto file in /protos.

Can't parse Enum fields

Hi there!

Great library, I just couldn't make it work yet.

I have a proto definition with a GRPC enum type. When I run gripmock i get the following ouput:

Starting GripMock
Serving stub admin on http://localhost:4771
2018/11/21 13:13:53 can't parse proto <source>:6:1: unexpected token "enum"

My protos compiles just fine but GripMock doesn't seem to like the enum type can you advise what's wrong

Send and receive stream

Could you please provide an example how to setup mocking server if a client needs to send and receive multiple data?

For example having following proto:

syntax = "proto3";

package com.book;

message Book {
    int64 isbn = 1;
    string title = 2;
    string author = 3;
}

message GetBookRequest {
    int64 isbn = 1;
}

service BookService {
    rpc GetBook (GetBookRequest) returns (Book) {}
}

It's needed mock server to operate with following data:

{
  "isbn": 1,
  "author": "Great Gatsby",
  "author": "Fitzgerald"
},
{
  "isbn": 1,
  "author": "Tender Is the Night",
  "author": "Fitzgerald"
},
{
  "isbn": 2,
  "author": "To Kill a Mockingbird",
  "author": "Harper Lee"
}

How do I add a request that has `oneof` keyword in the stub?

message GetApplicationRequest {
  oneof request {
    int32 application_id = 1;
    string api_key = 2;
  }
}

I tried the following but I am getting a Can't find stub error

  "service": "ConfigurationServiceAPI",
  "method": "GetApplication",
  "input": {
    "matches": {      
      "equals":{
          "api_key": "bogus_string"
      }
    }
  }

The error is

service-mock               | 2021/06/15 10:43:39 Can't find stub 
service-mock               |
service-mock               | Service: ConfigurationServiceAPI     
service-mock               |
service-mock               | Method: GetApplication
service-mock               |
service-mock               | Input
service-mock               |
service-mock               | {
service-mock               |      Request: map[ApiKey:bogus_string]
service-mock               | }
service-mock               |
service-mock               | Closest Match
service-mock               |
service-mock               | equals:{
service-mock               |      api_key: bogus_string
service-mock               | }

I also tried ohter possible implemention I can think of but none of them works

Problem with running multi proto setup on Docker

Hi!

I have a problem with running multi proto setup. I try to execute multi-package example with Docker command:
docker run --rm -p 4770:4770 -p 4771:4771 -v <local_protos>:/proto tkpd/gripmock --imports=/proto/ /proto/foo.proto /proto/hello.proto
where <local_protos> is a path to folder containing hello.proto, foo.proto and bar/bar.proto as in example. As a result container doesn't start and I get following logs:

Starting GripMock
Serving stub admin on http://:4771
2020/02/28 20:36:20 Failed to generate server formatting: 35:62: expected type, found '.' (and 2 more errors)
// Code generated by GripMock. DO NOT EDIT.
package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "io"
        "io/ioutil"
        "log"
        "net"
        "net/http"

        "github.com/mitchellh/mapstructure"
        "golang.org/x/net/context"
        "google.golang.org/grpc"
        "google.golang.org/grpc/reflection"
)

import bar "github.com/tokopedia/gripmock/example/multi-package/bar"

const (
        TCP_ADDRESS  = ":4770"
        HTTP_PORT = ":4771"
)



type Gripmock struct{}





func (s *Gripmock) Greet(ctx context.Context, in *bar.Bar) (*.Response,error){
        out := &.Response{}
        err := findStub("Gripmock", "Greet", in, out)
        return out, err
}







func main() {
        lis, err := net.Listen("tcp", TCP_ADDRESS)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }

        s := grpc.NewServer()


        RegisterGripmockServer(s, &Gripmock{})



        reflection.Register(s)
        fmt.Println("Serving gRPC on tcp://" + TCP_ADDRESS)
        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}


type payload struct {
        Service string      `json:"service"`
        Method  string      `json:"method"`
        Data    interface{} `json:"data"`
}

type response struct {
        Data  interface{} `json:"data"`
        Error string      `json:"error"`
}

func findStub(service, method string, in, out interface{}) error {
        url := fmt.Sprintf("http://localhost%s/find", HTTP_PORT)
        pyl := payload{
                Service: service,
                Method:  method,
                Data:    in,
        }
        byt, err := json.Marshal(pyl)
        if err != nil {
                return 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)
        }

        if resp.StatusCode != http.StatusOK {
                body, _ := ioutil.ReadAll(resp.Body)
                return 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)
        }

        if respRPC.Error != "" {
                return fmt.Errorf(respRPC.Error)
        }

        return mapstructure.Decode(respRPC.Data, out)
}

--gripmock_out: protoc-gen-gripmock: Plugin failed with status code 1.
2020/02/28 20:36:20 Fail on protoc exit status 1

Additionally when I try to run another setup with two different and not related proto files I get another error:

Starting GripMock
Serving stub admin on http://:4771
2020/02/28 20:54:56 Failed to generate server formatting: 65:7: expected 'IDENT', found 'struct'
// Code generated by GripMock. DO NOT EDIT.
package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "io"
        "io/ioutil"
        "log"
        "net"
        "net/http"

        "github.com/mitchellh/mapstructure"
        "golang.org/x/net/context"
        "google.golang.org/grpc"
        "google.golang.org/grpc/reflection"
)

const (
        TCP_ADDRESS  = ":4770"
        HTTP_PORT = ":4771"
)



type MathService struct{}





func (s *MathService) Add(ctx context.Context, in *Double) (*Result,error){
        out := &Result{}
        err := findStub("MathService", "Add", in, out)
        return out, err
}





func (s *MathService) Power(ctx context.Context, in *Single) (*Result,error){
        out := &Result{}
        err := findStub("MathService", "Power", in, out)
        return out, err
}





func (s *MathService) Hello(ctx context.Context, in *Text) (*Text,error){
        out := &Text{}
        err := findStub("MathService", "Hello", in, out)
        return out, err
}







type  struct{}







func main() {
        lis, err := net.Listen("tcp", TCP_ADDRESS)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }

        s := grpc.NewServer()


        RegisterMathServiceServer(s, &MathService{})



        RegisterServer(s, &{})



        reflection.Register(s)
        fmt.Println("Serving gRPC on tcp://" + TCP_ADDRESS)
        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}


type payload struct {
        Service string      `json:"service"`
        Method  string      `json:"method"`
        Data    interface{} `json:"data"`
}

type response struct {
        Data  interface{} `json:"data"`
        Error string      `json:"error"`
}

func findStub(service, method string, in, out interface{}) error {
        url := fmt.Sprintf("http://localhost%s/find", HTTP_PORT)
        pyl := payload{
                Service: service,
                Method:  method,
                Data:    in,
        }
        byt, err := json.Marshal(pyl)
        if err != nil {
                return 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)
        }

        if resp.StatusCode != http.StatusOK {
                body, _ := ioutil.ReadAll(resp.Body)
                return 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)
        }

        if respRPC.Error != "" {
                return fmt.Errorf(respRPC.Error)
        }

        return mapstructure.Decode(respRPC.Data, out)
}

--gripmock_out: protoc-gen-gripmock: Plugin failed with status code 1.
2020/02/28 20:54:56 Fail on protoc exit status 1

I tried with different Docker image tags available but no luck.
Am I missing something here? I would really appreciate any help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.