github.com/matrixorigin/matrixone@v1.2.0/pkg/common/morpc/backend_test.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package morpc 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 "runtime/debug" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/fagongzi/goetty/v2" 27 "github.com/fagongzi/goetty/v2/buf" 28 "github.com/lni/goutils/leaktest" 29 "github.com/matrixorigin/matrixone/pkg/logutil" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 "go.uber.org/zap" 33 ) 34 35 var ( 36 testProxyAddr = "unix:///tmp/proxy.sock" 37 testAddr = "unix:///tmp/goetty.sock" 38 testUnixFile = "/tmp/goetty.sock" 39 ) 40 41 func TestSend(t *testing.T) { 42 testBackendSend(t, 43 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 44 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 45 }, 46 func(b *remoteBackend) { 47 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 48 defer cancel() 49 req := newTestMessage(1) 50 f, err := b.Send(ctx, req) 51 assert.NoError(t, err) 52 defer f.Close() 53 54 resp, err := f.Get() 55 assert.NoError(t, err) 56 assert.Equal(t, req, resp) 57 }, 58 ) 59 } 60 61 func TestReadTimeoutWithNormalMessageMissed(t *testing.T) { 62 testBackendSend(t, 63 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 64 request := msg.(RPCMessage) 65 if request.internal { 66 if m, ok := request.Message.(*flagOnlyMessage); ok { 67 switch m.flag { 68 case flagPing: 69 return conn.Write(RPCMessage{ 70 Ctx: request.Ctx, 71 internal: true, 72 Message: &flagOnlyMessage{ 73 flag: flagPong, 74 id: m.id, 75 }, 76 }, goetty.WriteOptions{Flush: true}) 77 default: 78 panic(fmt.Sprintf("invalid internal message, flag %d", m.flag)) 79 } 80 } 81 } 82 // no response 83 return nil 84 }, 85 func(b *remoteBackend) { 86 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 87 defer cancel() 88 req := newTestMessage(1) 89 f, err := b.Send(ctx, req) 90 assert.NoError(t, err) 91 defer f.Close() 92 _, err = f.Get() 93 assert.Equal(t, ctx.Err(), err) 94 }, 95 WithBackendReadTimeout(time.Millisecond*200), 96 ) 97 } 98 99 func TestReadTimeout(t *testing.T) { 100 testBackendSend(t, 101 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 102 // no response 103 return nil 104 }, 105 func(b *remoteBackend) { 106 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 107 defer cancel() 108 req := newTestMessage(1) 109 f, err := b.Send(ctx, req) 110 assert.NoError(t, err) 111 defer f.Close() 112 _, err = f.Get() 113 assert.Equal(t, backendClosed, err) 114 }, 115 WithBackendReadTimeout(time.Millisecond*200), 116 ) 117 } 118 119 func TestSendWithPayloadCannotTimeout(t *testing.T) { 120 testBackendSend(t, 121 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 122 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 123 }, 124 func(b *remoteBackend) { 125 b.conn.RawConn().SetWriteDeadline(time.Now().Add(time.Millisecond)) 126 time.Sleep(time.Millisecond) 127 ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 128 defer cancel() 129 req := newTestMessage(1) 130 req.payload = []byte("hello") 131 f, err := b.Send(ctx, req) 132 assert.NoError(t, err) 133 defer f.Close() 134 135 resp, err := f.Get() 136 assert.NoError(t, err) 137 assert.Equal(t, req, resp) 138 }, 139 ) 140 } 141 142 func TestSendWithPayloadCannotBlockIfFutureRemoved(t *testing.T) { 143 var wg sync.WaitGroup 144 wg.Add(1) 145 testBackendSend(t, 146 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 147 wg.Wait() 148 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 149 }, 150 func(b *remoteBackend) { 151 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) 152 defer cancel() 153 req := newTestMessage(1) 154 req.payload = []byte("hello") 155 f, err := b.Send(ctx, req) 156 require.NoError(t, err) 157 id := f.getSendMessageID() 158 // keep future in the futures map 159 f.ref() 160 defer f.unRef() 161 f.Close() 162 b.mu.RLock() 163 _, ok := b.mu.futures[id] 164 assert.True(t, ok) 165 b.mu.RUnlock() 166 wg.Done() 167 time.Sleep(time.Second) 168 }, 169 WithBackendHasPayloadResponse()) 170 } 171 172 func TestSendWithPayloadCannotBlockIfFutureClosed(t *testing.T) { 173 var wg sync.WaitGroup 174 wg.Add(1) 175 testBackendSend(t, 176 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 177 wg.Wait() 178 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 179 }, 180 func(b *remoteBackend) { 181 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) 182 defer cancel() 183 req := newTestMessage(1) 184 req.payload = []byte("hello") 185 f, err := b.Send(ctx, req) 186 require.NoError(t, err) 187 id := f.getSendMessageID() 188 f.mu.Lock() 189 f.mu.closed = true 190 f.releaseFunc = nil // make it nil to keep this future in b.mu.features 191 f.mu.Unlock() 192 b.mu.RLock() 193 _, ok := b.mu.futures[id] 194 b.mu.RUnlock() 195 assert.True(t, ok) 196 wg.Done() 197 time.Sleep(time.Second) 198 }, 199 WithBackendHasPayloadResponse()) 200 } 201 202 func TestCloseWhileContinueSending(t *testing.T) { 203 defer leaktest.AfterTest(t)() 204 testBackendSend(t, 205 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 206 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 207 }, 208 func(b *remoteBackend) { 209 c := make(chan struct{}) 210 stopC := make(chan struct{}) 211 var wg sync.WaitGroup 212 wg.Add(1) 213 go func() { 214 defer wg.Done() 215 sendFunc := func() { 216 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 217 defer cancel() 218 req := newTestMessage(1) 219 f, err := b.Send(ctx, req) 220 if err != nil { 221 return 222 } 223 defer f.Close() 224 225 resp, err := f.Get() 226 if err == nil { 227 assert.Equal(t, req, resp) 228 } 229 select { 230 case c <- struct{}{}: 231 default: 232 } 233 } 234 235 for { 236 select { 237 case <-stopC: 238 return 239 default: 240 sendFunc() 241 } 242 } 243 }() 244 <-c 245 b.Close() 246 close(stopC) 247 wg.Wait() 248 }, 249 ) 250 } 251 252 func TestSendWithAlreadyContextDone(t *testing.T) { 253 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 254 255 testBackendSend(t, 256 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 257 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 258 }, 259 func(b *remoteBackend) { 260 261 req := newTestMessage(1) 262 f, err := b.Send(ctx, req) 263 assert.NoError(t, err) 264 defer f.Close() 265 resp, err := f.Get() 266 assert.Error(t, err) 267 assert.Nil(t, resp) 268 }, 269 WithBackendFilter(func(Message, string) bool { 270 cancel() 271 return true 272 })) 273 } 274 275 func TestSendWithTimeout(t *testing.T) { 276 testBackendSend(t, 277 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 278 return nil 279 }, 280 func(b *remoteBackend) { 281 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200) 282 defer cancel() 283 req := &testMessage{id: 1} 284 f, err := b.Send(ctx, req) 285 assert.NoError(t, err) 286 defer f.Close() 287 288 resp, err := f.Get() 289 assert.Error(t, err) 290 assert.Nil(t, resp) 291 assert.Equal(t, err, ctx.Err()) 292 }, 293 ) 294 } 295 296 func TestSendWithCannotConnect(t *testing.T) { 297 var rb *remoteBackend 298 testBackendSend(t, 299 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 300 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 301 }, 302 func(b *remoteBackend) { 303 rb = b 304 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) 305 defer cancel() 306 req := &testMessage{id: 1} 307 f, err := b.Send(ctx, req) 308 assert.NoError(t, err) 309 defer f.Close() 310 311 resp, err := f.Get() 312 assert.Error(t, err) 313 assert.Nil(t, resp) 314 }, 315 WithBackendFilter(func(Message, string) bool { 316 assert.NoError(t, rb.conn.Disconnect()) 317 rb.remote = "" 318 return true 319 }), 320 WithBackendConnectTimeout(time.Millisecond*200), 321 ) 322 } 323 324 func TestFutureGetCannotBlockIfCloseBackend(t *testing.T) { 325 testBackendSend(t, 326 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 327 return conn.Close() 328 }, 329 func(b *remoteBackend) { 330 ctx, cancel := context.WithTimeout(context.Background(), time.Second*100) 331 defer cancel() 332 333 n := 2 334 futures := make([]*Future, 0, n) 335 for i := 0; i < n; i++ { 336 req := newTestMessage(1) 337 f, err := b.Send(ctx, req) 338 assert.NoError(t, err) 339 futures = append(futures, f) 340 } 341 b.Close() 342 for _, f := range futures { 343 _, err := f.Get() 344 assert.Error(t, err) 345 } 346 }, 347 WithBackendBatchSendSize(1), 348 WithBackendFilter(func(m Message, s string) bool { 349 time.Sleep(time.Millisecond * 100) 350 return false 351 }), 352 ) 353 } 354 355 func TestStream(t *testing.T) { 356 testBackendSend(t, 357 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 358 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 359 }, 360 func(b *remoteBackend) { 361 st, err := b.NewStream(false) 362 assert.NoError(t, err) 363 defer func() { 364 assert.NoError(t, st.Close(false)) 365 b.mu.RLock() 366 assert.Equal(t, 0, len(b.mu.futures)) 367 b.mu.RUnlock() 368 }() 369 370 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 371 defer cancel() 372 373 n := 1 374 for i := 0; i < n; i++ { 375 req := &testMessage{id: st.ID()} 376 assert.NoError(t, st.Send(ctx, req)) 377 } 378 379 rc, err := st.Receive() 380 assert.NoError(t, err) 381 for i := 0; i < n; i++ { 382 v, ok := <-rc 383 assert.True(t, ok) 384 assert.Equal(t, &testMessage{id: st.ID()}, v) 385 } 386 }, 387 ) 388 } 389 390 func TestCloseStreamWithCloseConn(t *testing.T) { 391 testBackendSend(t, 392 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 393 for { 394 if err := conn.Write(msg, goetty.WriteOptions{Flush: true}); err != nil { 395 return err 396 } 397 } 398 }, 399 func(b *remoteBackend) { 400 st, err := b.NewStream(false) 401 assert.NoError(t, err) 402 403 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 404 defer cancel() 405 406 req := &testMessage{id: st.ID()} 407 assert.NoError(t, st.Send(ctx, req)) 408 409 for { 410 n := len(st.(*stream).c) 411 if n == 2 { 412 break 413 } 414 time.Sleep(time.Millisecond * 10) 415 } 416 417 require.NoError(t, st.Close(true)) 418 419 _, err = st.Receive() 420 require.Error(t, err) 421 422 b.Lock() 423 defer b.Unlock() 424 assert.Equal(t, stateStopped, b.stateMu.state) 425 }, 426 WithBackendStreamBufferSize(2), 427 ) 428 } 429 430 func TestStreamSendWillPanicIfDeadlineNotSet(t *testing.T) { 431 testBackendSend(t, 432 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 433 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 434 }, 435 func(b *remoteBackend) { 436 st, err := b.NewStream(false) 437 assert.NoError(t, err) 438 defer func() { 439 assert.NoError(t, st.Close(false)) 440 b.mu.RLock() 441 assert.Equal(t, 0, len(b.mu.futures)) 442 b.mu.RUnlock() 443 }() 444 445 defer func() { 446 if err := recover(); err == nil { 447 assert.Fail(t, "must panic") 448 } 449 }() 450 451 req := &testMessage{id: st.ID()} 452 assert.NoError(t, st.Send(context.TODO(), req)) 453 }, 454 ) 455 } 456 457 func TestStreamClosedByConnReset(t *testing.T) { 458 testBackendSend(t, 459 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 460 return conn.Disconnect() 461 }, 462 func(b *remoteBackend) { 463 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 464 defer cancel() 465 466 st, err := b.NewStream(false) 467 assert.NoError(t, err) 468 defer func() { 469 assert.NoError(t, st.Close(false)) 470 }() 471 c, err := st.Receive() 472 assert.NoError(t, err) 473 assert.NoError(t, st.Send(ctx, &testMessage{id: st.ID()})) 474 475 v, ok := <-c 476 assert.True(t, ok) 477 assert.Nil(t, v) 478 }, 479 ) 480 } 481 482 func TestStreamClosedBySequenceNotMatch(t *testing.T) { 483 testBackendSend(t, 484 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 485 resp := msg.(RPCMessage) 486 resp.streamSequence = 2 487 return conn.Write(resp, goetty.WriteOptions{Flush: true}) 488 }, 489 func(b *remoteBackend) { 490 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 491 defer cancel() 492 493 st, err := b.NewStream(false) 494 assert.NoError(t, err) 495 defer func() { 496 assert.NoError(t, st.Close(false)) 497 }() 498 c, err := st.Receive() 499 assert.NoError(t, err) 500 assert.NoError(t, st.Send(ctx, &testMessage{id: st.ID()})) 501 502 v, ok := <-c 503 assert.True(t, ok) 504 assert.Nil(t, v) 505 }, 506 ) 507 } 508 509 func TestBusy(t *testing.T) { 510 n := 0 511 c := make(chan struct{}) 512 testBackendSend(t, 513 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 514 return nil 515 }, 516 func(b *remoteBackend) { 517 assert.False(t, b.Busy()) 518 519 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200) 520 defer cancel() 521 f1, err := b.Send(ctx, newTestMessage(1)) 522 assert.NoError(t, err) 523 defer f1.Close() 524 525 f2, err := b.Send(ctx, newTestMessage(2)) 526 assert.NoError(t, err) 527 defer f2.Close() 528 529 assert.True(t, b.Busy()) 530 c <- struct{}{} 531 }, 532 WithBackendFilter(func(Message, string) bool { 533 if n == 0 { 534 <-c 535 n++ 536 } 537 return false 538 }), 539 WithBackendBatchSendSize(1), 540 WithBackendBufferSize(10), 541 WithBackendBusyBufferSize(1)) 542 } 543 544 func TestDoneWithClosedStreamCannotPanic(t *testing.T) { 545 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 546 defer cancel() 547 548 c := make(chan Message, 1) 549 s := newStream( 550 nil, 551 c, 552 func() *Future { return newFuture(nil) }, 553 func(m *Future) error { 554 m.messageSent(nil) 555 return nil 556 }, 557 func(s *stream) {}, 558 func() {}) 559 s.init(1, false) 560 assert.NoError(t, s.Send(ctx, &testMessage{id: s.ID()})) 561 assert.NoError(t, s.Close(false)) 562 s.done(context.TODO(), RPCMessage{}, false) 563 } 564 565 func TestGCStream(t *testing.T) { 566 c := make(chan Message, 1) 567 s := newStream( 568 nil, 569 c, 570 func() *Future { return newFuture(nil) }, 571 func(m *Future) error { 572 return nil 573 }, 574 func(s *stream) {}, 575 func() {}) 576 s.init(1, false) 577 s = nil 578 debug.FreeOSMemory() 579 _, ok := <-c 580 assert.False(t, ok) 581 } 582 583 func TestLastActiveWithNew(t *testing.T) { 584 testBackendSend(t, 585 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 586 return nil 587 }, 588 func(b *remoteBackend) { 589 assert.NotEqual(t, time.Time{}, b.LastActiveTime()) 590 }, 591 ) 592 } 593 594 func TestLastActiveWithSend(t *testing.T) { 595 c := make(chan struct{}) 596 testBackendSend(t, 597 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 598 <-c 599 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 600 }, 601 func(b *remoteBackend) { 602 t1 := b.LastActiveTime() 603 604 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 605 defer cancel() 606 req := newTestMessage(1) 607 f, err := b.Send(ctx, req) 608 assert.NoError(t, err) 609 defer f.Close() 610 611 t2 := b.LastActiveTime() 612 assert.NotEqual(t, t1, t2) 613 assert.True(t, t2.After(t1)) 614 c <- struct{}{} 615 616 resp, err := f.Get() 617 assert.NoError(t, err) 618 assert.Equal(t, req, resp) 619 620 t3 := b.LastActiveTime() 621 assert.NotEqual(t, t2, t3) 622 assert.True(t, t3.After(t2)) 623 624 }, 625 ) 626 } 627 628 func TestLastActiveWithStream(t *testing.T) { 629 testBackendSend(t, 630 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 631 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 632 }, 633 func(b *remoteBackend) { 634 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 635 defer cancel() 636 637 t1 := b.LastActiveTime() 638 639 st, err := b.NewStream(false) 640 assert.NoError(t, err) 641 defer func() { 642 assert.NoError(t, st.Close(false)) 643 }() 644 645 n := 1 646 for i := 0; i < n; i++ { 647 req := &testMessage{id: st.ID()} 648 assert.NoError(t, st.Send(ctx, req)) 649 t2 := b.LastActiveTime() 650 assert.NotEqual(t, t1, t2) 651 assert.True(t, t2.After(t1)) 652 } 653 }, 654 ) 655 } 656 657 func TestBackendConnectTimeout(t *testing.T) { 658 rb, err := NewRemoteBackend( 659 testAddr, 660 newTestCodec(), 661 WithBackendMetrics(newMetrics("")), 662 WithBackendConnectTimeout(time.Millisecond*200), 663 ) 664 assert.Error(t, err) 665 assert.Nil(t, rb) 666 } 667 668 func TestInactiveAfterCannotConnect(t *testing.T) { 669 app := newTestApp(t, func(conn goetty.IOSession, msg interface{}, _ uint64) error { 670 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 671 }) 672 assert.NoError(t, app.Start()) 673 674 testBackendSendWithoutServer(t, 675 testAddr, 676 func(b *remoteBackend) { 677 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 678 defer cancel() 679 req := newTestMessage(1) 680 f, err := b.Send(ctx, req) 681 assert.NoError(t, err) 682 defer f.Close() 683 684 resp, err := f.Get() 685 assert.NoError(t, err) 686 assert.Equal(t, req, resp) 687 688 assert.NoError(t, app.Stop()) 689 var v time.Time 690 for { 691 if b.LastActiveTime() == v { 692 break 693 } 694 time.Sleep(time.Millisecond * 100) 695 } 696 }, 697 WithBackendConnectTimeout(time.Millisecond*100)) 698 } 699 700 func TestTCPProxyExample(t *testing.T) { 701 assert.NoError(t, os.RemoveAll(testProxyAddr[7:])) 702 p := goetty.NewProxy(testProxyAddr, nil) 703 assert.NoError(t, p.Start()) 704 defer func() { 705 assert.NoError(t, p.Stop()) 706 }() 707 p.AddUpStream(testAddr, time.Second*10) 708 709 testBackendSendWithAddr(t, 710 testProxyAddr, 711 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 712 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 713 }, 714 func(b *remoteBackend) { 715 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 716 defer cancel() 717 req := newTestMessage(1) 718 f, err := b.Send(ctx, req) 719 assert.NoError(t, err) 720 defer f.Close() 721 722 resp, err := f.Get() 723 assert.NoError(t, err) 724 assert.Equal(t, req, resp) 725 }, 726 ) 727 } 728 729 func TestLockedStream(t *testing.T) { 730 testBackendSend(t, 731 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 732 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 733 }, 734 func(b *remoteBackend) { 735 assert.False(t, b.Locked()) 736 b.Lock() 737 st, err := b.NewStream(true) 738 assert.NoError(t, err) 739 assert.True(t, b.Locked()) 740 assert.NoError(t, st.Close(false)) 741 assert.False(t, b.Locked()) 742 }, 743 ) 744 } 745 746 func TestIssue7678(t *testing.T) { 747 s := &stream{} 748 s.lastReceivedSequence = 10 749 s.init(0, false) 750 assert.Equal(t, uint32(0), s.lastReceivedSequence) 751 } 752 753 func TestWaitingFutureMustGetClosedError(t *testing.T) { 754 testBackendSend(t, 755 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 756 return backendClosed 757 }, 758 func(b *remoteBackend) { 759 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 760 defer cancel() 761 req := newTestMessage(1) 762 f, err := b.Send(ctx, req) 763 assert.NoError(t, err) 764 defer f.Close() 765 766 _, err = f.Get() 767 assert.Error(t, err) 768 assert.Equal(t, backendClosed, err) 769 }, 770 ) 771 } 772 773 func TestIssue11838(t *testing.T) { 774 testBackendSend(t, 775 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 776 if seq == 100 { 777 return backendClosed 778 } 779 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 780 }, 781 func(b *remoteBackend) { 782 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200) 783 defer cancel() 784 785 var futures []*Future 786 for i := 0; i < 10000; i++ { 787 req := newTestMessage(uint64(i)) 788 f, err := b.Send(ctx, req) 789 if err == nil { 790 futures = append(futures, f) 791 } 792 } 793 794 for _, f := range futures { 795 _, err := f.Get() 796 if err == nil { 797 f.Close() 798 } 799 } 800 }, 801 ) 802 } 803 804 func testBackendSend(t *testing.T, 805 handleFunc func(goetty.IOSession, interface{}, uint64) error, 806 testFunc func(b *remoteBackend), 807 options ...BackendOption) { 808 testBackendSendWithAddr(t, testAddr, handleFunc, testFunc, options...) 809 } 810 811 func testBackendSendWithAddr(t *testing.T, addr string, 812 handleFunc func(goetty.IOSession, interface{}, uint64) error, 813 testFunc func(b *remoteBackend), 814 options ...BackendOption) { 815 app := newTestApp(t, handleFunc) 816 assert.NoError(t, app.Start()) 817 defer func() { 818 assert.NoError(t, app.Stop()) 819 }() 820 821 testBackendSendWithoutServer(t, addr, testFunc, options...) 822 } 823 824 func testBackendSendWithoutServer(t *testing.T, addr string, 825 testFunc func(b *remoteBackend), 826 options ...BackendOption) { 827 828 options = append( 829 options, 830 WithBackendMetrics(newMetrics("")), 831 WithBackendBufferSize(1), 832 WithBackendLogger(logutil.GetPanicLoggerWithLevel(zap.DebugLevel).With(zap.String("testcase", t.Name())))) 833 rb, err := NewRemoteBackend(addr, newTestCodec(), options...) 834 assert.NoError(t, err) 835 836 b := rb.(*remoteBackend) 837 defer func() { 838 b.Close() 839 assert.Nil(t, b.conn) 840 }() 841 testFunc(b) 842 } 843 844 func newTestApp(t *testing.T, 845 handleFunc func(goetty.IOSession, interface{}, uint64) error, 846 opts ...goetty.AppOption) goetty.NetApplication { 847 assert.NoError(t, os.RemoveAll(testUnixFile)) 848 codec := newTestCodec().(*messageCodec) 849 opts = append(opts, goetty.WithAppSessionOptions(goetty.WithSessionCodec(codec))) 850 app, err := goetty.NewApplication(testAddr, handleFunc, opts...) 851 assert.NoError(t, err) 852 853 return app 854 } 855 856 type testBackendFactory struct { 857 sync.RWMutex 858 id int 859 } 860 861 func newTestBackendFactory() *testBackendFactory { 862 return &testBackendFactory{} 863 } 864 865 func (bf *testBackendFactory) Create(backend string, opts ...BackendOption) (Backend, error) { 866 bf.Lock() 867 defer bf.Unlock() 868 b := &testBackend{id: bf.id} 869 b.activeTime = time.Now() 870 bf.id++ 871 return b, nil 872 } 873 874 type testBackend struct { 875 sync.RWMutex 876 id int 877 busy bool 878 activeTime time.Time 879 closed bool 880 locked bool 881 } 882 883 func (b *testBackend) Send(ctx context.Context, request Message) (*Future, error) { 884 b.active() 885 f := newFuture(nil) 886 f.init(RPCMessage{Ctx: ctx, Message: request}) 887 return f, nil 888 } 889 890 func (b *testBackend) SendInternal(ctx context.Context, request Message) (*Future, error) { 891 b.active() 892 f := newFuture(nil) 893 f.init(RPCMessage{Ctx: ctx, Message: request}) 894 return f, nil 895 } 896 897 func (b *testBackend) NewStream(unlockAfterClose bool) (Stream, error) { 898 b.active() 899 st := newStream( 900 nil, 901 make(chan Message, 1), 902 func() *Future { return newFuture(nil) }, 903 func(m *Future) error { 904 m.messageSent(nil) 905 return nil 906 }, 907 func(s *stream) { 908 if s.unlockAfterClose { 909 b.Unlock() 910 } 911 }, 912 b.active) 913 st.init(1, false) 914 return st, nil 915 } 916 917 func (b *testBackend) Close() { 918 b.RWMutex.Lock() 919 defer b.RWMutex.Unlock() 920 b.closed = true 921 } 922 func (b *testBackend) Busy() bool { return b.busy } 923 func (b *testBackend) LastActiveTime() time.Time { 924 b.RLock() 925 defer b.RUnlock() 926 return b.activeTime 927 } 928 929 func (b *testBackend) Lock() { 930 b.RWMutex.Lock() 931 defer b.RWMutex.Unlock() 932 if b.locked { 933 panic("backend is already locked") 934 } 935 b.locked = true 936 } 937 938 func (b *testBackend) Unlock() { 939 b.RWMutex.Lock() 940 defer b.RWMutex.Unlock() 941 if !b.locked { 942 panic("backend is not locked") 943 } 944 b.locked = false 945 } 946 947 func (b *testBackend) Locked() bool { 948 b.RLock() 949 defer b.RUnlock() 950 return b.locked 951 } 952 953 func (b *testBackend) active() { 954 b.RWMutex.Lock() 955 defer b.RWMutex.Unlock() 956 b.activeTime = time.Now() 957 } 958 959 type testMessage struct { 960 id uint64 961 payload []byte 962 } 963 964 func newTestMessage(id uint64) *testMessage { 965 return &testMessage{id: id} 966 } 967 968 func (tm *testMessage) SetID(id uint64) { 969 tm.id = id 970 } 971 972 func (tm *testMessage) GetID() uint64 { 973 return tm.id 974 } 975 976 func (tm *testMessage) DebugString() string { 977 return fmt.Sprintf("%d:%d", tm.id, len(tm.payload)) 978 } 979 980 func (tm *testMessage) Size() int { 981 return 8 + len(tm.payload) 982 } 983 984 func (tm *testMessage) MarshalTo(data []byte) (int, error) { 985 buf.Uint64ToBytesTo(tm.id, data) 986 return 8, nil 987 } 988 989 func (tm *testMessage) Unmarshal(data []byte) error { 990 tm.id = buf.Byte2Uint64(data) 991 return nil 992 } 993 994 func (tm *testMessage) GetPayloadField() []byte { 995 return tm.payload 996 } 997 998 func (tm *testMessage) SetPayloadField(data []byte) { 999 if len(data) > 0 { 1000 tm.payload = make([]byte, len(data)) 1001 copy(tm.payload, data) 1002 } 1003 } 1004 1005 func newTestCodec(options ...CodecOption) Codec { 1006 options = append(options, 1007 WithCodecPayloadCopyBufferSize(1024)) 1008 return NewMessageCodec(func() Message { return messagePool.Get().(*testMessage) }, options...) 1009 } 1010 1011 var ( 1012 messagePool = sync.Pool{ 1013 New: func() any { 1014 return newTestMessage(0) 1015 }, 1016 } 1017 )