Skip to content

Commit df0f91b

Browse files
validator: add support for protoc-gen-validate 0.6.0 (#417)
* add support for new validation interface * spelling
1 parent 165f605 commit df0f91b

File tree

3 files changed

+59
-18
lines changed

3 files changed

+59
-18
lines changed

testing/testproto/test.manual_validator.pb.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,23 @@
22

33
package mwitkow_testproto
44

5-
import "errors"
5+
import (
6+
"errors"
7+
"math"
8+
)
69

10+
// Implements the legacy validation interface from protoc-gen-validate.
711
func (p *PingRequest) Validate() error {
812
if p.SleepTimeMs > 10000 {
913
return errors.New("cannot sleep for more than 10s")
1014
}
1115
return nil
1216
}
17+
18+
// Implements the new validation interface from protoc-gen-validate.
19+
func (p *PingResponse) Validate(bool) error {
20+
if p.Counter > math.MaxInt16 {
21+
return errors.New("ping allocation exceeded")
22+
}
23+
return nil
24+
}

validator/validator.go

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,38 @@ import (
1111
"google.golang.org/grpc/status"
1212
)
1313

14+
// The validate interface starting with protoc-gen-validate v0.6.0.
15+
// See https://github.com/envoyproxy/protoc-gen-validate/pull/455.
1416
type validator interface {
17+
Validate(all bool) error
18+
}
19+
20+
// The validate interface prior to protoc-gen-validate v0.6.0.
21+
type validatorLegacy interface {
1522
Validate() error
1623
}
1724

25+
func validate(req interface{}) error {
26+
switch v := req.(type) {
27+
case validatorLegacy:
28+
if err := v.Validate(); err != nil {
29+
return status.Error(codes.InvalidArgument, err.Error())
30+
}
31+
case validator:
32+
if err := v.Validate(false); err != nil {
33+
return status.Error(codes.InvalidArgument, err.Error())
34+
}
35+
}
36+
return nil
37+
}
38+
1839
// UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages.
1940
//
2041
// Invalid messages will be rejected with `InvalidArgument` before reaching any userspace handlers.
2142
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
2243
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
23-
if v, ok := req.(validator); ok {
24-
if err := v.Validate(); err != nil {
25-
return nil, status.Error(codes.InvalidArgument, err.Error())
26-
}
44+
if err := validate(req); err != nil {
45+
return nil, err
2746
}
2847
return handler(ctx, req)
2948
}
@@ -34,10 +53,8 @@ func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
3453
// Invalid messages will be rejected with `InvalidArgument` before sending the request to server.
3554
func UnaryClientInterceptor() grpc.UnaryClientInterceptor {
3655
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
37-
if v, ok := req.(validator); ok {
38-
if err := v.Validate(); err != nil {
39-
return status.Error(codes.InvalidArgument, err.Error())
40-
}
56+
if err := validate(req); err != nil {
57+
return err
4158
}
4259
return invoker(ctx, method, req, reply, cc, opts...)
4360
}
@@ -64,10 +81,10 @@ func (s *recvWrapper) RecvMsg(m interface{}) error {
6481
if err := s.ServerStream.RecvMsg(m); err != nil {
6582
return err
6683
}
67-
if v, ok := m.(validator); ok {
68-
if err := v.Validate(); err != nil {
69-
return status.Error(codes.InvalidArgument, err.Error())
70-
}
84+
85+
if err := validate(m); err != nil {
86+
return err
7187
}
88+
7289
return nil
7390
}

validator/validator_test.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
// Copyright 2016 Michal Witkowski. All Rights Reserved.
22
// See LICENSE for licensing terms.
33

4-
package grpc_validator_test
4+
package grpc_validator
55

66
import (
77
"io"
8+
"math"
89
"testing"
910

1011
grpc_testing "github.com/grpc-ecosystem/go-grpc-middleware/testing"
1112
pb_testproto "github.com/grpc-ecosystem/go-grpc-middleware/testing/testproto"
12-
grpc_validator "github.com/grpc-ecosystem/go-grpc-middleware/validator"
1313
"github.com/stretchr/testify/assert"
1414
"github.com/stretchr/testify/require"
1515
"github.com/stretchr/testify/suite"
@@ -22,14 +22,26 @@ var (
2222
// See test.manual_validator.pb.go for the validator check of SleepTimeMs.
2323
goodPing = &pb_testproto.PingRequest{Value: "something", SleepTimeMs: 9999}
2424
badPing = &pb_testproto.PingRequest{Value: "something", SleepTimeMs: 10001}
25+
26+
// See test.manual_validator.pb.go for the validator check of the counter.
27+
goodPingResponse = &pb_testproto.PingResponse{Counter: 100}
28+
badPingResponse = &pb_testproto.PingResponse{Counter: math.MaxInt16 + 1}
2529
)
2630

31+
func TestValidateWrapper(t *testing.T) {
32+
assert.NoError(t, validate(goodPing))
33+
assert.Error(t, validate(badPing))
34+
35+
assert.NoError(t, validate(goodPingResponse))
36+
assert.Error(t, validate(badPingResponse))
37+
}
38+
2739
func TestValidatorTestSuite(t *testing.T) {
2840
s := &ValidatorTestSuite{
2941
InterceptorTestSuite: &grpc_testing.InterceptorTestSuite{
3042
ServerOpts: []grpc.ServerOption{
31-
grpc.StreamInterceptor(grpc_validator.StreamServerInterceptor()),
32-
grpc.UnaryInterceptor(grpc_validator.UnaryServerInterceptor()),
43+
grpc.StreamInterceptor(StreamServerInterceptor()),
44+
grpc.UnaryInterceptor(UnaryServerInterceptor()),
3345
},
3446
},
3547
}
@@ -38,7 +50,7 @@ func TestValidatorTestSuite(t *testing.T) {
3850
cs := &ClientValidatorTestSuite{
3951
InterceptorTestSuite: &grpc_testing.InterceptorTestSuite{
4052
ClientOpts: []grpc.DialOption{
41-
grpc.WithUnaryInterceptor(grpc_validator.UnaryClientInterceptor()),
53+
grpc.WithUnaryInterceptor(UnaryClientInterceptor()),
4254
},
4355
},
4456
}

0 commit comments

Comments
 (0)