1 package kit_test
2
3 import (
4 "io"
5 "runtime"
6 "strings"
7 "testing"
8
9 "github.com/go-kit/log"
10 "github.com/go-kit/log/level"
11 grpc_kit "github.com/grpc-ecosystem/go-grpc-middleware/logging/kit"
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 )
19
20 func customClientCodeToLevel(c codes.Code, logger log.Logger) log.Logger {
21 if c == codes.Unauthenticated {
22
23 return level.Error(logger)
24 }
25 return grpc_kit.DefaultClientCodeToLevel(c, logger)
26 }
27
28 func TestKitClientSuite(t *testing.T) {
29 opts := []grpc_kit.Option{
30 grpc_kit.WithLevels(customClientCodeToLevel),
31 }
32 b := newKitBaseSuite(t)
33 b.logger = level.NewFilter(b.logger, level.AllowDebug())
34 b.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
35 grpc.WithUnaryInterceptor(grpc_kit.UnaryClientInterceptor(b.logger, opts...)),
36 grpc.WithStreamInterceptor(grpc_kit.StreamClientInterceptor(b.logger, opts...)),
37 }
38 suite.Run(t, &kitClientSuite{b})
39 }
40
41 type kitClientSuite struct {
42 *kitBaseSuite
43 }
44
45 func (s *kitClientSuite) TestPing() {
46 _, err := s.Client.Ping(s.SimpleCtx(), goodPing)
47 assert.NoError(s.T(), err, "there must be not be an on a successful call")
48
49 msgs := s.getOutputJSONs()
50 require.Len(s.T(), msgs, 1, "one log statement should be logged")
51
52 assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
53 assert.Equal(s.T(), msgs[0]["grpc.method"], "Ping", "all lines must contain the correct method name")
54 assert.Equal(s.T(), msgs[0]["msg"], "finished client unary call", "handler's message must contain the correct message")
55 assert.Equal(s.T(), msgs[0]["span.kind"], "client", "all lines must contain the kind of call (client)")
56 assert.Equal(s.T(), msgs[0]["level"], "debug", "OK codes must be logged on debug level.")
57
58 assert.Contains(s.T(), msgs[0], "grpc.time_ms", "interceptor log statement should contain execution time (duration in ms)")
59 }
60
61 func (s *kitClientSuite) TestPingList() {
62 stream, err := s.Client.PingList(s.SimpleCtx(), goodPing)
63 require.NoError(s.T(), err, "should not fail on establishing the stream")
64 for {
65 _, err := stream.Recv()
66 if err == io.EOF {
67 break
68 }
69 require.NoError(s.T(), err, "reading stream should not fail")
70 }
71
72 msgs := s.getOutputJSONs()
73 require.Len(s.T(), msgs, 1, "one log statement should be logged")
74
75 assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
76 assert.Equal(s.T(), msgs[0]["grpc.method"], "PingList", "all lines must contain the correct method name")
77 assert.Equal(s.T(), msgs[0]["msg"], "finished client streaming call", "handler's message must contain the correct message")
78 assert.Equal(s.T(), msgs[0]["span.kind"], "client", "all lines must contain the kind of call (client)")
79 assert.Equal(s.T(), msgs[0]["level"], "debug", "OK codes must be logged on debug level.")
80 assert.Contains(s.T(), msgs[0], "grpc.time_ms", "interceptor log statement should contain execution time (duration in ms)")
81 }
82
83 func (s *kitClientSuite) TestPingError_WithCustomLevels() {
84 for _, tcase := range []struct {
85 code codes.Code
86 level level.Value
87 msg string
88 }{
89 {
90 code: codes.Internal,
91 level: level.WarnValue(),
92 msg: "Internal must remap to WarnLevel in DefaultClientCodeToLevel",
93 },
94 {
95 code: codes.NotFound,
96 level: level.DebugValue(),
97 msg: "NotFound must remap to DebugLevel in DefaultClientCodeToLevel",
98 },
99 {
100 code: codes.FailedPrecondition,
101 level: level.DebugValue(),
102 msg: "FailedPrecondition must remap to DebugLevel in DefaultClientCodeToLevel",
103 },
104 {
105 code: codes.Unauthenticated,
106 level: level.ErrorValue(),
107 msg: "Unauthenticated is overwritten to ErrorLevel with customClientCodeToLevel override, which probably didn't work",
108 },
109 } {
110 s.SetupTest()
111 _, err := s.Client.PingError(
112 s.SimpleCtx(),
113 &pb_testproto.PingRequest{Value: "something", ErrorCodeReturned: uint32(tcase.code)})
114
115 assert.Error(s.T(), err, "each call here must return an error")
116
117 msgs := s.getOutputJSONs()
118 require.Len(s.T(), msgs, 1, "only a single log message is printed")
119
120 assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
121 assert.Equal(s.T(), msgs[0]["grpc.method"], "PingError", "all lines must contain the correct method name")
122 assert.Equal(s.T(), msgs[0]["grpc.code"], tcase.code.String(), "all lines must contain a grpc code")
123 assert.Equal(s.T(), msgs[0]["level"], tcase.level.String(), tcase.msg)
124 }
125 }
126
127 func TestKitClientOverrideSuite(t *testing.T) {
128 if strings.HasPrefix(runtime.Version(), "go1.7") {
129 t.Skip("Skipping due to json.RawMessage incompatibility with go1.7")
130 return
131 }
132 opts := []grpc_kit.Option{
133 grpc_kit.WithDurationField(grpc_kit.DurationToDurationField),
134 }
135 b := newKitBaseSuite(t)
136 b.logger = level.NewFilter(b.logger, level.AllowDebug())
137 b.InterceptorTestSuite.ClientOpts = []grpc.DialOption{
138 grpc.WithUnaryInterceptor(grpc_kit.UnaryClientInterceptor(b.logger, opts...)),
139 grpc.WithStreamInterceptor(grpc_kit.StreamClientInterceptor(b.logger, opts...)),
140 }
141 suite.Run(t, &kitClientOverrideSuite{b})
142 }
143
144 type kitClientOverrideSuite struct {
145 *kitBaseSuite
146 }
147
148 func (s *kitClientOverrideSuite) TestPing_HasOverrides() {
149 _, err := s.Client.Ping(s.SimpleCtx(), goodPing)
150 assert.NoError(s.T(), err, "there must be not be an on a successful call")
151
152 msgs := s.getOutputJSONs()
153 require.Len(s.T(), msgs, 1, "one log statement should be logged")
154 assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
155 assert.Equal(s.T(), msgs[0]["grpc.method"], "Ping", "all lines must contain the correct method name")
156 assert.Equal(s.T(), msgs[0]["msg"], "finished client unary call", "handler's message must contain the correct message")
157
158 assert.NotContains(s.T(), msgs[0], "grpc.time_ms", "message must not contain default duration")
159 assert.Contains(s.T(), msgs[0], "grpc.duration", "message must contain overridden duration")
160 }
161
162 func (s *kitClientOverrideSuite) TestPingList_HasOverrides() {
163 stream, err := s.Client.PingList(s.SimpleCtx(), goodPing)
164 require.NoError(s.T(), err, "should not fail on establishing the stream")
165 for {
166 _, err := stream.Recv()
167 if err == io.EOF {
168 break
169 }
170 require.NoError(s.T(), err, "reading stream should not fail")
171 }
172
173 msgs := s.getOutputJSONs()
174 require.Len(s.T(), msgs, 1, "one log statement should be logged")
175
176 assert.Equal(s.T(), msgs[0]["grpc.service"], "mwitkow.testproto.TestService", "all lines must contain the correct service name")
177 assert.Equal(s.T(), msgs[0]["grpc.method"], "PingList", "all lines must contain the correct method name")
178 assert.Equal(s.T(), msgs[0]["msg"], "finished client streaming call", "log message must be correct")
179 assert.Equal(s.T(), msgs[0]["span.kind"], "client", "all lines must contain the kind of call (client)")
180 assert.Equal(s.T(), msgs[0]["level"], "debug", "OK codes must be logged on debug level.")
181
182 assert.NotContains(s.T(), msgs[0], "grpc.time_ms", "message must not contain default duration")
183 assert.Contains(s.T(), msgs[0], "grpc.duration", "message must contain overridden duration")
184 }
185
View as plain text