github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/common/grpclogging/server_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package grpclogging_test 8 9 import ( 10 "context" 11 "crypto/tls" 12 "crypto/x509" 13 "errors" 14 "fmt" 15 "io" 16 "net" 17 "time" 18 19 "github.com/hyperledger/fabric/common/flogging" 20 "github.com/hyperledger/fabric/common/grpclogging" 21 "github.com/hyperledger/fabric/common/grpclogging/fakes" 22 "github.com/hyperledger/fabric/common/grpclogging/testpb" 23 . "github.com/onsi/ginkgo" 24 . "github.com/onsi/gomega" 25 "go.uber.org/zap" 26 "go.uber.org/zap/zapcore" 27 "go.uber.org/zap/zaptest/observer" 28 "google.golang.org/grpc" 29 "google.golang.org/grpc/codes" 30 "google.golang.org/grpc/credentials" 31 "google.golang.org/grpc/status" 32 ) 33 34 const TimeThreshold = 100 * time.Millisecond 35 36 var _ = Describe("Server", func() { 37 var ( 38 fakeEchoService *fakes.EchoServiceServer 39 echoServiceClient testpb.EchoServiceClient 40 41 caCertPool *x509.CertPool 42 clientCertWithKey tls.Certificate 43 44 listener net.Listener 45 serveCompleteCh chan error 46 server *grpc.Server 47 clientConn *grpc.ClientConn 48 49 core zapcore.Core 50 observed *observer.ObservedLogs 51 logger *zap.Logger 52 ) 53 54 BeforeEach(func() { 55 var err error 56 listener, err = net.Listen("tcp", "127.0.0.1:0") 57 Expect(err).NotTo(HaveOccurred()) 58 59 core, observed = observer.New(zap.LevelEnablerFunc(func(zapcore.Level) bool { return true })) 60 logger = zap.New(core, zap.AddCaller()).Named("test-logger") 61 62 caCert, caKey := generateCA("test-ca", "127.0.0.1") 63 clientCert, clientKey := issueCertificate(caCert, caKey, "client", "127.0.0.1") 64 clientCertWithKey, err = tls.X509KeyPair(clientCert, clientKey) 65 Expect(err).NotTo(HaveOccurred()) 66 serverCert, serverKey := issueCertificate(caCert, caKey, "server", "127.0.0.1") 67 serverCertWithKey, err := tls.X509KeyPair(serverCert, serverKey) 68 Expect(err).NotTo(HaveOccurred()) 69 70 caCertPool = x509.NewCertPool() 71 added := caCertPool.AppendCertsFromPEM(caCert) 72 Expect(added).To(BeTrue()) 73 74 fakeEchoService = &fakes.EchoServiceServer{} 75 fakeEchoService.EchoStub = func(ctx context.Context, msg *testpb.Message) (*testpb.Message, error) { 76 msg.Sequence++ 77 return msg, nil 78 } 79 fakeEchoService.EchoStreamStub = func(stream testpb.EchoService_EchoStreamServer) error { 80 msg, err := stream.Recv() 81 if err == io.EOF { 82 return nil 83 } 84 if err != nil { 85 return err 86 } 87 88 msg.Sequence++ 89 return stream.Send(msg) 90 } 91 92 serverTLSConfig := &tls.Config{ 93 Certificates: []tls.Certificate{serverCertWithKey}, 94 ClientAuth: tls.VerifyClientCertIfGiven, 95 ClientCAs: caCertPool, 96 RootCAs: caCertPool, 97 } 98 serverTLSConfig.BuildNameToCertificate() 99 server = grpc.NewServer( 100 grpc.Creds(credentials.NewTLS(serverTLSConfig)), 101 grpc.StreamInterceptor(grpclogging.StreamServerInterceptor(logger)), 102 grpc.UnaryInterceptor(grpclogging.UnaryServerInterceptor(logger)), 103 ) 104 105 testpb.RegisterEchoServiceServer(server, fakeEchoService) 106 serveCompleteCh = make(chan error, 1) 107 go func() { serveCompleteCh <- server.Serve(listener) }() 108 109 clientTLSConfig := &tls.Config{ 110 Certificates: []tls.Certificate{clientCertWithKey}, 111 RootCAs: caCertPool, 112 } 113 clientTLSConfig.BuildNameToCertificate() 114 dialOpts := []grpc.DialOption{ 115 grpc.WithTransportCredentials(credentials.NewTLS(clientTLSConfig)), 116 } 117 clientConn, err = grpc.Dial(listener.Addr().String(), dialOpts...) 118 Expect(err).NotTo(HaveOccurred()) 119 120 echoServiceClient = testpb.NewEchoServiceClient(clientConn) 121 }) 122 123 AfterEach(func() { 124 clientConn.Close() 125 126 err := listener.Close() 127 Expect(err).NotTo(HaveOccurred()) 128 Eventually(serveCompleteCh).Should(Receive()) 129 }) 130 131 Describe("UnaryServerInterceptor", func() { 132 It("logs request data", func() { 133 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 134 defer cancel() 135 136 resp, err := echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"}) 137 Expect(err).NotTo(HaveOccurred()) 138 Expect(resp).To(Equal(&testpb.Message{Message: "hi", Sequence: 1})) 139 140 var logMessages []string 141 for _, entry := range observed.AllUntimed() { 142 logMessages = append(logMessages, entry.Message) 143 } 144 Expect(logMessages).To(ConsistOf( 145 "received unary request", // received payload 146 "sending unary response", // sending payload 147 "unary call completed", 148 )) 149 150 for _, entry := range observed.AllUntimed() { 151 keyNames := map[string]struct{}{} 152 for _, field := range entry.Context { 153 keyNames[field.Key] = struct{}{} 154 } 155 156 switch entry.LoggerName { 157 case "test-logger": 158 Expect(entry.Level).To(Equal(zapcore.InfoLevel)) 159 Expect(entry.Context).To(HaveLen(8)) 160 Expect(keyNames).To(HaveLen(8)) 161 case "test-logger.payload": 162 Expect(entry.Level).To(Equal(zapcore.DebugLevel - 1)) 163 Expect(entry.Context).To(HaveLen(6)) 164 Expect(keyNames).To(HaveLen(6)) 165 default: 166 Fail("unexpected logger name: " + entry.LoggerName) 167 } 168 Expect(entry.Caller.String()).To(ContainSubstring("grpclogging/server.go")) 169 170 for _, field := range entry.Context { 171 switch field.Key { 172 case "grpc.code": 173 Expect(field.Type).To(Equal(zapcore.StringerType)) 174 Expect(field.Interface).To(Equal(codes.OK)) 175 case "grpc.call_duration": 176 Expect(field.Type).To(Equal(zapcore.DurationType)) 177 Expect(field.Integer).NotTo(BeZero()) 178 case "grpc.service": 179 Expect(field.Type).To(Equal(zapcore.StringType)) 180 Expect(field.String).To(Equal("testpb.EchoService")) 181 case "grpc.method": 182 Expect(field.Type).To(Equal(zapcore.StringType)) 183 Expect(field.String).To(Equal("Echo")) 184 case "grpc.request_deadline": 185 deadline, ok := ctx.Deadline() 186 Expect(ok).To(BeTrue()) 187 Expect(field.Type).To(Equal(zapcore.TimeType)) 188 Expect(field.Integer).NotTo(BeZero()) 189 Expect(time.Unix(0, field.Integer)).To(BeTemporally("~", deadline, TimeThreshold)) 190 case "grpc.peer_address": 191 Expect(field.Type).To(Equal(zapcore.StringType)) 192 Expect(field.String).To(HavePrefix("127.0.0.1")) 193 case "grpc.peer_subject": 194 Expect(field.Type).To(Equal(zapcore.StringType)) 195 Expect(field.String).To(HavePrefix("CN=client")) 196 case "message": 197 Expect(field.Type).To(Equal(zapcore.ReflectType)) 198 case "error": 199 Expect(field.Type).To(Equal(zapcore.ErrorType)) 200 case "": 201 Expect(field.Type).To(Equal(zapcore.SkipType)) 202 default: 203 Fail("unexpected context field: " + field.Key) 204 } 205 } 206 } 207 }) 208 209 It("provides a decorated context", func() { 210 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 211 defer cancel() 212 _, err := echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"}) 213 Expect(err).NotTo(HaveOccurred()) 214 215 Expect(fakeEchoService.EchoCallCount()).To(Equal(1)) 216 echoContext, _ := fakeEchoService.EchoArgsForCall(0) 217 zapFields := grpclogging.ZapFields(echoContext) 218 219 keyNames := []string{} 220 for _, field := range zapFields { 221 keyNames = append(keyNames, field.Key) 222 } 223 Expect(keyNames).To(ConsistOf( 224 "grpc.service", 225 "grpc.method", 226 "grpc.request_deadline", 227 "grpc.peer_address", 228 "grpc.peer_subject", 229 )) 230 }) 231 232 Context("when the request ends with an unknown error", func() { 233 var expectedErr error 234 235 BeforeEach(func() { 236 expectedErr = errors.New("gah!") 237 fakeEchoService.EchoReturns(nil, expectedErr) 238 239 _, err := echoServiceClient.Echo(context.Background(), &testpb.Message{Message: "hi"}) 240 Expect(err).To(HaveOccurred()) 241 }) 242 243 It("logs the unknown code", func() { 244 entries := observed.FilterMessage("unary call completed").FilterField(zap.Stringer("grpc.code", codes.Unknown)).AllUntimed() 245 Expect(entries).To(HaveLen(1)) 246 }) 247 248 It("logs the error", func() { 249 entries := observed.FilterMessage("unary call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed() 250 Expect(entries).To(HaveLen(1)) 251 }) 252 }) 253 254 Context("when the request ends with a grpc status error", func() { 255 var expectedErr error 256 257 BeforeEach(func() { 258 expectedErr = &statusError{Status: status.New(codes.Aborted, "aborted")} 259 fakeEchoService.EchoReturns(nil, expectedErr) 260 261 _, err := echoServiceClient.Echo(context.Background(), &testpb.Message{Message: "hi"}) 262 Expect(err).To(HaveOccurred()) 263 }) 264 265 It("logs the corect code", func() { 266 entries := observed.FilterMessage("unary call completed").FilterField(zap.Stringer("grpc.code", codes.Aborted)).AllUntimed() 267 Expect(entries).To(HaveLen(1)) 268 }) 269 270 It("logs the error", func() { 271 entries := observed.FilterMessage("unary call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed() 272 Expect(entries).To(HaveLen(1)) 273 }) 274 }) 275 276 Context("when options are used", func() { 277 var ( 278 listener net.Listener 279 serveCompleteCh chan error 280 server *grpc.Server 281 clientConn *grpc.ClientConn 282 283 leveler *fakes.Leveler 284 payloadLeveler *fakes.Leveler 285 ) 286 287 BeforeEach(func() { 288 var err error 289 listener, err = net.Listen("tcp", "127.0.0.1:0") 290 Expect(err).NotTo(HaveOccurred()) 291 292 leveler = &fakes.Leveler{} 293 leveler.Returns(zapcore.ErrorLevel) 294 payloadLeveler = &fakes.Leveler{} 295 payloadLeveler.Returns(zapcore.WarnLevel) 296 297 server = grpc.NewServer( 298 grpc.UnaryInterceptor(grpclogging.UnaryServerInterceptor( 299 logger, 300 grpclogging.WithLeveler(grpclogging.LevelerFunc(leveler.Spy)), 301 grpclogging.WithPayloadLeveler(grpclogging.LevelerFunc(payloadLeveler.Spy)), 302 )), 303 ) 304 305 testpb.RegisterEchoServiceServer(server, fakeEchoService) 306 serveCompleteCh = make(chan error, 1) 307 go func() { serveCompleteCh <- server.Serve(listener) }() 308 309 clientConn, err = grpc.Dial(listener.Addr().String(), grpc.WithInsecure()) 310 Expect(err).NotTo(HaveOccurred()) 311 echoServiceClient = testpb.NewEchoServiceClient(clientConn) 312 313 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 314 defer cancel() 315 316 _, err = echoServiceClient.Echo(ctx, &testpb.Message{Message: "hi"}) 317 Expect(err).NotTo(HaveOccurred()) 318 }) 319 320 AfterEach(func() { 321 clientConn.Close() 322 323 err := listener.Close() 324 Expect(err).NotTo(HaveOccurred()) 325 Eventually(serveCompleteCh).Should(Receive()) 326 }) 327 328 It("uses the levels returned by the levelers", func() { 329 Eventually(leveler.CallCount).Should(Equal(1)) 330 Eventually(observed.FilterMessage("unary call completed").AllUntimed, 2*time.Second).Should(HaveLen(1)) 331 Expect(observed.FilterMessage("unary call completed").AllUntimed()[0].Level).To(Equal(zapcore.ErrorLevel)) 332 333 Eventually(payloadLeveler.CallCount).Should(Equal(1)) 334 Expect(observed.FilterMessage("received unary request").AllUntimed()).To(HaveLen(1)) 335 Expect(observed.FilterMessage("received unary request").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel)) 336 Expect(observed.FilterMessage("sending unary response").AllUntimed()).To(HaveLen(1)) 337 Expect(observed.FilterMessage("sending unary response").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel)) 338 }) 339 340 It("provides the decorated context and full method name to the levelers", func() { 341 Eventually(leveler.CallCount).Should(Equal(1)) 342 ctx, fullMethod := leveler.ArgsForCall(0) 343 Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty()) 344 Expect(fullMethod).To(Equal("/testpb.EchoService/Echo")) 345 346 Eventually(payloadLeveler.CallCount).Should(Equal(1)) 347 ctx, fullMethod = payloadLeveler.ArgsForCall(0) 348 Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty()) 349 Expect(fullMethod).To(Equal("/testpb.EchoService/Echo")) 350 }) 351 }) 352 }) 353 354 Describe("StreamServerInterceptor", func() { 355 It("logs stream data", func() { 356 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 357 defer cancel() 358 streamClient, err := echoServiceClient.EchoStream(ctx) 359 Expect(err).NotTo(HaveOccurred()) 360 361 err = streamClient.Send(&testpb.Message{Message: "hello"}) 362 Expect(err).NotTo(HaveOccurred()) 363 364 msg, err := streamClient.Recv() 365 Expect(err).NotTo(HaveOccurred()) 366 Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1})) 367 368 err = streamClient.CloseSend() 369 Expect(err).NotTo(HaveOccurred()) 370 371 Eventually(observed.AllUntimed).Should(HaveLen(3)) 372 var logMessages []string 373 for _, entry := range observed.AllUntimed() { 374 logMessages = append(logMessages, entry.Message) 375 } 376 Expect(logMessages).To(ConsistOf( 377 "received stream message", // received payload 378 "sending stream message", // sending payload 379 "streaming call completed", 380 )) 381 382 for _, entry := range observed.AllUntimed() { 383 keyNames := map[string]struct{}{} 384 for _, field := range entry.Context { 385 keyNames[field.Key] = struct{}{} 386 } 387 388 switch entry.LoggerName { 389 case "test-logger": 390 Expect(entry.Level).To(Equal(zapcore.InfoLevel)) 391 Expect(entry.Context).To(HaveLen(8)) 392 Expect(keyNames).To(HaveLen(8)) 393 case "test-logger.payload": 394 Expect(entry.Level).To(Equal(zapcore.DebugLevel - 1)) 395 Expect(entry.Context).To(HaveLen(6)) 396 Expect(keyNames).To(HaveLen(6)) 397 default: 398 Fail("unexpected logger name: " + entry.LoggerName) 399 } 400 Expect(entry.Caller.String()).To(ContainSubstring("grpclogging/server.go")) 401 402 for _, field := range entry.Context { 403 switch field.Key { 404 case "grpc.code": 405 Expect(field.Type).To(Equal(zapcore.StringerType)) 406 Expect(field.Interface).To(Equal(codes.OK)) 407 case "grpc.call_duration": 408 Expect(field.Type).To(Equal(zapcore.DurationType)) 409 Expect(field.Integer).NotTo(BeZero()) 410 case "grpc.service": 411 Expect(field.Type).To(Equal(zapcore.StringType)) 412 Expect(field.String).To(Equal("testpb.EchoService")) 413 case "grpc.method": 414 Expect(field.Type).To(Equal(zapcore.StringType)) 415 Expect(field.String).To(Equal("EchoStream")) 416 case "grpc.request_deadline": 417 deadline, ok := ctx.Deadline() 418 Expect(ok).To(BeTrue()) 419 Expect(field.Type).To(Equal(zapcore.TimeType)) 420 Expect(field.Integer).NotTo(BeZero()) 421 Expect(time.Unix(0, field.Integer)).To(BeTemporally("~", deadline, TimeThreshold)) 422 case "grpc.peer_address": 423 Expect(field.Type).To(Equal(zapcore.StringType)) 424 Expect(field.String).To(HavePrefix("127.0.0.1")) 425 case "grpc.peer_subject": 426 Expect(field.Type).To(Equal(zapcore.StringType)) 427 Expect(field.String).To(HavePrefix("CN=client")) 428 case "message": 429 Expect(field.Type).To(Equal(zapcore.ReflectType)) 430 case "error": 431 Expect(field.Type).To(Equal(zapcore.ErrorType)) 432 case "": 433 Expect(field.Type).To(Equal(zapcore.SkipType)) 434 default: 435 Fail("unexpected context field: " + field.Key) 436 } 437 } 438 } 439 }) 440 441 It("provides a decorated context", func() { 442 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 443 defer cancel() 444 streamClient, err := echoServiceClient.EchoStream(ctx) 445 Expect(err).NotTo(HaveOccurred()) 446 447 err = streamClient.Send(&testpb.Message{Message: "hello"}) 448 Expect(err).NotTo(HaveOccurred()) 449 450 msg, err := streamClient.Recv() 451 Expect(err).NotTo(HaveOccurred()) 452 Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1})) 453 454 err = streamClient.CloseSend() 455 Expect(err).NotTo(HaveOccurred()) 456 457 Expect(fakeEchoService.EchoStreamCallCount()).To(Equal(1)) 458 echoStream := fakeEchoService.EchoStreamArgsForCall(0) 459 zapFields := grpclogging.ZapFields(echoStream.Context()) 460 461 keyNames := []string{} 462 for _, field := range zapFields { 463 keyNames = append(keyNames, field.Key) 464 } 465 Expect(keyNames).To(ConsistOf( 466 "grpc.service", 467 "grpc.method", 468 "grpc.request_deadline", 469 "grpc.peer_address", 470 "grpc.peer_subject", 471 )) 472 }) 473 474 Context("when tls client auth is missing", func() { 475 var clientConn *grpc.ClientConn 476 477 BeforeEach(func() { 478 dialOpts := []grpc.DialOption{ 479 grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(caCertPool, "")), 480 } 481 var err error 482 clientConn, err = grpc.Dial(listener.Addr().String(), dialOpts...) 483 Expect(err).NotTo(HaveOccurred()) 484 485 echoServiceClient = testpb.NewEchoServiceClient(clientConn) 486 }) 487 488 AfterEach(func() { 489 clientConn.Close() 490 }) 491 492 It("omits grpc.peer_subject", func() { 493 streamClient, err := echoServiceClient.EchoStream(context.Background()) 494 Expect(err).NotTo(HaveOccurred()) 495 496 err = streamClient.Send(&testpb.Message{Message: "hello"}) 497 Expect(err).NotTo(HaveOccurred()) 498 499 msg, err := streamClient.Recv() 500 Expect(err).NotTo(HaveOccurred()) 501 Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1})) 502 503 err = streamClient.CloseSend() 504 Expect(err).NotTo(HaveOccurred()) 505 506 for _, entry := range observed.AllUntimed() { 507 keyNames := map[string]struct{}{} 508 for _, field := range entry.Context { 509 keyNames[field.Key] = struct{}{} 510 } 511 Expect(keyNames).NotTo(HaveKey("grpc.peer_subject")) 512 } 513 }) 514 }) 515 516 Context("when the stream ends with an unknown error", func() { 517 var expectedErr error 518 519 BeforeEach(func() { 520 expectedErr = errors.New("gah!") 521 fakeEchoService.EchoStreamStub = func(stream testpb.EchoService_EchoStreamServer) error { 522 stream.Recv() 523 return expectedErr 524 } 525 526 streamClient, err := echoServiceClient.EchoStream(context.Background()) 527 Expect(err).NotTo(HaveOccurred()) 528 529 err = streamClient.Send(&testpb.Message{Message: "hello"}) 530 Expect(err).NotTo(HaveOccurred()) 531 _, err = streamClient.Recv() 532 Expect(err).To(HaveOccurred()) 533 }) 534 535 It("logs the unknown code", func() { 536 entries := observed.FilterMessage("streaming call completed").FilterField(zap.Stringer("grpc.code", codes.Unknown)).AllUntimed() 537 Expect(entries).To(HaveLen(1)) 538 }) 539 540 It("logs the error", func() { 541 entries := observed.FilterMessage("streaming call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed() 542 Expect(entries).To(HaveLen(1)) 543 }) 544 }) 545 546 Context("when the stream ends with a grpc status error", func() { 547 var expectedErr error 548 549 BeforeEach(func() { 550 errCh := make(chan error) 551 fakeEchoService.EchoStreamStub = func(svr testpb.EchoService_EchoStreamServer) error { return <-errCh } 552 553 streamClient, err := echoServiceClient.EchoStream(context.Background()) 554 Expect(err).NotTo(HaveOccurred()) 555 556 err = streamClient.Send(&testpb.Message{Message: "hello"}) 557 Expect(err).NotTo(HaveOccurred()) 558 559 expectedErr = &statusError{Status: status.New(codes.Aborted, "aborted")} 560 errCh <- expectedErr 561 562 _, err = streamClient.Recv() 563 Expect(err).To(HaveOccurred()) 564 }) 565 566 It("logs the corect code", func() { 567 entries := observed.FilterMessage("streaming call completed").FilterField(zap.Stringer("grpc.code", codes.Aborted)).AllUntimed() 568 Expect(entries).To(HaveLen(1)) 569 }) 570 571 It("logs the error", func() { 572 entries := observed.FilterMessage("streaming call completed").FilterField(grpclogging.Error(expectedErr)).AllUntimed() 573 Expect(entries).To(HaveLen(1)) 574 }) 575 }) 576 577 Context("when options are used", func() { 578 var ( 579 listener net.Listener 580 serveCompleteCh chan error 581 server *grpc.Server 582 clientConn *grpc.ClientConn 583 584 leveler *fakes.Leveler 585 payloadLeveler *fakes.Leveler 586 ) 587 588 BeforeEach(func() { 589 var err error 590 listener, err = net.Listen("tcp", "127.0.0.1:0") 591 Expect(err).NotTo(HaveOccurred()) 592 593 leveler = &fakes.Leveler{} 594 leveler.Returns(zapcore.ErrorLevel) 595 payloadLeveler = &fakes.Leveler{} 596 payloadLeveler.Returns(zapcore.WarnLevel) 597 598 server = grpc.NewServer( 599 grpc.StreamInterceptor(grpclogging.StreamServerInterceptor( 600 logger, 601 grpclogging.WithLeveler(grpclogging.LevelerFunc(leveler.Spy)), 602 grpclogging.WithPayloadLeveler(grpclogging.LevelerFunc(payloadLeveler.Spy)), 603 )), 604 ) 605 606 testpb.RegisterEchoServiceServer(server, fakeEchoService) 607 serveCompleteCh = make(chan error, 1) 608 go func() { serveCompleteCh <- server.Serve(listener) }() 609 610 clientConn, err = grpc.Dial(listener.Addr().String(), grpc.WithInsecure()) 611 Expect(err).NotTo(HaveOccurred()) 612 echoServiceClient = testpb.NewEchoServiceClient(clientConn) 613 614 streamClient, err := echoServiceClient.EchoStream(context.Background()) 615 Expect(err).NotTo(HaveOccurred()) 616 err = streamClient.Send(&testpb.Message{Message: "hello"}) 617 Expect(err).NotTo(HaveOccurred()) 618 msg, err := streamClient.Recv() 619 Expect(err).NotTo(HaveOccurred()) 620 Expect(msg).To(Equal(&testpb.Message{Message: "hello", Sequence: 1})) 621 622 err = streamClient.CloseSend() 623 Expect(err).NotTo(HaveOccurred()) 624 }) 625 626 AfterEach(func() { 627 clientConn.Close() 628 629 err := listener.Close() 630 Expect(err).NotTo(HaveOccurred()) 631 Eventually(serveCompleteCh).Should(Receive()) 632 }) 633 634 It("uses the levels returned by the levelers", func() { 635 Eventually(leveler.CallCount).Should(Equal(1)) 636 Eventually(observed.FilterMessage("streaming call completed").AllUntimed, 2*time.Second).Should(HaveLen(1)) 637 Expect(observed.FilterMessage("streaming call completed").AllUntimed()[0].Level).To(Equal(zapcore.ErrorLevel)) 638 639 Eventually(payloadLeveler.CallCount).Should(Equal(1)) 640 Expect(observed.FilterMessage("received stream message").AllUntimed()).To(HaveLen(1)) 641 Expect(observed.FilterMessage("received stream message").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel)) 642 Expect(observed.FilterMessage("sending stream message").AllUntimed()).To(HaveLen(1)) 643 Expect(observed.FilterMessage("sending stream message").AllUntimed()[0].Level).To(Equal(zapcore.WarnLevel)) 644 }) 645 646 It("provides the decorated context and full method name to the levelers", func() { 647 Eventually(leveler.CallCount).Should(Equal(1)) 648 ctx, fullMethod := leveler.ArgsForCall(0) 649 Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty()) 650 Expect(fullMethod).To(Equal("/testpb.EchoService/EchoStream")) 651 652 Eventually(payloadLeveler.CallCount).Should(Equal(1)) 653 ctx, fullMethod = payloadLeveler.ArgsForCall(0) 654 Expect(grpclogging.ZapFields(ctx)).NotTo(BeEmpty()) 655 Expect(fullMethod).To(Equal("/testpb.EchoService/EchoStream")) 656 }) 657 }) 658 }) 659 660 It("uses flogging.PayloadLevel as DefaultPayloadLevel", func() { 661 Expect(grpclogging.DefaultPayloadLevel).To(Equal(flogging.PayloadLevel)) 662 }) 663 }) 664 665 type statusError struct{ *status.Status } 666 667 func (s *statusError) GRPCStatus() *status.Status { return s.Status } 668 669 func (s *statusError) Error() string { 670 return fmt.Sprintf("🎶 I'm a little error, short and sweet. Here is my message: %s. Here is my code: %d.🎶", s.Status.Message(), s.Status.Code()) 671 }