sorcererxw / protoc-gen-go-grpc-mock

Generate Go gRPC service mocks compatible with gomock
MIT License
23 stars 9 forks source link

Separated package for generated mock and proto codes #4

Open AVM-Martin opened 1 year ago

AVM-Martin commented 1 year ago

Is it possible to separate the package? We only need mock service when running unit test and won't generate it

Background

We need put generated mock inside gen/mock directory. The directory tree will look similar to the following

github.com/example/project
├── gen
│   ├── mock
│   │   └── example_grpc_mock.pb.go
│   ├── example.pb.go
│   └── example_grpc.pb.go
└── proto
    └── example.proto

and gen/mock/example_grpc_mock.pb.go file will import structs from github.com/example/project/gen

// Code generated by protoc-gen-go-grpc-mock. DO NOT EDIT.
// source: proto/example.proto

package mock_example

import (
    context "context"
    reflect "reflect"

    gomock "github.com/golang/mock/gomock"
    grpc "google.golang.org/grpc"

    contract "github.com/example/project/gen"
)

// ... omitted

// PostMethodV1 mocks base method.
func (m *MockExampleServiceClient) PostMethodV1(ctx context.Context, in *contract.PostMethodV1Request, opts ...grpc.CallOption) (*contract.PostMethodV1Response, error) {
    m.ctrl.T.Helper()
    varargs := []interface{}{ctx, in}
    for _, a := range opts {
        varargs = append(varargs, a)
    }
    ret := m.ctrl.Call(m, "PostMethodV1", varargs...)
    ret0, _ := ret[0].(*contract.PostMethodV1)
    ret1, _ := ret[1].(error)
    return ret0, ret1
}

// ... omitted

// PostMethodV1 mocks base method.
func (m *MockExampleServiceServer) PostMethodV1(ctx context.Context, in *contract.PostMethodV1Request) (*contract.PostMethodV1Response, error) {
    m.ctrl.T.Helper()
    ret := m.ctrl.Call(m, "PostMethodV1", ctx, in)
    ret0, _ := ret[0].(*contract.PostMethodV1Response)
    ret1, _ := ret[1].(error)
    return ret0, ret1
}

// ... omitted

For further directory sample, you may see the official gomock example here

Further Discussion

If it is possible, we can refer the main generated golang code based on provided flag (i.e. proto_import_path)

sorcererxw commented 1 year ago

I understand your needs very well, but there are two problems:

  1. If the final file structure is like this:

    github.com/example/project
    ├── gen
    │   ├── mock
    │   │   └── example_grpc_mock.pb.go
    │   ├── example.pb.go
    │   └── example_grpc.pb.go
    └── proto
    └── example.proto

    Then the example_grpc_mock.pb.go file should import the parent package:

    // example_grpc_mock.pb.go
    import (
    . "github.com/example/project/gen"
    )

    We tend to use . /;package_name in go_package to generate code to the relative path. However, with google.golang.org/protobuf/compiler/protogen alone, we cannot get the real import path of the parent package in code generation. Of course, you could declare the full package path in the go_package, but this would be too demanding and not a good implementation.

  2. There is a small chance of causing a conflict, for example, if there is already a mock subdirectory:

    github.com/example/project
    ├── proto
    │   ├── mock
    │   │   └── example2.proto
    │   ├── example1.proto

For the reasons above, generating code to a subdirectory doesn't seem to be a common behavior of Go proto plugins. I haven’t found a good solution to above problems yet, so if you have a good idea, feel free to discuss.

AVM-Martin commented 1 year ago

Hi, sorry for a late reply

  1. Yes, we could import the parent package that way, but I do not explicitly define the go_package (see this eliza.proto from bufbuild/connect-demo). I am using this convention because my protobuf contract will be imported from another repository and generated locally, so I need to define go_package on buf.gen.yaml (equivalent with --go_opt=M=$FILENAME=$IMPORT_PATH arg)

https://github.com/bufbuild/connect-demo/blob/4d0f5a60813773f228db9fadef566cf802715d31/buf.gen.yaml#L2-L5

managed:
  enabled: true
  go_package_prefix:
    default: github.com/bufbuild/connect-demo/internal/gen
  1. It doesn’t have to be under gen/mock directory, maybe under /mock directory on the repository root. This is my specific use case (and that means I won’t have proto/mock directory)

I'm open to contribute on this plugin, but I need some time to learn about the codebase