github.com/matrixorigin/matrixone@v0.7.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 TestSendWithPayloadCannotTimeout(t *testing.T) { 62 testBackendSend(t, 63 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 64 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 65 }, 66 func(b *remoteBackend) { 67 b.conn.RawConn().SetWriteDeadline(time.Now().Add(time.Millisecond)) 68 time.Sleep(time.Millisecond) 69 ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 70 defer cancel() 71 req := newTestMessage(1) 72 req.payload = []byte("hello") 73 f, err := b.Send(ctx, req) 74 assert.NoError(t, err) 75 defer f.Close() 76 77 resp, err := f.Get() 78 assert.NoError(t, err) 79 assert.Equal(t, req, resp) 80 }, 81 ) 82 } 83 84 func TestSendWithPayloadCannotBlockIfFutureRemoved(t *testing.T) { 85 var wg sync.WaitGroup 86 wg.Add(1) 87 testBackendSend(t, 88 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 89 wg.Wait() 90 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 91 }, 92 func(b *remoteBackend) { 93 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) 94 defer cancel() 95 req := newTestMessage(1) 96 req.payload = []byte("hello") 97 f, err := b.Send(ctx, req) 98 require.NoError(t, err) 99 id := f.getSendMessageID() 100 // keep future in the futures map 101 f.ref() 102 defer f.unRef() 103 f.Close() 104 b.mu.RLock() 105 _, ok := b.mu.futures[id] 106 assert.True(t, ok) 107 b.mu.RUnlock() 108 wg.Done() 109 time.Sleep(time.Second) 110 }, 111 WithBackendHasPayloadResponse()) 112 } 113 114 func TestSendWithPayloadCannotBlockIfFutureClosed(t *testing.T) { 115 var wg sync.WaitGroup 116 wg.Add(1) 117 testBackendSend(t, 118 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 119 wg.Wait() 120 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 121 }, 122 func(b *remoteBackend) { 123 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) 124 defer cancel() 125 req := newTestMessage(1) 126 req.payload = []byte("hello") 127 f, err := b.Send(ctx, req) 128 require.NoError(t, err) 129 id := f.getSendMessageID() 130 f.mu.Lock() 131 f.mu.closed = true 132 f.releaseFunc = nil // make it nil to keep this future in b.mu.features 133 f.mu.Unlock() 134 b.mu.RLock() 135 _, ok := b.mu.futures[id] 136 b.mu.RUnlock() 137 assert.True(t, ok) 138 wg.Done() 139 time.Sleep(time.Second) 140 }, 141 WithBackendHasPayloadResponse()) 142 } 143 144 func TestCloseWhileContinueSending(t *testing.T) { 145 defer leaktest.AfterTest(t)() 146 testBackendSend(t, 147 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 148 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 149 }, 150 func(b *remoteBackend) { 151 c := make(chan struct{}) 152 stopC := make(chan struct{}) 153 var wg sync.WaitGroup 154 wg.Add(1) 155 go func() { 156 defer wg.Done() 157 sendFunc := func() { 158 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 159 defer cancel() 160 req := newTestMessage(1) 161 f, err := b.Send(ctx, req) 162 if err != nil { 163 return 164 } 165 defer f.Close() 166 167 resp, err := f.Get() 168 if err == nil { 169 assert.Equal(t, req, resp) 170 } 171 select { 172 case c <- struct{}{}: 173 default: 174 } 175 } 176 177 for { 178 select { 179 case <-stopC: 180 return 181 default: 182 sendFunc() 183 } 184 } 185 }() 186 <-c 187 b.Close() 188 close(stopC) 189 wg.Wait() 190 }, 191 ) 192 } 193 194 func TestSendWithAlreadyContextDone(t *testing.T) { 195 ctx, cancel := context.WithTimeout(context.Background(), time.Hour) 196 197 testBackendSend(t, 198 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 199 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 200 }, 201 func(b *remoteBackend) { 202 203 req := newTestMessage(1) 204 f, err := b.Send(ctx, req) 205 assert.NoError(t, err) 206 defer f.Close() 207 resp, err := f.Get() 208 assert.Error(t, err) 209 assert.Nil(t, resp) 210 }, 211 WithBackendFilter(func(Message, string) bool { 212 cancel() 213 return true 214 })) 215 } 216 217 func TestSendWithTimeout(t *testing.T) { 218 testBackendSend(t, 219 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 220 return nil 221 }, 222 func(b *remoteBackend) { 223 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200) 224 defer cancel() 225 req := &testMessage{id: 1} 226 f, err := b.Send(ctx, req) 227 assert.NoError(t, err) 228 defer f.Close() 229 230 resp, err := f.Get() 231 assert.Error(t, err) 232 assert.Nil(t, resp) 233 assert.Equal(t, err, ctx.Err()) 234 }, 235 ) 236 } 237 238 func TestSendWithCannotConnect(t *testing.T) { 239 var rb *remoteBackend 240 testBackendSend(t, 241 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 242 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 243 }, 244 func(b *remoteBackend) { 245 rb = b 246 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) 247 defer cancel() 248 req := &testMessage{id: 1} 249 f, err := b.Send(ctx, req) 250 assert.NoError(t, err) 251 defer f.Close() 252 253 resp, err := f.Get() 254 assert.Error(t, err) 255 assert.Nil(t, resp) 256 }, 257 WithBackendFilter(func(Message, string) bool { 258 assert.NoError(t, rb.conn.Disconnect()) 259 rb.remote = "" 260 return true 261 }), 262 WithBackendConnectTimeout(time.Millisecond*200), 263 ) 264 } 265 266 func TestFutureGetCannotBlockIfCloseBackend(t *testing.T) { 267 testBackendSend(t, 268 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 269 return conn.Close() 270 }, 271 func(b *remoteBackend) { 272 ctx, cancel := context.WithTimeout(context.Background(), time.Second*100) 273 defer cancel() 274 275 n := 2 276 futures := make([]*Future, 0, n) 277 for i := 0; i < n; i++ { 278 req := newTestMessage(1) 279 f, err := b.Send(ctx, req) 280 assert.NoError(t, err) 281 futures = append(futures, f) 282 } 283 b.Close() 284 for _, f := range futures { 285 _, err := f.Get() 286 assert.Error(t, err) 287 } 288 }, 289 WithBackendBatchSendSize(1), 290 WithBackendFilter(func(m Message, s string) bool { 291 time.Sleep(time.Millisecond * 100) 292 return false 293 }), 294 ) 295 } 296 297 func TestStream(t *testing.T) { 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 st, err := b.NewStream(false) 304 assert.NoError(t, err) 305 defer func() { 306 assert.NoError(t, st.Close()) 307 b.mu.RLock() 308 assert.Equal(t, 0, len(b.mu.futures)) 309 b.mu.RUnlock() 310 }() 311 312 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 313 defer cancel() 314 315 n := 1 316 for i := 0; i < n; i++ { 317 req := &testMessage{id: st.ID()} 318 assert.NoError(t, st.Send(ctx, req)) 319 } 320 321 rc, err := st.Receive() 322 assert.NoError(t, err) 323 for i := 0; i < n; i++ { 324 v, ok := <-rc 325 assert.True(t, ok) 326 assert.Equal(t, &testMessage{id: st.ID()}, v) 327 } 328 }, 329 ) 330 } 331 332 func TestStreamSendWillPanicIfDeadlineNotSet(t *testing.T) { 333 testBackendSend(t, 334 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 335 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 336 }, 337 func(b *remoteBackend) { 338 st, err := b.NewStream(false) 339 assert.NoError(t, err) 340 defer func() { 341 assert.NoError(t, st.Close()) 342 b.mu.RLock() 343 assert.Equal(t, 0, len(b.mu.futures)) 344 b.mu.RUnlock() 345 }() 346 347 defer func() { 348 if err := recover(); err == nil { 349 assert.Fail(t, "must panic") 350 } 351 }() 352 353 req := &testMessage{id: st.ID()} 354 assert.NoError(t, st.Send(context.TODO(), req)) 355 }, 356 ) 357 } 358 359 func TestStreamClosedByConnReset(t *testing.T) { 360 testBackendSend(t, 361 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 362 return conn.Disconnect() 363 }, 364 func(b *remoteBackend) { 365 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 366 defer cancel() 367 368 st, err := b.NewStream(false) 369 assert.NoError(t, err) 370 defer func() { 371 assert.NoError(t, st.Close()) 372 }() 373 c, err := st.Receive() 374 assert.NoError(t, err) 375 assert.NoError(t, st.Send(ctx, &testMessage{id: st.ID()})) 376 377 v, ok := <-c 378 assert.True(t, ok) 379 assert.Nil(t, v) 380 }, 381 ) 382 } 383 384 func TestStreamClosedBySequenceNotMatch(t *testing.T) { 385 testBackendSend(t, 386 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 387 resp := msg.(RPCMessage) 388 resp.streamSequence = 2 389 return conn.Write(resp, goetty.WriteOptions{Flush: true}) 390 }, 391 func(b *remoteBackend) { 392 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 393 defer cancel() 394 395 st, err := b.NewStream(false) 396 assert.NoError(t, err) 397 defer func() { 398 assert.NoError(t, st.Close()) 399 }() 400 c, err := st.Receive() 401 assert.NoError(t, err) 402 assert.NoError(t, st.Send(ctx, &testMessage{id: st.ID()})) 403 404 v, ok := <-c 405 assert.True(t, ok) 406 assert.Nil(t, v) 407 }, 408 ) 409 } 410 411 func TestBusy(t *testing.T) { 412 n := 0 413 c := make(chan struct{}) 414 testBackendSend(t, 415 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 416 return nil 417 }, 418 func(b *remoteBackend) { 419 assert.False(t, b.Busy()) 420 421 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*200) 422 defer cancel() 423 f1, err := b.Send(ctx, newTestMessage(1)) 424 assert.NoError(t, err) 425 defer f1.Close() 426 427 f2, err := b.Send(ctx, newTestMessage(2)) 428 assert.NoError(t, err) 429 defer f2.Close() 430 431 assert.True(t, b.Busy()) 432 c <- struct{}{} 433 }, 434 WithBackendFilter(func(Message, string) bool { 435 if n == 0 { 436 <-c 437 n++ 438 } 439 return false 440 }), 441 WithBackendBatchSendSize(1), 442 WithBackendBufferSize(10), 443 WithBackendBusyBufferSize(1)) 444 } 445 446 func TestDoneWithClosedStreamCannotPanic(t *testing.T) { 447 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 448 defer cancel() 449 450 c := make(chan Message, 1) 451 s := newStream(c, 452 func() *Future { return newFuture(nil) }, 453 func(m *Future) error { 454 m.messageSended(nil) 455 return nil 456 }, 457 func(s *stream) {}, 458 func() {}) 459 s.init(1, false) 460 assert.NoError(t, s.Send(ctx, &testMessage{id: s.ID()})) 461 assert.NoError(t, s.Close()) 462 assert.Nil(t, <-c) 463 464 s.done(RPCMessage{}) 465 } 466 467 func TestGCStream(t *testing.T) { 468 c := make(chan Message, 1) 469 s := newStream(c, 470 func() *Future { return newFuture(nil) }, 471 func(m *Future) error { 472 return nil 473 }, 474 func(s *stream) {}, 475 func() {}) 476 s.init(1, false) 477 s = nil 478 debug.FreeOSMemory() 479 _, ok := <-c 480 assert.False(t, ok) 481 } 482 483 func TestLastActiveWithNew(t *testing.T) { 484 testBackendSend(t, 485 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 486 return nil 487 }, 488 func(b *remoteBackend) { 489 assert.NotEqual(t, time.Time{}, b.LastActiveTime()) 490 }, 491 ) 492 } 493 494 func TestLastActiveWithSend(t *testing.T) { 495 c := make(chan struct{}) 496 testBackendSend(t, 497 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 498 <-c 499 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 500 }, 501 func(b *remoteBackend) { 502 t1 := b.LastActiveTime() 503 504 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 505 defer cancel() 506 req := newTestMessage(1) 507 f, err := b.Send(ctx, req) 508 assert.NoError(t, err) 509 defer f.Close() 510 511 t2 := b.LastActiveTime() 512 assert.NotEqual(t, t1, t2) 513 assert.True(t, t2.After(t1)) 514 c <- struct{}{} 515 516 resp, err := f.Get() 517 assert.NoError(t, err) 518 assert.Equal(t, req, resp) 519 520 t3 := b.LastActiveTime() 521 assert.NotEqual(t, t2, t3) 522 assert.True(t, t3.After(t2)) 523 524 }, 525 ) 526 } 527 528 func TestLastActiveWithStream(t *testing.T) { 529 testBackendSend(t, 530 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 531 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 532 }, 533 func(b *remoteBackend) { 534 ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10) 535 defer cancel() 536 537 t1 := b.LastActiveTime() 538 539 st, err := b.NewStream(false) 540 assert.NoError(t, err) 541 defer func() { 542 assert.NoError(t, st.Close()) 543 }() 544 545 n := 1 546 for i := 0; i < n; i++ { 547 req := &testMessage{id: st.ID()} 548 assert.NoError(t, st.Send(ctx, req)) 549 t2 := b.LastActiveTime() 550 assert.NotEqual(t, t1, t2) 551 assert.True(t, t2.After(t1)) 552 } 553 }, 554 ) 555 } 556 557 func TestBackendConnectTimeout(t *testing.T) { 558 rb, err := NewRemoteBackend(testAddr, newTestCodec(), 559 WithBackendConnectTimeout(time.Millisecond*200), 560 ) 561 assert.Error(t, err) 562 assert.Nil(t, rb) 563 } 564 565 func TestInactiveAfterCannotConnect(t *testing.T) { 566 app := newTestApp(t, func(conn goetty.IOSession, msg interface{}, _ uint64) error { 567 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 568 }) 569 assert.NoError(t, app.Start()) 570 571 testBackendSendWithoutServer(t, 572 testAddr, 573 func(b *remoteBackend) { 574 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 575 defer cancel() 576 req := newTestMessage(1) 577 f, err := b.Send(ctx, req) 578 assert.NoError(t, err) 579 defer f.Close() 580 581 resp, err := f.Get() 582 assert.NoError(t, err) 583 assert.Equal(t, req, resp) 584 585 assert.NoError(t, app.Stop()) 586 var v time.Time 587 for { 588 if b.LastActiveTime() == v { 589 break 590 } 591 time.Sleep(time.Millisecond * 100) 592 } 593 }, 594 WithBackendConnectTimeout(time.Millisecond*100)) 595 } 596 597 func TestTCPProxyExample(t *testing.T) { 598 assert.NoError(t, os.RemoveAll(testProxyAddr[7:])) 599 p := goetty.NewProxy(testProxyAddr, nil) 600 assert.NoError(t, p.Start()) 601 defer func() { 602 assert.NoError(t, p.Stop()) 603 }() 604 p.AddUpStream(testAddr, time.Second*10) 605 606 testBackendSendWithAddr(t, 607 testProxyAddr, 608 func(conn goetty.IOSession, msg interface{}, _ uint64) error { 609 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 610 }, 611 func(b *remoteBackend) { 612 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 613 defer cancel() 614 req := newTestMessage(1) 615 f, err := b.Send(ctx, req) 616 assert.NoError(t, err) 617 defer f.Close() 618 619 resp, err := f.Get() 620 assert.NoError(t, err) 621 assert.Equal(t, req, resp) 622 }, 623 ) 624 } 625 626 func TestLockedStream(t *testing.T) { 627 testBackendSend(t, 628 func(conn goetty.IOSession, msg interface{}, seq uint64) error { 629 return conn.Write(msg, goetty.WriteOptions{Flush: true}) 630 }, 631 func(b *remoteBackend) { 632 assert.False(t, b.Locked()) 633 b.Lock() 634 st, err := b.NewStream(true) 635 assert.NoError(t, err) 636 assert.True(t, b.Locked()) 637 assert.NoError(t, st.Close()) 638 assert.False(t, b.Locked()) 639 }, 640 ) 641 } 642 643 func TestIssue7678(t *testing.T) { 644 s := &stream{lastReceivedSequence: 10} 645 s.init(0, false) 646 assert.Equal(t, uint32(0), s.lastReceivedSequence) 647 } 648 649 func testBackendSend(t *testing.T, 650 handleFunc func(goetty.IOSession, interface{}, uint64) error, 651 testFunc func(b *remoteBackend), 652 options ...BackendOption) { 653 testBackendSendWithAddr(t, testAddr, handleFunc, testFunc, options...) 654 } 655 656 func testBackendSendWithAddr(t *testing.T, addr string, 657 handleFunc func(goetty.IOSession, interface{}, uint64) error, 658 testFunc func(b *remoteBackend), 659 options ...BackendOption) { 660 app := newTestApp(t, handleFunc) 661 assert.NoError(t, app.Start()) 662 defer func() { 663 assert.NoError(t, app.Stop()) 664 }() 665 666 testBackendSendWithoutServer(t, addr, testFunc, options...) 667 } 668 669 func testBackendSendWithoutServer(t *testing.T, addr string, 670 testFunc func(b *remoteBackend), 671 options ...BackendOption) { 672 673 options = append(options, 674 WithBackendBufferSize(1), 675 WithBackendLogger(logutil.GetPanicLoggerWithLevel(zap.DebugLevel).With(zap.String("testcase", t.Name())))) 676 rb, err := NewRemoteBackend(addr, newTestCodec(), options...) 677 assert.NoError(t, err) 678 679 b := rb.(*remoteBackend) 680 defer func() { 681 b.Close() 682 assert.False(t, b.conn.Connected()) 683 }() 684 testFunc(b) 685 } 686 687 func newTestApp(t *testing.T, 688 handleFunc func(goetty.IOSession, interface{}, uint64) error, 689 opts ...goetty.AppOption) goetty.NetApplication { 690 assert.NoError(t, os.RemoveAll(testUnixFile)) 691 codec := newTestCodec().(*messageCodec) 692 opts = append(opts, goetty.WithAppSessionOptions(goetty.WithSessionCodec(codec))) 693 app, err := goetty.NewApplication(testAddr, handleFunc, opts...) 694 assert.NoError(t, err) 695 696 return app 697 } 698 699 type testBackendFactory struct { 700 sync.RWMutex 701 id int 702 } 703 704 func newTestBackendFactory() *testBackendFactory { 705 return &testBackendFactory{} 706 } 707 708 func (bf *testBackendFactory) Create(backend string) (Backend, error) { 709 bf.Lock() 710 defer bf.Unlock() 711 b := &testBackend{id: bf.id} 712 b.activeTime = time.Now() 713 bf.id++ 714 return b, nil 715 } 716 717 type testBackend struct { 718 sync.RWMutex 719 id int 720 busy bool 721 activeTime time.Time 722 closed bool 723 locked bool 724 } 725 726 func (b *testBackend) Send(ctx context.Context, request Message) (*Future, error) { 727 b.active() 728 f := newFuture(nil) 729 f.init(RPCMessage{Ctx: ctx, Message: request}) 730 return f, nil 731 } 732 733 func (b *testBackend) SendInternal(ctx context.Context, request Message) (*Future, error) { 734 b.active() 735 f := newFuture(nil) 736 f.init(RPCMessage{Ctx: ctx, Message: request}) 737 return f, nil 738 } 739 740 func (b *testBackend) NewStream(unlockAfterClose bool) (Stream, error) { 741 b.active() 742 st := newStream(make(chan Message, 1), 743 func() *Future { return newFuture(nil) }, 744 func(m *Future) error { 745 m.messageSended(nil) 746 return nil 747 }, 748 func(s *stream) { 749 if s.unlockAfterClose { 750 b.Unlock() 751 } 752 }, 753 b.active) 754 st.init(1, false) 755 return st, nil 756 } 757 758 func (b *testBackend) Close() { 759 b.RWMutex.Lock() 760 defer b.RWMutex.Unlock() 761 b.closed = true 762 } 763 func (b *testBackend) Busy() bool { return b.busy } 764 func (b *testBackend) LastActiveTime() time.Time { 765 b.RLock() 766 defer b.RUnlock() 767 return b.activeTime 768 } 769 770 func (b *testBackend) Lock() { 771 b.RWMutex.Lock() 772 defer b.RWMutex.Unlock() 773 if b.locked { 774 panic("backend is already locked") 775 } 776 b.locked = true 777 } 778 779 func (b *testBackend) Unlock() { 780 b.RWMutex.Lock() 781 defer b.RWMutex.Unlock() 782 if !b.locked { 783 panic("backend is not locked") 784 } 785 b.locked = false 786 } 787 788 func (b *testBackend) Locked() bool { 789 b.RLock() 790 defer b.RUnlock() 791 return b.locked 792 } 793 794 func (b *testBackend) active() { 795 b.RWMutex.Lock() 796 defer b.RWMutex.Unlock() 797 b.activeTime = time.Now() 798 } 799 800 type testMessage struct { 801 id uint64 802 payload []byte 803 } 804 805 func newTestMessage(id uint64) *testMessage { 806 return &testMessage{id: id} 807 } 808 809 func (tm *testMessage) SetID(id uint64) { 810 tm.id = id 811 } 812 813 func (tm *testMessage) GetID() uint64 { 814 return tm.id 815 } 816 817 func (tm *testMessage) DebugString() string { 818 return fmt.Sprintf("%d:%d", tm.id, len(tm.payload)) 819 } 820 821 func (tm *testMessage) Size() int { 822 return 8 + len(tm.payload) 823 } 824 825 func (tm *testMessage) MarshalTo(data []byte) (int, error) { 826 buf.Uint64ToBytesTo(tm.id, data) 827 return 8, nil 828 } 829 830 func (tm *testMessage) Unmarshal(data []byte) error { 831 tm.id = buf.Byte2Uint64(data) 832 return nil 833 } 834 835 func (tm *testMessage) GetPayloadField() []byte { 836 return tm.payload 837 } 838 839 func (tm *testMessage) SetPayloadField(data []byte) { 840 tm.payload = data 841 } 842 843 func newTestCodec(options ...CodecOption) Codec { 844 options = append(options, 845 WithCodecPayloadCopyBufferSize(1024)) 846 return NewMessageCodec(func() Message { return messagePool.Get().(*testMessage) }, options...) 847 } 848 849 var ( 850 messagePool = sync.Pool{ 851 New: func() any { 852 return newTestMessage(0) 853 }, 854 } 855 )