Skip to content

cmd/protoc-gen-go-grpc: add protoc change detector test #6910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ jobs:
# Run the main gRPC-Go tests.
tests:
# Proto checks are run in the above job.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should be moved with the env lines and updated to something like in the vet-proto job.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, I can do that

env:
VET_SKIP_PROTO: 1
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
Expand Down Expand Up @@ -98,14 +96,20 @@ jobs:

# Only run vet for 'vet' runs.
- name: Run vet.sh
env:
VET_SKIP_PROTO: 1
if: matrix.type == 'vet'
run: ./vet.sh -install && ./vet.sh

# Main tests run for everything except when testing "extras"
# (where we run a reduced set of tests).
- name: Run tests
if: matrix.type == 'tests'
env:
VET_BUILD_GO_PROTOC: 1
run: |
./vet.sh -install
protoc --version
Comment on lines +108 to +112
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't want to be run for every version of Go that we test, presumably.

Let's test it in extras instead, below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, that's reasonable

go version
go test ${{ matrix.testflags }} -cpu 1,4 -timeout 7m google.golang.org/grpc/...
cd "${GITHUB_WORKSPACE}"
Expand Down
97 changes: 97 additions & 0 deletions cmd/protoc-gen-go-grpc/grpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
*
* Copyright 2024 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package main

import (
"os"
"os/exec"
"reflect"
"strings"
"testing"
)

func TestProtocBinary(t *testing.T) {
workingDir, err := os.Getwd()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this workingDir at all. os.MkdirTemp uses the default temp directory if the first parameter is "" which seems perfectly fine and command.Dir defaults to the current directory already.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, will do

if err != nil {
t.Fatalf("failed to get current working directory: %v", err)
}

tmpDir, err := os.MkdirTemp(workingDir, "test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}

defer t.Cleanup(func() {
err := os.RemoveAll(tmpDir)
if err != nil {
t.Fatalf("error removing temp dir and all test files: %v", err)
}
})

protocPath, err := exec.LookPath("protoc")
if err != nil {
t.Fatalf("protoc not found in PATH: %v", err)
}

for _, spec := range []struct {
protoFile string
}{
{
protoFile: "test_unary.proto",
},
{
protoFile: "test_server_streaming.proto",
},
{
protoFile: "test_client_streaming.proto",
},
{
protoFile: "test_bidirectional_streaming.proto",
},
} {
protoFilePath := "./proto/" + spec.protoFile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use path.Join instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds like a plan

if _, err := os.Stat(protoFilePath); os.IsNotExist(err) {
t.Fatalf("proto file %s does not exist", protoFilePath)
}

command := exec.Command(protocPath, "--go-grpc_out="+tmpDir, protoFilePath)
command.Dir = workingDir

output, err := command.CombinedOutput()
if err != nil {
t.Fatalf("failed to execute command protoc: %v\n%s", err, output)
}

pbgoFile := strings.Replace(spec.protoFile, ".proto", "_grpc.pb.go", 1)

testPluginContent, err := os.ReadFile(tmpDir + "/testdata/proto/" + pbgoFile)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment re: path.Join and below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

if err != nil {
t.Errorf("error while reading proto file generated from test: %s", err)
}

protocPluginContent, err := os.ReadFile("./testdata/proto/" + pbgoFile)
if err != nil {
t.Errorf("error while reading proto file generated from protoc command: %s", err)
}

if !reflect.DeepEqual(testPluginContent, protocPluginContent) {
t.Errorf("error generated go test stubs are not equal")
}
Comment on lines +93 to +95
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use cmp.Diff and show the results so if things change we can see exactly what.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds like an awesome plan

}
}
31 changes: 31 additions & 0 deletions cmd/protoc-gen-go-grpc/proto/test_bidirectional_streaming.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option go_package = "testdata/proto";

package main;

message EventRequest {
bytes content = 1;
}

message EventResponse {
bytes content = 1;
}

service BidirectionalStreamingService {
rpc bidirectionalMethod(stream EventRequest) returns (stream EventResponse) {}
}
31 changes: 31 additions & 0 deletions cmd/protoc-gen-go-grpc/proto/test_client_streaming.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option go_package = "testdata/proto";

package main;

message EventRequest {
bytes content = 1;
}

message EventResponse {
bytes content = 1;
}

service ClientStreamingService {
rpc clientMethod(stream EventRequest) returns (EventResponse) {}
}
31 changes: 31 additions & 0 deletions cmd/protoc-gen-go-grpc/proto/test_server_streaming.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option go_package = "testdata/proto";

package main;

message EventRequest {
bytes content = 1;
}

message EventResponse {
bytes content = 1;
}

service ServerStreamingService {
rpc serverMethod(EventRequest) returns (stream EventResponse) {};
}
31 changes: 31 additions & 0 deletions cmd/protoc-gen-go-grpc/proto/test_unary.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option go_package = "testdata/proto";

package main;

message EventRequest {
bytes content = 1;
}

message EventResponse {
bytes content = 1;
}

service UnaryService {
rpc unaryMethod(EventRequest) returns (EventResponse) {}
}
Loading