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  )