github.com/lingyao2333/mo-zero@v1.4.1/zrpc/internal/clientinterceptors/tracinginterceptor_test.go (about) 1 package clientinterceptors 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "sync" 8 "sync/atomic" 9 "testing" 10 11 "github.com/lingyao2333/mo-zero/core/trace" 12 "github.com/stretchr/testify/assert" 13 "google.golang.org/grpc" 14 "google.golang.org/grpc/codes" 15 "google.golang.org/grpc/metadata" 16 "google.golang.org/grpc/status" 17 ) 18 19 func TestOpenTracingInterceptor(t *testing.T) { 20 trace.StartAgent(trace.Config{ 21 Name: "go-zero-test", 22 Endpoint: "http://localhost:14268/api/traces", 23 Batcher: "jaeger", 24 Sampler: 1.0, 25 }) 26 defer trace.StopAgent() 27 28 cc := new(grpc.ClientConn) 29 ctx := metadata.NewOutgoingContext(context.Background(), metadata.MD{}) 30 err := UnaryTracingInterceptor(ctx, "/ListUser", nil, nil, cc, 31 func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, 32 opts ...grpc.CallOption) error { 33 return nil 34 }) 35 assert.Nil(t, err) 36 } 37 38 func TestUnaryTracingInterceptor(t *testing.T) { 39 var run int32 40 var wg sync.WaitGroup 41 wg.Add(1) 42 cc := new(grpc.ClientConn) 43 err := UnaryTracingInterceptor(context.Background(), "/foo", nil, nil, cc, 44 func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, 45 opts ...grpc.CallOption) error { 46 defer wg.Done() 47 atomic.AddInt32(&run, 1) 48 return nil 49 }) 50 wg.Wait() 51 assert.Nil(t, err) 52 assert.Equal(t, int32(1), atomic.LoadInt32(&run)) 53 } 54 55 func TestUnaryTracingInterceptor_WithError(t *testing.T) { 56 var run int32 57 var wg sync.WaitGroup 58 wg.Add(1) 59 cc := new(grpc.ClientConn) 60 err := UnaryTracingInterceptor(context.Background(), "/foo", nil, nil, cc, 61 func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, 62 opts ...grpc.CallOption) error { 63 defer wg.Done() 64 atomic.AddInt32(&run, 1) 65 return errors.New("dummy") 66 }) 67 wg.Wait() 68 assert.NotNil(t, err) 69 assert.Equal(t, int32(1), atomic.LoadInt32(&run)) 70 } 71 72 func TestStreamTracingInterceptor(t *testing.T) { 73 var run int32 74 var wg sync.WaitGroup 75 wg.Add(1) 76 cc := new(grpc.ClientConn) 77 _, err := StreamTracingInterceptor(context.Background(), nil, cc, "/foo", 78 func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, 79 opts ...grpc.CallOption) (grpc.ClientStream, error) { 80 defer wg.Done() 81 atomic.AddInt32(&run, 1) 82 return nil, nil 83 }) 84 wg.Wait() 85 assert.Nil(t, err) 86 assert.Equal(t, int32(1), atomic.LoadInt32(&run)) 87 } 88 89 func TestStreamTracingInterceptor_FinishWithNormalError(t *testing.T) { 90 var wg sync.WaitGroup 91 wg.Add(1) 92 cc := new(grpc.ClientConn) 93 ctx, cancel := context.WithCancel(context.Background()) 94 stream, err := StreamTracingInterceptor(ctx, nil, cc, "/foo", 95 func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, 96 opts ...grpc.CallOption) (grpc.ClientStream, error) { 97 defer wg.Done() 98 return nil, nil 99 }) 100 wg.Wait() 101 assert.Nil(t, err) 102 103 cancel() 104 cs := stream.(*clientStream) 105 <-cs.eventsDone 106 } 107 108 func TestStreamTracingInterceptor_FinishWithGrpcError(t *testing.T) { 109 tests := []struct { 110 name string 111 event streamEventType 112 err error 113 }{ 114 { 115 name: "receive event", 116 event: receiveEndEvent, 117 err: status.Error(codes.DataLoss, "dummy"), 118 }, 119 { 120 name: "error event", 121 event: errorEvent, 122 err: status.Error(codes.DataLoss, "dummy"), 123 }, 124 } 125 126 for _, test := range tests { 127 test := test 128 t.Run(test.name, func(t *testing.T) { 129 t.Parallel() 130 131 var wg sync.WaitGroup 132 wg.Add(1) 133 cc := new(grpc.ClientConn) 134 stream, err := StreamTracingInterceptor(context.Background(), nil, cc, "/foo", 135 func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, 136 opts ...grpc.CallOption) (grpc.ClientStream, error) { 137 defer wg.Done() 138 return &mockedClientStream{ 139 err: errors.New("dummy"), 140 }, nil 141 }) 142 wg.Wait() 143 assert.Nil(t, err) 144 145 cs := stream.(*clientStream) 146 cs.sendStreamEvent(test.event, status.Error(codes.DataLoss, "dummy")) 147 <-cs.eventsDone 148 cs.sendStreamEvent(test.event, test.err) 149 assert.NotNil(t, cs.CloseSend()) 150 }) 151 } 152 } 153 154 func TestStreamTracingInterceptor_WithError(t *testing.T) { 155 tests := []struct { 156 name string 157 err error 158 }{ 159 { 160 name: "normal error", 161 err: errors.New("dummy"), 162 }, 163 { 164 name: "grpc error", 165 err: status.Error(codes.DataLoss, "dummy"), 166 }, 167 } 168 169 for _, test := range tests { 170 test := test 171 t.Run(test.name, func(t *testing.T) { 172 t.Parallel() 173 174 var run int32 175 var wg sync.WaitGroup 176 wg.Add(1) 177 cc := new(grpc.ClientConn) 178 _, err := StreamTracingInterceptor(context.Background(), nil, cc, "/foo", 179 func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, 180 opts ...grpc.CallOption) (grpc.ClientStream, error) { 181 defer wg.Done() 182 atomic.AddInt32(&run, 1) 183 return new(mockedClientStream), test.err 184 }) 185 wg.Wait() 186 assert.NotNil(t, err) 187 assert.Equal(t, int32(1), atomic.LoadInt32(&run)) 188 }) 189 } 190 } 191 192 func TestUnaryTracingInterceptor_GrpcFormat(t *testing.T) { 193 var run int32 194 var wg sync.WaitGroup 195 wg.Add(1) 196 cc := new(grpc.ClientConn) 197 err := UnaryTracingInterceptor(context.Background(), "/foo", nil, nil, cc, 198 func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, 199 opts ...grpc.CallOption) error { 200 defer wg.Done() 201 atomic.AddInt32(&run, 1) 202 return nil 203 }) 204 wg.Wait() 205 assert.Nil(t, err) 206 assert.Equal(t, int32(1), atomic.LoadInt32(&run)) 207 } 208 209 func TestStreamTracingInterceptor_GrpcFormat(t *testing.T) { 210 var run int32 211 var wg sync.WaitGroup 212 wg.Add(1) 213 cc := new(grpc.ClientConn) 214 _, err := StreamTracingInterceptor(context.Background(), nil, cc, "/foo", 215 func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, 216 opts ...grpc.CallOption) (grpc.ClientStream, error) { 217 defer wg.Done() 218 atomic.AddInt32(&run, 1) 219 return nil, nil 220 }) 221 wg.Wait() 222 assert.Nil(t, err) 223 assert.Equal(t, int32(1), atomic.LoadInt32(&run)) 224 } 225 226 func TestClientStream_RecvMsg(t *testing.T) { 227 tests := []struct { 228 name string 229 serverStreams bool 230 err error 231 }{ 232 { 233 name: "nil error", 234 }, 235 { 236 name: "EOF", 237 err: io.EOF, 238 }, 239 { 240 name: "dummy error", 241 err: errors.New("dummy"), 242 }, 243 { 244 name: "server streams", 245 serverStreams: true, 246 }, 247 } 248 249 for _, test := range tests { 250 test := test 251 t.Run(test.name, func(t *testing.T) { 252 t.Parallel() 253 desc := new(grpc.StreamDesc) 254 desc.ServerStreams = test.serverStreams 255 stream := wrapClientStream(context.Background(), &mockedClientStream{ 256 md: nil, 257 err: test.err, 258 }, desc) 259 assert.Equal(t, test.err, stream.RecvMsg(nil)) 260 }) 261 } 262 } 263 264 func TestClientStream_Header(t *testing.T) { 265 tests := []struct { 266 name string 267 err error 268 }{ 269 { 270 name: "nil error", 271 }, 272 { 273 name: "with error", 274 err: errors.New("dummy"), 275 }, 276 } 277 278 for _, test := range tests { 279 test := test 280 t.Run(test.name, func(t *testing.T) { 281 t.Parallel() 282 desc := new(grpc.StreamDesc) 283 stream := wrapClientStream(context.Background(), &mockedClientStream{ 284 md: metadata.MD{}, 285 err: test.err, 286 }, desc) 287 _, err := stream.Header() 288 assert.Equal(t, test.err, err) 289 }) 290 } 291 } 292 293 func TestClientStream_SendMsg(t *testing.T) { 294 tests := []struct { 295 name string 296 err error 297 }{ 298 { 299 name: "nil error", 300 }, 301 { 302 name: "with error", 303 err: errors.New("dummy"), 304 }, 305 } 306 307 for _, test := range tests { 308 test := test 309 t.Run(test.name, func(t *testing.T) { 310 t.Parallel() 311 desc := new(grpc.StreamDesc) 312 stream := wrapClientStream(context.Background(), &mockedClientStream{ 313 md: metadata.MD{}, 314 err: test.err, 315 }, desc) 316 assert.Equal(t, test.err, stream.SendMsg(nil)) 317 }) 318 } 319 } 320 321 type mockedClientStream struct { 322 md metadata.MD 323 err error 324 } 325 326 func (m *mockedClientStream) Header() (metadata.MD, error) { 327 return m.md, m.err 328 } 329 330 func (m *mockedClientStream) Trailer() metadata.MD { 331 panic("implement me") 332 } 333 334 func (m *mockedClientStream) CloseSend() error { 335 return m.err 336 } 337 338 func (m *mockedClientStream) Context() context.Context { 339 return context.Background() 340 } 341 342 func (m *mockedClientStream) SendMsg(v interface{}) error { 343 return m.err 344 } 345 346 func (m *mockedClientStream) RecvMsg(v interface{}) error { 347 return m.err 348 }