1// Copyright 2016 Michal Witkowski. All Rights Reserved.
2// See LICENSE for licensing terms.
3
4package grpc_validator
5
6import (
7	"io"
8	"math"
9	"testing"
10
11	grpc_testing "github.com/grpc-ecosystem/go-grpc-middleware/testing"
12	pb_testproto "github.com/grpc-ecosystem/go-grpc-middleware/testing/testproto"
13	"github.com/stretchr/testify/assert"
14	"github.com/stretchr/testify/require"
15	"github.com/stretchr/testify/suite"
16	"google.golang.org/grpc"
17	"google.golang.org/grpc/codes"
18	"google.golang.org/grpc/status"
19)
20
21var (
22	// See test.manual_validator.pb.go for the validator check of SleepTimeMs.
23	goodPing = &pb_testproto.PingRequest{Value: "something", SleepTimeMs: 9999}
24	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}
29)
30
31func 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
39func TestValidatorTestSuite(t *testing.T) {
40	s := &ValidatorTestSuite{
41		InterceptorTestSuite: &grpc_testing.InterceptorTestSuite{
42			ServerOpts: []grpc.ServerOption{
43				grpc.StreamInterceptor(StreamServerInterceptor()),
44				grpc.UnaryInterceptor(UnaryServerInterceptor()),
45			},
46		},
47	}
48	suite.Run(t, s)
49
50	cs := &ClientValidatorTestSuite{
51		InterceptorTestSuite: &grpc_testing.InterceptorTestSuite{
52			ClientOpts: []grpc.DialOption{
53				grpc.WithUnaryInterceptor(UnaryClientInterceptor()),
54			},
55		},
56	}
57	suite.Run(t, cs)
58}
59
60type ValidatorTestSuite struct {
61	*grpc_testing.InterceptorTestSuite
62}
63
64func (s *ValidatorTestSuite) TestValidPasses_Unary() {
65	_, err := s.Client.Ping(s.SimpleCtx(), goodPing)
66	assert.NoError(s.T(), err, "no error expected")
67}
68
69func (s *ValidatorTestSuite) TestInvalidErrors_Unary() {
70	_, err := s.Client.Ping(s.SimpleCtx(), badPing)
71	assert.Error(s.T(), err, "no error expected")
72	assert.Equal(s.T(), codes.InvalidArgument, status.Code(err), "gRPC status must be InvalidArgument")
73}
74
75func (s *ValidatorTestSuite) TestValidPasses_ServerStream() {
76	stream, err := s.Client.PingList(s.SimpleCtx(), goodPing)
77	require.NoError(s.T(), err, "no error on stream establishment expected")
78	for true {
79		_, err := stream.Recv()
80		if err == io.EOF {
81			break
82		}
83		assert.NoError(s.T(), err, "no error on messages sent occured")
84	}
85}
86
87func (s *ValidatorTestSuite) TestInvalidErrors_ServerStream() {
88	stream, err := s.Client.PingList(s.SimpleCtx(), badPing)
89	require.NoError(s.T(), err, "no error on stream establishment expected")
90	_, err = stream.Recv()
91	assert.Error(s.T(), err, "error should be received on first message")
92	assert.Equal(s.T(), codes.InvalidArgument, status.Code(err), "gRPC status must be InvalidArgument")
93}
94
95func (s *ValidatorTestSuite) TestInvalidErrors_BidiStream() {
96	stream, err := s.Client.PingStream(s.SimpleCtx())
97	require.NoError(s.T(), err, "no error on stream establishment expected")
98
99	stream.Send(goodPing)
100	_, err = stream.Recv()
101	assert.NoError(s.T(), err, "receiving a good ping should return a good pong")
102	stream.Send(goodPing)
103	_, err = stream.Recv()
104	assert.NoError(s.T(), err, "receiving a good ping should return a good pong")
105
106	stream.Send(badPing)
107	_, err = stream.Recv()
108	assert.Error(s.T(), err, "receiving a good ping should return a good pong")
109	assert.Equal(s.T(), codes.InvalidArgument, status.Code(err), "gRPC status must be InvalidArgument")
110
111	err = stream.CloseSend()
112	assert.NoError(s.T(), err, "there should be no error closing the stream on send")
113}
114
115type ClientValidatorTestSuite struct {
116	*grpc_testing.InterceptorTestSuite
117}
118
119func (s *ClientValidatorTestSuite) TestValidPasses_Unary() {
120	_, err := s.Client.Ping(s.SimpleCtx(), goodPing)
121	assert.NoError(s.T(), err, "no error expected")
122}
123
124func (s *ClientValidatorTestSuite) TestInvalidErrors_Unary() {
125	_, err := s.Client.Ping(s.SimpleCtx(), badPing)
126	assert.Error(s.T(), err, "error expected")
127	assert.Equal(s.T(), codes.InvalidArgument, status.Code(err), "gRPC status must be InvalidArgument")
128}
129