github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/p2p/server_test.go (about) 1 // Copyright 2021 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package p2p 15 16 import ( 17 "context" 18 "encoding/json" 19 "fmt" 20 "math" 21 "net" 22 "strings" 23 "sync" 24 "sync/atomic" 25 "testing" 26 "time" 27 28 "github.com/phayes/freeport" 29 "github.com/pingcap/tiflow/proto/p2p" 30 "github.com/stretchr/testify/require" 31 "google.golang.org/grpc" 32 ) 33 34 const ( 35 defaultTimeout = time.Second * 10 36 defaultMessageBatchSizeSmall = 128 37 defaultMessageBatchSizeMedium = 512 38 defaultMessageBatchSizeLarge = 1024 39 defaultMultiClientCount = 16 40 ) 41 42 // read only 43 var defaultServerConfig4Testing = &MessageServerConfig{ 44 MaxPendingMessageCountPerTopic: 256, 45 MaxPendingTaskCount: 102400, 46 SendChannelSize: 16, 47 SendRateLimitPerStream: 1024, 48 AckInterval: time.Millisecond * 200, 49 WorkerPoolSize: 4, 50 MaxPeerCount: 1024, 51 WaitUnregisterHandleTimeoutThreshold: time.Millisecond * 100, 52 } 53 54 func newServerForTesting(t *testing.T, serverID string) (server *MessageServer, newClient func() (p2p.CDCPeerToPeerClient, func()), cancel func()) { 55 port := freeport.GetPort() 56 addr := fmt.Sprintf("127.0.0.1:%d", port) 57 lis, err := net.Listen("tcp", addr) 58 require.NoError(t, err) 59 60 var opts []grpc.ServerOption 61 grpcServer := grpc.NewServer(opts...) 62 63 config := *defaultServerConfig4Testing 64 server = NewMessageServer(serverID, &config) 65 p2p.RegisterCDCPeerToPeerServer(grpcServer, server) 66 67 var wg sync.WaitGroup 68 wg.Add(1) 69 go func() { 70 defer wg.Done() 71 _ = grpcServer.Serve(lis) 72 }() 73 74 cancel = func() { 75 grpcServer.Stop() 76 wg.Wait() 77 } 78 79 newClient = func() (p2p.CDCPeerToPeerClient, func()) { 80 conn, err := grpc.Dial( 81 addr, 82 grpc.WithInsecure(), 83 grpc.WithContextDialer(func(_ context.Context, s string) (net.Conn, error) { 84 return net.Dial("tcp", addr) 85 })) 86 require.NoError(t, err) 87 88 cancel := func() { 89 _ = conn.Close() 90 } 91 return p2p.NewCDCPeerToPeerClient(conn), cancel 92 } 93 return 94 } 95 96 func mustAddHandler(ctx context.Context, t *testing.T, server *MessageServer, topic string, tpi interface{}, f func(string, interface{}) error) <-chan error { 97 doneCh, errCh, err := server.AddHandler(ctx, topic, tpi, f) 98 require.NoError(t, err) 99 100 select { 101 case <-ctx.Done(): 102 t.Fatalf("AddHandler timed out") 103 case <-doneCh: 104 } 105 106 return errCh 107 } 108 109 type testTopicContent struct { 110 Index int64 111 } 112 113 func TestServerMultiClientSingleTopic(t *testing.T) { 114 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 115 defer cancel() 116 117 serverID := "test-server-1" 118 server, newClient, closer := newServerForTesting(t, serverID) 119 defer closer() 120 121 // Avoids server returning error due to congested topic. 122 server.config.MaxPendingMessageCountPerTopic = math.MaxInt64 123 124 localCh := make(chan RawMessageEntry, defaultMessageBatchSizeMedium) 125 var wg sync.WaitGroup 126 wg.Add(1) 127 go func() { 128 defer wg.Done() 129 err := server.Run(ctx, localCh) 130 require.Regexp(t, ".*context canceled.*", err) 131 }() 132 133 var ackWg sync.WaitGroup 134 for i := 0; i < defaultMultiClientCount; i++ { 135 wg.Add(1) 136 ackWg.Add(1) 137 i := i 138 go func() { 139 defer wg.Done() 140 client, closeClient := newClient() 141 stream, err := client.SendMessage(ctx) 142 require.NoError(t, err) 143 144 err = stream.Send(&p2p.MessagePacket{ 145 Meta: &p2p.StreamMeta{ 146 SenderId: fmt.Sprintf("test-client-%d", i), 147 ReceiverId: serverID, 148 Epoch: 0, 149 }, 150 }) 151 require.NoError(t, err) 152 153 go func() { 154 defer closeClient() 155 defer ackWg.Done() 156 var lastAck int64 157 for { 158 resp, err := stream.Recv() 159 require.NoError(t, err) 160 require.Equal(t, p2p.ExitReason_OK, resp.ExitReason) 161 162 acks := resp.Ack 163 require.Len(t, acks, 1) 164 require.Equal(t, "test-topic-1", acks[0].Topic) 165 require.GreaterOrEqual(t, acks[0].LastSeq, lastAck) 166 lastAck = acks[0].LastSeq 167 if lastAck == defaultMessageBatchSizeMedium { 168 return 169 } 170 } 171 }() 172 173 for j := 0; j < defaultMessageBatchSizeMedium; j++ { 174 content := &testTopicContent{Index: int64(j + 1)} 175 bytes, err := json.Marshal(content) 176 require.NoError(t, err) 177 178 err = stream.Send(&p2p.MessagePacket{ 179 Entries: []*p2p.MessageEntry{ 180 { 181 Topic: "test-topic-1", 182 Content: bytes, 183 Sequence: int64(j + 1), 184 }, 185 }, 186 }) 187 require.NoError(t, err) 188 } 189 }() 190 } 191 192 time.Sleep(1 * time.Second) 193 194 lastIndices := sync.Map{} 195 errCh := mustAddHandler(ctx, t, server, "test-topic-1", &testTopicContent{}, func(senderID string, i interface{}) error { 196 if strings.Contains(senderID, "server") { 197 require.Equal(t, serverID, senderID) 198 } else { 199 require.Regexp(t, "test-client-.*", senderID) 200 } 201 require.IsType(t, &testTopicContent{}, i) 202 content := i.(*testTopicContent) 203 204 v, ok := lastIndices.Load(senderID) 205 if !ok { 206 require.Equal(t, int64(1), content.Index) 207 } else { 208 require.Equal(t, content.Index-1, v.(int64)) 209 } 210 lastIndices.Store(senderID, content.Index) 211 return nil 212 }) 213 214 // test local client 215 wg.Add(1) 216 ackWg.Add(1) 217 go func() { 218 defer wg.Done() 219 for j := 0; j < defaultMessageBatchSizeLarge; j++ { 220 content := &testTopicContent{Index: int64(j + 1)} 221 select { 222 case <-ctx.Done(): 223 t.Fail() 224 case localCh <- RawMessageEntry{ 225 topic: "test-topic-1", 226 value: content, 227 }: 228 } 229 } 230 go func() { 231 defer ackWg.Done() 232 ticker := time.NewTicker(100 * time.Millisecond) 233 defer ticker.Stop() 234 for { 235 select { 236 case <-ctx.Done(): 237 t.Fail() 238 case <-ticker.C: 239 v, ok := lastIndices.Load(serverID) 240 if !ok { 241 continue 242 } 243 idx := v.(int64) 244 if idx == defaultMessageBatchSizeLarge { 245 return 246 } 247 } 248 } 249 }() 250 }() 251 252 wg.Add(1) 253 go func() { 254 defer wg.Done() 255 select { 256 case <-ctx.Done(): 257 case err := <-errCh: 258 require.Error(t, err) 259 require.Regexp(t, ".*ErrWorkerPoolHandleCancelled.*", err.Error()) 260 } 261 }() 262 263 ackWg.Wait() 264 265 err := server.SyncRemoveHandler(ctx, "test-topic-1") 266 require.NoError(t, err) 267 268 // double remove to test idempotency. 269 err = server.SyncRemoveHandler(ctx, "test-topic-1") 270 require.NoError(t, err) 271 272 closer() 273 cancel() 274 275 wg.Wait() 276 } 277 278 func TestServerDeregisterHandler(t *testing.T) { 279 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 280 defer cancel() 281 282 server, newClient, closer := newServerForTesting(t, "test-server-1") 283 defer closer() 284 285 var wg sync.WaitGroup 286 wg.Add(1) 287 go func() { 288 defer wg.Done() 289 err := server.Run(ctx, nil) 290 require.Regexp(t, ".*context canceled.*", err.Error()) 291 }() 292 293 var ( 294 lastIndex int64 295 removed int32 296 ) 297 errCh := mustAddHandler(ctx, t, server, "test-topic-1", &testTopicContent{}, func(senderID string, i interface{}) error { 298 require.Equal(t, int32(0), atomic.LoadInt32(&removed)) 299 require.Equal(t, "test-client-1", senderID) 300 require.IsType(t, &testTopicContent{}, i) 301 content := i.(*testTopicContent) 302 swapped := atomic.CompareAndSwapInt64(&lastIndex, content.Index-1, content.Index) 303 require.True(t, swapped) 304 return nil 305 }) 306 307 wg.Add(1) 308 go func() { 309 defer wg.Done() 310 select { 311 case <-ctx.Done(): 312 case err := <-errCh: 313 require.Regexp(t, ".*ErrWorkerPoolHandleCancelled.*", err.Error()) 314 } 315 }() 316 317 client, closeClient := newClient() 318 defer closeClient() 319 320 stream, err := client.SendMessage(ctx) 321 require.NoError(t, err) 322 323 err = stream.Send(&p2p.MessagePacket{ 324 Meta: &p2p.StreamMeta{ 325 SenderId: "test-client-1", 326 ReceiverId: "test-server-1", 327 Epoch: 0, 328 }, 329 }) 330 require.NoError(t, err) 331 332 removeHandler := func() { 333 wg.Add(1) 334 go func() { 335 defer wg.Done() 336 doneCh, err := server.RemoveHandler(ctx, "test-topic-1") 337 require.NoError(t, err) 338 select { 339 case <-ctx.Done(): 340 require.FailNow(t, "RemoveHandler timed out") 341 case <-doneCh: 342 } 343 atomic.StoreInt32(&removed, 1) 344 }() 345 } 346 347 wg.Add(1) 348 go func() { 349 defer wg.Done() 350 defer cancel() 351 defer closer() 352 var lastAck int64 353 for { 354 resp, err := stream.Recv() 355 require.NoError(t, err) 356 require.Equal(t, p2p.ExitReason_OK, resp.ExitReason) 357 acks := resp.Ack 358 require.Len(t, acks, 1) 359 require.Equal(t, "test-topic-1", acks[0].Topic) 360 require.GreaterOrEqual(t, acks[0].LastSeq, lastAck) 361 lastAck = acks[0].LastSeq 362 if lastAck >= defaultMessageBatchSizeSmall/3 { 363 removeHandler() 364 time.Sleep(time.Millisecond * 500) 365 require.Equal(t, int32(1), atomic.LoadInt32(&removed)) 366 time.Sleep(time.Millisecond * 500) 367 return 368 } 369 } 370 }() 371 372 for i := 0; i < defaultMessageBatchSizeSmall; i++ { 373 content := &testTopicContent{Index: int64(i + 1)} 374 bytes, err := json.Marshal(content) 375 require.NoError(t, err) 376 377 err = stream.Send(&p2p.MessagePacket{ 378 Entries: []*p2p.MessageEntry{ 379 { 380 Topic: "test-topic-1", 381 Content: bytes, 382 Sequence: int64(i + 1), 383 }, 384 }, 385 }) 386 require.NoError(t, err) 387 } 388 389 wg.Wait() 390 } 391 392 func TestServerClosed(t *testing.T) { 393 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 394 defer cancel() 395 396 server, newClient, closer := newServerForTesting(t, "test-server-1") 397 defer closer() 398 399 cctx, cancelServer := context.WithCancel(ctx) 400 var wg sync.WaitGroup 401 wg.Add(1) 402 go func() { 403 defer wg.Done() 404 err := server.Run(cctx, nil) 405 require.Regexp(t, ".*context canceled.*", err.Error()) 406 }() 407 408 client, closeClient := newClient() 409 defer closeClient() 410 411 stream, err := client.SendMessage(ctx) 412 require.NoError(t, err) 413 414 err = stream.Send(&p2p.MessagePacket{ 415 Meta: &p2p.StreamMeta{ 416 SenderId: "test-client-1", 417 ReceiverId: "test-server-1", 418 Epoch: 0, 419 }, 420 }) 421 require.NoError(t, err) 422 423 cancelServer() 424 425 var clientErr error 426 require.Eventually(t, func() bool { 427 _, clientErr = stream.Recv() 428 return clientErr != nil 429 }, time.Second*1, time.Millisecond*10) 430 require.Regexp(t, ".*message server is closing.*", clientErr.Error()) 431 432 wg.Wait() 433 } 434 435 func TestServerTopicCongestedDueToNoHandler(t *testing.T) { 436 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 437 defer cancel() 438 439 server, newClient, closer := newServerForTesting(t, "test-server-1") 440 defer closer() 441 442 var wg sync.WaitGroup 443 wg.Add(1) 444 go func() { 445 defer wg.Done() 446 err := server.Run(ctx, nil) 447 require.Regexp(t, ".*context canceled.*", err.Error()) 448 }() 449 450 client, closeClient := newClient() 451 defer closeClient() 452 453 stream, err := client.SendMessage(ctx) 454 require.NoError(t, err) 455 456 err = stream.Send(&p2p.MessagePacket{ 457 Meta: &p2p.StreamMeta{ 458 SenderId: "test-client-1", 459 ReceiverId: "test-server-1", 460 Epoch: 0, 461 }, 462 }) 463 require.NoError(t, err) 464 465 wg.Add(1) 466 go func() { 467 defer wg.Done() 468 for { 469 resp, err := stream.Recv() 470 require.NoError(t, err) 471 if resp.ExitReason == p2p.ExitReason_OK { 472 continue 473 } 474 require.Equal(t, p2p.ExitReason_CONGESTED, resp.ExitReason) 475 cancel() 476 return 477 } 478 }() 479 480 for i := 0; i < defaultMessageBatchSizeMedium; i++ { 481 content := &testTopicContent{Index: int64(i + 1)} 482 bytes, err := json.Marshal(content) 483 require.NoError(t, err) 484 485 err = stream.Send(&p2p.MessagePacket{ 486 Entries: []*p2p.MessageEntry{ 487 { 488 Topic: "test-topic-1", 489 Content: bytes, 490 Sequence: int64(i + 1), 491 }, 492 }, 493 }) 494 if err != nil { 495 require.Regexp(t, "EOF", err.Error()) 496 return 497 } 498 } 499 500 wg.Wait() 501 } 502 503 func TestServerIncomingConnectionStale(t *testing.T) { 504 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 505 defer cancel() 506 507 server, newClient, closer := newServerForTesting(t, "test-server-1") 508 defer closer() 509 510 var wg sync.WaitGroup 511 wg.Add(1) 512 go func() { 513 defer wg.Done() 514 err := server.Run(ctx, nil) 515 require.Regexp(t, ".*context canceled.*", err.Error()) 516 }() 517 518 client, closeClient := newClient() 519 defer closeClient() 520 521 streamCtx, cancelStream := context.WithCancel(ctx) 522 defer cancelStream() 523 stream, err := client.SendMessage(streamCtx) 524 require.NoError(t, err) 525 526 err = stream.Send(&p2p.MessagePacket{ 527 Meta: &p2p.StreamMeta{ 528 SenderId: "test-client-1", 529 ReceiverId: "test-server-1", 530 Epoch: 5, // a larger epoch 531 }, 532 }) 533 require.NoError(t, err) 534 _ = stream.CloseSend() 535 536 require.Eventually(t, func() bool { 537 server.peerLock.RLock() 538 defer server.peerLock.RUnlock() 539 _, ok := server.peers["test-client-1"] 540 return ok 541 }, time.Millisecond*100, time.Millisecond*10) 542 543 stream, err = client.SendMessage(ctx) 544 require.NoError(t, err) 545 546 err = stream.Send(&p2p.MessagePacket{ 547 Meta: &p2p.StreamMeta{ 548 SenderId: "test-client-1", 549 ReceiverId: "test-server-1", 550 Epoch: 4, // a smaller epoch 551 }, 552 }) 553 require.NoError(t, err) 554 555 for { 556 resp, err := stream.Recv() 557 require.NoError(t, err) 558 if resp.ExitReason == p2p.ExitReason_OK { 559 continue 560 } 561 require.Equal(t, resp.ExitReason, p2p.ExitReason_STALE_CONNECTION) 562 break 563 } 564 565 cancel() 566 wg.Wait() 567 } 568 569 func TestServerOldConnectionStale(t *testing.T) { 570 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 571 defer cancel() 572 573 server, newClient, closer := newServerForTesting(t, "test-server-1") 574 defer closer() 575 576 var wg sync.WaitGroup 577 wg.Add(1) 578 go func() { 579 defer wg.Done() 580 err := server.Run(ctx, nil) 581 require.Regexp(t, ".*context canceled.*", err.Error()) 582 }() 583 584 client, closeClient := newClient() 585 defer closeClient() 586 587 streamCtx, cancelStream := context.WithCancel(ctx) 588 defer cancelStream() 589 stream, err := client.SendMessage(streamCtx) 590 require.NoError(t, err) 591 592 err = stream.Send(&p2p.MessagePacket{ 593 Meta: &p2p.StreamMeta{ 594 SenderId: "test-client-1", 595 ReceiverId: "test-server-1", 596 Epoch: 4, // a smaller epoch 597 }, 598 }) 599 require.NoError(t, err) 600 601 require.Eventually(t, func() bool { 602 server.peerLock.RLock() 603 defer server.peerLock.RUnlock() 604 _, ok := server.peers["test-client-1"] 605 return ok 606 }, time.Millisecond*100, time.Millisecond*10) 607 608 stream1, err := client.SendMessage(ctx) 609 require.NoError(t, err) 610 611 err = stream1.Send(&p2p.MessagePacket{ 612 Meta: &p2p.StreamMeta{ 613 SenderId: "test-client-1", 614 ReceiverId: "test-server-1", 615 Epoch: 5, // a larger epoch 616 }, 617 }) 618 require.NoError(t, err) 619 620 for { 621 resp, err := stream.Recv() 622 require.NoError(t, err) 623 if resp.ExitReason == p2p.ExitReason_OK { 624 continue 625 } 626 require.Equal(t, resp.ExitReason, p2p.ExitReason_STALE_CONNECTION) 627 break 628 } 629 630 cancel() 631 wg.Wait() 632 } 633 634 func TestServerRepeatedMessages(t *testing.T) { 635 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 636 defer cancel() 637 638 server, newClient, closer := newServerForTesting(t, "test-server-1") 639 defer closer() 640 641 var wg sync.WaitGroup 642 wg.Add(1) 643 go func() { 644 defer wg.Done() 645 err := server.Run(ctx, nil) 646 require.Regexp(t, ".*context canceled.*", err.Error()) 647 }() 648 649 var lastIndex int64 650 _ = mustAddHandler(ctx, t, server, "test-topic-1", 651 &testTopicContent{}, func(senderID string, i interface{}) error { 652 require.Equal(t, "test-client-1", senderID) 653 require.IsType(t, &testTopicContent{}, i) 654 content := i.(*testTopicContent) 655 require.Equal(t, content.Index-1, atomic.LoadInt64(&lastIndex)) 656 atomic.StoreInt64(&lastIndex, content.Index) 657 return nil 658 }) 659 660 client, closeClient := newClient() 661 defer closeClient() 662 663 stream, err := client.SendMessage(ctx) 664 require.NoError(t, err) 665 666 err = stream.Send(&p2p.MessagePacket{ 667 Meta: &p2p.StreamMeta{ 668 SenderId: "test-client-1", 669 ReceiverId: "test-server-1", 670 Epoch: 0, 671 }, 672 }) 673 require.NoError(t, err) 674 675 wg.Add(1) 676 go func() { 677 defer wg.Done() 678 defer cancel() 679 for { 680 resp, err := stream.Recv() 681 require.NoError(t, err) 682 require.Equal( 683 t, 684 p2p.ExitReason_OK, 685 resp.ExitReason, 686 "unexpected error: %s", 687 resp.ErrorMessage, 688 ) 689 if resp.Ack[0].LastSeq == defaultMessageBatchSizeSmall { 690 return 691 } 692 } 693 }() 694 695 for i := 0; i < defaultMessageBatchSizeSmall; i++ { 696 content := &testTopicContent{Index: int64(i + 1)} 697 bytes, err := json.Marshal(content) 698 require.NoError(t, err) 699 700 err = stream.Send(&p2p.MessagePacket{ 701 Entries: []*p2p.MessageEntry{ 702 { 703 Topic: "test-topic-1", 704 Content: bytes, 705 Sequence: int64(i + 1), 706 }, 707 }, 708 }) 709 if err != nil { 710 require.Regexp(t, "EOF", err.Error()) 711 return 712 } 713 714 err = stream.Send(&p2p.MessagePacket{ 715 Entries: []*p2p.MessageEntry{ 716 { 717 Topic: "test-topic-1", 718 Content: bytes, 719 Sequence: int64(i + 1), 720 }, 721 }, 722 }) 723 if err != nil { 724 require.Regexp(t, "EOF", err.Error()) 725 return 726 } 727 } 728 729 wg.Wait() 730 } 731 732 func TestServerExitWhileAddingHandler(t *testing.T) { 733 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 734 defer cancel() 735 736 server, _, closer := newServerForTesting(t, "test-server-1") 737 defer closer() 738 739 serverCtx, cancelServer := context.WithCancel(ctx) 740 defer cancelServer() 741 742 var wg sync.WaitGroup 743 wg.Add(1) 744 go func() { 745 defer wg.Done() 746 err := server.Run(serverCtx, nil) 747 require.Regexp(t, ".*context canceled.*", err.Error()) 748 }() 749 750 waitCh := make(chan struct{}) 751 752 wg.Add(1) 753 go func() { 754 defer wg.Done() 755 err := server.scheduleTask(ctx, taskDebugDelay{ 756 doneCh: waitCh, 757 }) 758 require.NoError(t, err) 759 }() 760 761 wg.Add(1) 762 go func() { 763 defer wg.Done() 764 time.Sleep(time.Millisecond * 100) 765 _, err := server.SyncAddHandler(ctx, "test-topic", &testTopicContent{}, func(s string, i interface{}) error { 766 return nil 767 }) 768 require.Error(t, err) 769 require.Regexp(t, ".*ErrPeerMessageServerClosed.*", err.Error()) 770 }() 771 772 wg.Add(1) 773 go func() { 774 defer wg.Done() 775 time.Sleep(time.Millisecond * 300) 776 cancelServer() 777 }() 778 779 wg.Wait() 780 } 781 782 func TestServerExitWhileRemovingHandler(t *testing.T) { 783 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 784 defer cancel() 785 786 server, _, closer := newServerForTesting(t, "test-server-1") 787 defer closer() 788 789 serverCtx, cancelServer := context.WithCancel(ctx) 790 defer cancelServer() 791 792 var wg sync.WaitGroup 793 wg.Add(1) 794 go func() { 795 defer wg.Done() 796 err := server.Run(serverCtx, nil) 797 require.Regexp(t, ".*context canceled.*", err.Error()) 798 }() 799 800 waitCh := make(chan struct{}) 801 802 wg.Add(1) 803 go func() { 804 defer wg.Done() 805 _, err := server.SyncAddHandler(ctx, "test-topic", &testTopicContent{}, func(s string, i interface{}) error { 806 return nil 807 }) 808 require.NoError(t, err) 809 err = server.scheduleTask(ctx, taskDebugDelay{ 810 doneCh: waitCh, 811 }) 812 require.NoError(t, err) 813 time.Sleep(time.Millisecond * 100) 814 err = server.SyncRemoveHandler(ctx, "test-topic") 815 require.NoError(t, err) 816 }() 817 818 wg.Add(1) 819 go func() { 820 defer wg.Done() 821 time.Sleep(time.Millisecond * 500) 822 cancelServer() 823 }() 824 825 wg.Wait() 826 } 827 828 func TestReceiverIDMismatch(t *testing.T) { 829 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 830 defer cancel() 831 832 server, newClient, closer := newServerForTesting(t, "test-server-1") 833 defer closer() 834 835 var wg sync.WaitGroup 836 wg.Add(1) 837 go func() { 838 defer wg.Done() 839 err := server.Run(ctx, nil) 840 require.Regexp(t, ".*context canceled.*", err.Error()) 841 }() 842 843 client, closeClient := newClient() 844 defer closeClient() 845 846 stream, err := client.SendMessage(ctx) 847 require.NoError(t, err) 848 849 err = stream.Send(&p2p.MessagePacket{ 850 Meta: &p2p.StreamMeta{ 851 SenderId: "test-client-1", 852 ReceiverId: "test-server-2", // mismatch 853 Epoch: 0, 854 }, 855 }) 856 require.NoError(t, err) 857 858 resp, err := stream.Recv() 859 require.NoError(t, err) 860 require.Equal(t, p2p.ExitReason_CAPTURE_ID_MISMATCH, resp.ExitReason) 861 862 cancel() 863 wg.Wait() 864 } 865 866 func TestServerDataLossAfterUnregisterHandle(t *testing.T) { 867 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20) 868 defer cancel() 869 870 server, newClient, closer := newServerForTesting(t, "test-server-1") 871 defer closer() 872 873 serverCtx, cancelServer := context.WithCancel(ctx) 874 defer cancelServer() 875 876 var wg sync.WaitGroup 877 wg.Add(1) 878 go func() { 879 defer wg.Done() 880 err := server.Run(serverCtx, nil) 881 require.Regexp(t, ".*context canceled.*", err.Error()) 882 }() 883 884 var called int32 885 mustAddHandler(ctx, t, server, "blocking-handler", &testTopicContent{}, func(_ string, _ interface{}) error { 886 if atomic.AddInt32(&called, 1) == 2 { 887 time.Sleep(1 * time.Second) 888 } 889 return nil 890 }) 891 892 client, closeClient := newClient() 893 defer closeClient() 894 895 stream, err := client.SendMessage(ctx) 896 require.NoError(t, err) 897 898 err = stream.Send(&p2p.MessagePacket{ 899 Meta: &p2p.StreamMeta{ 900 SenderId: "test-client-1", 901 ReceiverId: "test-server-1", 902 Epoch: 0, 903 }, 904 }) 905 require.NoError(t, err) 906 907 err = stream.Send(&p2p.MessagePacket{ 908 Entries: []*p2p.MessageEntry{ 909 { 910 Topic: "blocking-handler", 911 Content: []byte(`{"index":1}`), // just a dummy message 912 Sequence: 1, 913 }, 914 { 915 Topic: "blocking-handler", 916 Content: []byte(`{"index":2}`), // just a dummy message 917 Sequence: 2, 918 }, 919 { 920 // This message will be lost 921 Topic: "blocking-handler", 922 Content: []byte(`{"index":3}`), // just a dummy message 923 Sequence: 3, 924 }, 925 }, 926 }) 927 require.NoError(t, err) 928 require.Eventually(t, func() bool { 929 return atomic.LoadInt32(&called) == 2 930 }, time.Millisecond*500, time.Millisecond*10) 931 932 err = server.SyncRemoveHandler(ctx, "blocking-handler") 933 934 require.NoError(t, err) 935 936 // re-registers the handler 937 errCh := mustAddHandler(ctx, t, server, "blocking-handler", &testTopicContent{}, func(_ string, msg interface{}) error { 938 require.Fail(t, "should not have been called", "value: %v", msg) 939 return nil 940 }) 941 942 err = stream.Send(&p2p.MessagePacket{ 943 Entries: []*p2p.MessageEntry{ 944 { 945 // This message should never have reached the handler because the 946 // message with Sequence = 2 has been lost. 947 Topic: "blocking-handler", 948 Content: []byte(`{"index":4}`), // just a dummy message 949 Sequence: 4, 950 }, 951 }, 952 }) 953 require.NoError(t, err) 954 955 select { 956 case <-ctx.Done(): 957 require.Fail(t, "test timed out: TestServerDataLossAfterUnregisterHandle") 958 case err = <-errCh: 959 } 960 require.Error(t, err) 961 require.Regexp(t, "ErrPeerMessageDataLost", err.Error()) 962 963 cancel() 964 wg.Wait() 965 } 966 967 func TestServerDeregisterPeer(t *testing.T) { 968 ctx, cancel := context.WithTimeout(context.TODO(), defaultTimeout) 969 defer cancel() 970 971 server, newClient, closer := newServerForTesting(t, "test-server-2") 972 defer closer() 973 974 // Avoids server returning error due to congested topic. 975 server.config.MaxPendingMessageCountPerTopic = math.MaxInt64 976 977 var wg sync.WaitGroup 978 wg.Add(1) 979 go func() { 980 defer wg.Done() 981 err := server.Run(ctx, nil) 982 require.Regexp(t, ".*context canceled.*", err) 983 }() 984 985 var sendGroup sync.WaitGroup 986 sendGroup.Add(1) 987 client, closeClient := newClient() 988 go func() { 989 defer sendGroup.Done() 990 stream, err := client.SendMessage(ctx) 991 require.NoError(t, err) 992 993 err = stream.Send(&p2p.MessagePacket{ 994 Meta: &p2p.StreamMeta{ 995 SenderId: "test-client-1", 996 ReceiverId: "test-server-2", 997 Epoch: 0, 998 }, 999 }) 1000 require.NoError(t, err) 1001 }() 1002 sendGroup.Wait() 1003 time.Sleep(1 * time.Second) 1004 1005 server.peerLock.Lock() 1006 require.Equal(t, 1, len(server.peers)) 1007 server.peerLock.Unlock() 1008 require.Nil(t, server.ScheduleDeregisterPeerTask(ctx, "test-client-1")) 1009 time.Sleep(1 * time.Second) 1010 server.peerLock.Lock() 1011 require.Equal(t, 0, len(server.peers)) 1012 server.peerLock.Unlock() 1013 1014 closeClient() 1015 closer() 1016 cancel() 1017 wg.Wait() 1018 }