google.golang.org/grpc@v1.72.2/internal/binarylog/method_logger_test.go (about) 1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package binarylog 20 21 import ( 22 "bytes" 23 "context" 24 "fmt" 25 "net" 26 "testing" 27 "time" 28 29 binlogpb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" 30 "google.golang.org/grpc/codes" 31 "google.golang.org/grpc/status" 32 "google.golang.org/protobuf/proto" 33 "google.golang.org/protobuf/types/known/durationpb" 34 ) 35 36 const defaultTestTimeout = 10 * time.Second 37 38 func (s) TestLog(t *testing.T) { 39 idGen.reset() 40 ml := NewTruncatingMethodLogger(10, 10) 41 // Set sink to testing buffer. 42 buf := bytes.NewBuffer(nil) 43 ml.sink = newWriterSink(buf) 44 45 addr := "1.2.3.4" 46 port := 790 47 tcpAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%d", addr, port)) 48 addr6 := "2001:1db8:85a3::8a2e:1370:7334" 49 port6 := 796 50 tcpAddr6, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("[%v]:%d", addr6, port6)) 51 52 testProtoMsg := &binlogpb.Message{ 53 Length: 1, 54 Data: []byte{'a'}, 55 } 56 testProtoBytes, _ := proto.Marshal(testProtoMsg) 57 58 testCases := []struct { 59 config LogEntryConfig 60 want *binlogpb.GrpcLogEntry 61 }{ 62 { 63 config: &ClientHeader{ 64 OnClientSide: false, 65 Header: map[string][]string{ 66 "a": {"b", "bb"}, 67 }, 68 MethodName: "testservice/testmethod", 69 Authority: "test.service.io", 70 Timeout: 2*time.Second + 3*time.Nanosecond, 71 PeerAddr: tcpAddr, 72 }, 73 want: &binlogpb.GrpcLogEntry{ 74 Timestamp: nil, 75 CallId: 1, 76 SequenceIdWithinCall: 0, 77 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, 78 Logger: binlogpb.GrpcLogEntry_LOGGER_SERVER, 79 Payload: &binlogpb.GrpcLogEntry_ClientHeader{ 80 ClientHeader: &binlogpb.ClientHeader{ 81 Metadata: &binlogpb.Metadata{ 82 Entry: []*binlogpb.MetadataEntry{ 83 {Key: "a", Value: []byte{'b'}}, 84 {Key: "a", Value: []byte{'b', 'b'}}, 85 }, 86 }, 87 MethodName: "testservice/testmethod", 88 Authority: "test.service.io", 89 Timeout: &durationpb.Duration{ 90 Seconds: 2, 91 Nanos: 3, 92 }, 93 }, 94 }, 95 PayloadTruncated: false, 96 Peer: &binlogpb.Address{ 97 Type: binlogpb.Address_TYPE_IPV4, 98 Address: addr, 99 IpPort: uint32(port), 100 }, 101 }, 102 }, 103 { 104 config: &ClientHeader{ 105 OnClientSide: false, 106 MethodName: "testservice/testmethod", 107 Authority: "test.service.io", 108 }, 109 want: &binlogpb.GrpcLogEntry{ 110 Timestamp: nil, 111 CallId: 1, 112 SequenceIdWithinCall: 0, 113 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, 114 Logger: binlogpb.GrpcLogEntry_LOGGER_SERVER, 115 Payload: &binlogpb.GrpcLogEntry_ClientHeader{ 116 ClientHeader: &binlogpb.ClientHeader{ 117 Metadata: &binlogpb.Metadata{}, 118 MethodName: "testservice/testmethod", 119 Authority: "test.service.io", 120 }, 121 }, 122 PayloadTruncated: false, 123 }, 124 }, 125 { 126 config: &ServerHeader{ 127 OnClientSide: true, 128 Header: map[string][]string{ 129 "a": {"b", "bb"}, 130 }, 131 PeerAddr: tcpAddr6, 132 }, 133 want: &binlogpb.GrpcLogEntry{ 134 Timestamp: nil, 135 CallId: 1, 136 SequenceIdWithinCall: 0, 137 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, 138 Logger: binlogpb.GrpcLogEntry_LOGGER_CLIENT, 139 Payload: &binlogpb.GrpcLogEntry_ServerHeader{ 140 ServerHeader: &binlogpb.ServerHeader{ 141 Metadata: &binlogpb.Metadata{ 142 Entry: []*binlogpb.MetadataEntry{ 143 {Key: "a", Value: []byte{'b'}}, 144 {Key: "a", Value: []byte{'b', 'b'}}, 145 }, 146 }, 147 }, 148 }, 149 PayloadTruncated: false, 150 Peer: &binlogpb.Address{ 151 Type: binlogpb.Address_TYPE_IPV6, 152 Address: addr6, 153 IpPort: uint32(port6), 154 }, 155 }, 156 }, 157 { 158 config: &ClientMessage{ 159 OnClientSide: true, 160 Message: testProtoMsg, 161 }, 162 want: &binlogpb.GrpcLogEntry{ 163 Timestamp: nil, 164 CallId: 1, 165 SequenceIdWithinCall: 0, 166 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, 167 Logger: binlogpb.GrpcLogEntry_LOGGER_CLIENT, 168 Payload: &binlogpb.GrpcLogEntry_Message{ 169 Message: &binlogpb.Message{ 170 Length: uint32(len(testProtoBytes)), 171 Data: testProtoBytes, 172 }, 173 }, 174 PayloadTruncated: false, 175 Peer: nil, 176 }, 177 }, 178 { 179 config: &ServerMessage{ 180 OnClientSide: false, 181 Message: testProtoMsg, 182 }, 183 want: &binlogpb.GrpcLogEntry{ 184 Timestamp: nil, 185 CallId: 1, 186 SequenceIdWithinCall: 0, 187 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, 188 Logger: binlogpb.GrpcLogEntry_LOGGER_SERVER, 189 Payload: &binlogpb.GrpcLogEntry_Message{ 190 Message: &binlogpb.Message{ 191 Length: uint32(len(testProtoBytes)), 192 Data: testProtoBytes, 193 }, 194 }, 195 PayloadTruncated: false, 196 Peer: nil, 197 }, 198 }, 199 { 200 config: &ClientHalfClose{ 201 OnClientSide: false, 202 }, 203 want: &binlogpb.GrpcLogEntry{ 204 Timestamp: nil, 205 CallId: 1, 206 SequenceIdWithinCall: 0, 207 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, 208 Logger: binlogpb.GrpcLogEntry_LOGGER_SERVER, 209 Payload: nil, 210 PayloadTruncated: false, 211 Peer: nil, 212 }, 213 }, 214 { 215 config: &ServerTrailer{ 216 OnClientSide: true, 217 Err: status.Errorf(codes.Unavailable, "test"), 218 PeerAddr: tcpAddr, 219 }, 220 want: &binlogpb.GrpcLogEntry{ 221 Timestamp: nil, 222 CallId: 1, 223 SequenceIdWithinCall: 0, 224 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, 225 Logger: binlogpb.GrpcLogEntry_LOGGER_CLIENT, 226 Payload: &binlogpb.GrpcLogEntry_Trailer{ 227 Trailer: &binlogpb.Trailer{ 228 Metadata: &binlogpb.Metadata{}, 229 StatusCode: uint32(codes.Unavailable), 230 StatusMessage: "test", 231 StatusDetails: nil, 232 }, 233 }, 234 PayloadTruncated: false, 235 Peer: &binlogpb.Address{ 236 Type: binlogpb.Address_TYPE_IPV4, 237 Address: addr, 238 IpPort: uint32(port), 239 }, 240 }, 241 }, 242 { // Err is nil, Log OK status. 243 config: &ServerTrailer{ 244 OnClientSide: true, 245 }, 246 want: &binlogpb.GrpcLogEntry{ 247 Timestamp: nil, 248 CallId: 1, 249 SequenceIdWithinCall: 0, 250 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, 251 Logger: binlogpb.GrpcLogEntry_LOGGER_CLIENT, 252 Payload: &binlogpb.GrpcLogEntry_Trailer{ 253 Trailer: &binlogpb.Trailer{ 254 Metadata: &binlogpb.Metadata{}, 255 StatusCode: uint32(codes.OK), 256 StatusMessage: "", 257 StatusDetails: nil, 258 }, 259 }, 260 PayloadTruncated: false, 261 Peer: nil, 262 }, 263 }, 264 { 265 config: &Cancel{ 266 OnClientSide: true, 267 }, 268 want: &binlogpb.GrpcLogEntry{ 269 Timestamp: nil, 270 CallId: 1, 271 SequenceIdWithinCall: 0, 272 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CANCEL, 273 Logger: binlogpb.GrpcLogEntry_LOGGER_CLIENT, 274 Payload: nil, 275 PayloadTruncated: false, 276 Peer: nil, 277 }, 278 }, 279 280 // gRPC headers should be omitted. 281 { 282 config: &ClientHeader{ 283 OnClientSide: false, 284 Header: map[string][]string{ 285 "grpc-reserved": {"to be omitted"}, 286 ":authority": {"to be omitted"}, 287 "a": {"b", "bb"}, 288 }, 289 }, 290 want: &binlogpb.GrpcLogEntry{ 291 Timestamp: nil, 292 CallId: 1, 293 SequenceIdWithinCall: 0, 294 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, 295 Logger: binlogpb.GrpcLogEntry_LOGGER_SERVER, 296 Payload: &binlogpb.GrpcLogEntry_ClientHeader{ 297 ClientHeader: &binlogpb.ClientHeader{ 298 Metadata: &binlogpb.Metadata{ 299 Entry: []*binlogpb.MetadataEntry{ 300 {Key: "a", Value: []byte{'b'}}, 301 {Key: "a", Value: []byte{'b', 'b'}}, 302 }, 303 }, 304 }, 305 }, 306 PayloadTruncated: false, 307 }, 308 }, 309 { 310 config: &ServerHeader{ 311 OnClientSide: true, 312 Header: map[string][]string{ 313 "grpc-reserved": {"to be omitted"}, 314 ":authority": {"to be omitted"}, 315 "a": {"b", "bb"}, 316 }, 317 }, 318 want: &binlogpb.GrpcLogEntry{ 319 Timestamp: nil, 320 CallId: 1, 321 SequenceIdWithinCall: 0, 322 Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, 323 Logger: binlogpb.GrpcLogEntry_LOGGER_CLIENT, 324 Payload: &binlogpb.GrpcLogEntry_ServerHeader{ 325 ServerHeader: &binlogpb.ServerHeader{ 326 Metadata: &binlogpb.Metadata{ 327 Entry: []*binlogpb.MetadataEntry{ 328 {Key: "a", Value: []byte{'b'}}, 329 {Key: "a", Value: []byte{'b', 'b'}}, 330 }, 331 }, 332 }, 333 }, 334 PayloadTruncated: false, 335 }, 336 }, 337 } 338 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 339 defer cancel() 340 for i, tc := range testCases { 341 buf.Reset() 342 tc.want.SequenceIdWithinCall = uint64(i + 1) 343 ml.Log(ctx, tc.config) 344 inSink := new(binlogpb.GrpcLogEntry) 345 if err := proto.Unmarshal(buf.Bytes()[4:], inSink); err != nil { 346 t.Errorf("failed to unmarshal bytes in sink to proto: %v", err) 347 continue 348 } 349 inSink.Timestamp = nil // Strip timestamp before comparing. 350 if !proto.Equal(inSink, tc.want) { 351 t.Errorf("Log(%+v), in sink: %+v, want %+v", tc.config, inSink, tc.want) 352 } 353 } 354 } 355 356 func (s) TestTruncateMetadataNotTruncated(t *testing.T) { 357 testCases := []struct { 358 ml *TruncatingMethodLogger 359 mpPb *binlogpb.Metadata 360 }{ 361 { 362 ml: NewTruncatingMethodLogger(maxUInt, maxUInt), 363 mpPb: &binlogpb.Metadata{ 364 Entry: []*binlogpb.MetadataEntry{ 365 {Key: "", Value: []byte{1}}, 366 }, 367 }, 368 }, 369 { 370 ml: NewTruncatingMethodLogger(2, maxUInt), 371 mpPb: &binlogpb.Metadata{ 372 Entry: []*binlogpb.MetadataEntry{ 373 {Key: "", Value: []byte{1}}, 374 }, 375 }, 376 }, 377 { 378 ml: NewTruncatingMethodLogger(1, maxUInt), 379 mpPb: &binlogpb.Metadata{ 380 Entry: []*binlogpb.MetadataEntry{ 381 {Key: "", Value: nil}, 382 }, 383 }, 384 }, 385 { 386 ml: NewTruncatingMethodLogger(2, maxUInt), 387 mpPb: &binlogpb.Metadata{ 388 Entry: []*binlogpb.MetadataEntry{ 389 {Key: "", Value: []byte{1, 1}}, 390 }, 391 }, 392 }, 393 { 394 ml: NewTruncatingMethodLogger(2, maxUInt), 395 mpPb: &binlogpb.Metadata{ 396 Entry: []*binlogpb.MetadataEntry{ 397 {Key: "", Value: []byte{1}}, 398 {Key: "", Value: []byte{1}}, 399 }, 400 }, 401 }, 402 // "grpc-trace-bin" is kept in log but not counted towards the size 403 // limit. 404 { 405 ml: NewTruncatingMethodLogger(1, maxUInt), 406 mpPb: &binlogpb.Metadata{ 407 Entry: []*binlogpb.MetadataEntry{ 408 {Key: "", Value: []byte{1}}, 409 {Key: "grpc-trace-bin", Value: []byte("some.trace.key")}, 410 }, 411 }, 412 }, 413 } 414 415 for i, tc := range testCases { 416 truncated := tc.ml.truncateMetadata(tc.mpPb) 417 if truncated { 418 t.Errorf("test case %v, returned truncated, want not truncated", i) 419 } 420 } 421 } 422 423 func (s) TestTruncateMetadataTruncated(t *testing.T) { 424 testCases := []struct { 425 ml *TruncatingMethodLogger 426 mpPb *binlogpb.Metadata 427 428 entryLen int 429 }{ 430 { 431 ml: NewTruncatingMethodLogger(2, maxUInt), 432 mpPb: &binlogpb.Metadata{ 433 Entry: []*binlogpb.MetadataEntry{ 434 {Key: "", Value: []byte{1, 1, 1}}, 435 }, 436 }, 437 entryLen: 0, 438 }, 439 { 440 ml: NewTruncatingMethodLogger(2, maxUInt), 441 mpPb: &binlogpb.Metadata{ 442 Entry: []*binlogpb.MetadataEntry{ 443 {Key: "", Value: []byte{1}}, 444 {Key: "", Value: []byte{1}}, 445 {Key: "", Value: []byte{1}}, 446 }, 447 }, 448 entryLen: 2, 449 }, 450 { 451 ml: NewTruncatingMethodLogger(2, maxUInt), 452 mpPb: &binlogpb.Metadata{ 453 Entry: []*binlogpb.MetadataEntry{ 454 {Key: "", Value: []byte{1, 1}}, 455 {Key: "", Value: []byte{1}}, 456 }, 457 }, 458 entryLen: 1, 459 }, 460 { 461 ml: NewTruncatingMethodLogger(2, maxUInt), 462 mpPb: &binlogpb.Metadata{ 463 Entry: []*binlogpb.MetadataEntry{ 464 {Key: "", Value: []byte{1}}, 465 {Key: "", Value: []byte{1, 1}}, 466 }, 467 }, 468 entryLen: 1, 469 }, 470 } 471 472 for i, tc := range testCases { 473 truncated := tc.ml.truncateMetadata(tc.mpPb) 474 if !truncated { 475 t.Errorf("test case %v, returned not truncated, want truncated", i) 476 continue 477 } 478 if len(tc.mpPb.Entry) != tc.entryLen { 479 t.Errorf("test case %v, entry length: %v, want: %v", i, len(tc.mpPb.Entry), tc.entryLen) 480 } 481 } 482 } 483 484 func (s) TestTruncateMessageNotTruncated(t *testing.T) { 485 testCases := []struct { 486 ml *TruncatingMethodLogger 487 msgPb *binlogpb.Message 488 }{ 489 { 490 ml: NewTruncatingMethodLogger(maxUInt, maxUInt), 491 msgPb: &binlogpb.Message{ 492 Data: []byte{1}, 493 }, 494 }, 495 { 496 ml: NewTruncatingMethodLogger(maxUInt, 3), 497 msgPb: &binlogpb.Message{ 498 Data: []byte{1, 1}, 499 }, 500 }, 501 { 502 ml: NewTruncatingMethodLogger(maxUInt, 2), 503 msgPb: &binlogpb.Message{ 504 Data: []byte{1, 1}, 505 }, 506 }, 507 } 508 509 for i, tc := range testCases { 510 truncated := tc.ml.truncateMessage(tc.msgPb) 511 if truncated { 512 t.Errorf("test case %v, returned truncated, want not truncated", i) 513 } 514 } 515 } 516 517 func (s) TestTruncateMessageTruncated(t *testing.T) { 518 testCases := []struct { 519 ml *TruncatingMethodLogger 520 msgPb *binlogpb.Message 521 522 oldLength uint32 523 }{ 524 { 525 ml: NewTruncatingMethodLogger(maxUInt, 2), 526 msgPb: &binlogpb.Message{ 527 Length: 3, 528 Data: []byte{1, 1, 1}, 529 }, 530 oldLength: 3, 531 }, 532 } 533 534 for i, tc := range testCases { 535 truncated := tc.ml.truncateMessage(tc.msgPb) 536 if !truncated { 537 t.Errorf("test case %v, returned not truncated, want truncated", i) 538 continue 539 } 540 if len(tc.msgPb.Data) != int(tc.ml.messageMaxLen) { 541 t.Errorf("test case %v, message length: %v, want: %v", i, len(tc.msgPb.Data), tc.ml.messageMaxLen) 542 } 543 if tc.msgPb.Length != tc.oldLength { 544 t.Errorf("test case %v, message.Length field: %v, want: %v", i, tc.msgPb.Length, tc.oldLength) 545 } 546 } 547 }