github.com/matrixorigin/matrixone@v1.2.0/pkg/common/morpc/client_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  	"testing"
    20  	"time"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  func TestCreateBackendLocked(t *testing.T) {
    26  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(1))
    27  	assert.NoError(t, err)
    28  	c := rc.(*client)
    29  	defer func() {
    30  		assert.NoError(t, c.Close())
    31  	}()
    32  
    33  	b, err := c.createBackendLocked("b1")
    34  	assert.NoError(t, err)
    35  	assert.Equal(t, 1, len(c.mu.backends["b1"]))
    36  	assert.NotNil(t, b)
    37  
    38  	b, err = c.createBackendLocked("b1")
    39  	assert.Error(t, err)
    40  	assert.Nil(t, b)
    41  	assert.Equal(t, 1, len(c.mu.backends["b1"]))
    42  }
    43  
    44  func TestGetBackendLockedWithClosed(t *testing.T) {
    45  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(1))
    46  	assert.NoError(t, err)
    47  	c := rc.(*client)
    48  	assert.NoError(t, c.Close())
    49  
    50  	b, err := c.getBackendLocked("b1", false)
    51  	assert.Error(t, err)
    52  	assert.Nil(t, b)
    53  }
    54  
    55  func TestGetBackendLockedWithEmptyBackends(t *testing.T) {
    56  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(1 /*disable create*/))
    57  	assert.NoError(t, err)
    58  	c := rc.(*client)
    59  	defer func() {
    60  		assert.NoError(t, c.Close())
    61  	}()
    62  
    63  	b, err := c.getBackendLocked("b1", false)
    64  	assert.NoError(t, err)
    65  	assert.Nil(t, b)
    66  }
    67  
    68  func TestGetBackend(t *testing.T) {
    69  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(1))
    70  	assert.NoError(t, err)
    71  	c := rc.(*client)
    72  	defer func() {
    73  		assert.NoError(t, c.Close())
    74  	}()
    75  
    76  	n := 2
    77  	for i := 0; i < n; i++ {
    78  		c.mu.backends["b1"] = append(c.mu.backends["b1"], &testBackend{id: i, busy: false, activeTime: time.Now()})
    79  	}
    80  	c.mu.ops["b1"] = &op{}
    81  
    82  	for i := 0; i < n; i++ {
    83  		b, err := c.getBackend("b1", false)
    84  		assert.NoError(t, err)
    85  		assert.Equal(t, c.mu.backends["b1"][(i+1)%n], b)
    86  	}
    87  }
    88  
    89  func TestCannotGetLocedBackend(t *testing.T) {
    90  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(1))
    91  	assert.NoError(t, err)
    92  	c := rc.(*client)
    93  	defer func() {
    94  		assert.NoError(t, c.Close())
    95  	}()
    96  
    97  	n := 10
    98  	for i := 0; i < n; i++ {
    99  		c.mu.backends["b1"] = append(c.mu.backends["b1"], &testBackend{id: i, locked: i == 0, busy: false, activeTime: time.Now()})
   100  	}
   101  	c.mu.ops["b1"] = &op{}
   102  
   103  	for i := 0; i < n; i++ {
   104  		b, err := c.getBackend("b1", false)
   105  		assert.NoError(t, err)
   106  		assert.False(t, b.Locked())
   107  	}
   108  }
   109  
   110  func TestCanGetBackendIfALLLockedAndNotReachMaxPerHost(t *testing.T) {
   111  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(3))
   112  	assert.NoError(t, err)
   113  	c := rc.(*client)
   114  	defer func() {
   115  		assert.NoError(t, c.Close())
   116  	}()
   117  
   118  	c.mu.backends["b1"] = append(c.mu.backends["b1"],
   119  		&testBackend{id: 1, locked: true, busy: false, activeTime: time.Now()},
   120  		&testBackend{id: 2, locked: true, busy: false, activeTime: time.Now()})
   121  	c.mu.ops["b1"] = &op{}
   122  
   123  	b, err := c.getBackend("b1", false)
   124  	assert.NoError(t, err)
   125  	assert.False(t, b.Locked())
   126  }
   127  
   128  func TestMaybeCreateLockedWithEmptyBackends(t *testing.T) {
   129  	rc, err := NewClient("",
   130  		newTestBackendFactory(),
   131  		WithClientMaxBackendPerHost(1),
   132  		WithClientEnableAutoCreateBackend())
   133  	assert.NoError(t, err)
   134  	c := rc.(*client)
   135  	defer func() {
   136  		assert.NoError(t, c.Close())
   137  	}()
   138  
   139  	assert.True(t, c.maybeCreateLocked("b1"))
   140  }
   141  
   142  func TestMaybeCreateLockedWithNotFullBackendsAndHasAnyBusy(t *testing.T) {
   143  	rc, err := NewClient("",
   144  		newTestBackendFactory(),
   145  		WithClientMaxBackendPerHost(3),
   146  		WithClientEnableAutoCreateBackend())
   147  	assert.NoError(t, err)
   148  	c := rc.(*client)
   149  	defer func() {
   150  		assert.NoError(t, c.Close())
   151  	}()
   152  	c.mu.backends["b1"] = []Backend{
   153  		&testBackend{busy: false},
   154  		&testBackend{busy: true},
   155  	}
   156  	assert.True(t, c.maybeCreateLocked("b1"))
   157  }
   158  
   159  func TestMaybeCreateLockedWithNotFullBackendsAndNoBusy(t *testing.T) {
   160  	rc, err := NewClient("", newTestBackendFactory(), WithClientMaxBackendPerHost(3))
   161  	assert.NoError(t, err)
   162  	c := rc.(*client)
   163  	defer func() {
   164  		assert.NoError(t, c.Close())
   165  	}()
   166  	c.mu.backends["b1"] = []Backend{
   167  		&testBackend{busy: false},
   168  	}
   169  	assert.False(t, c.maybeCreateLocked("b1"))
   170  }
   171  
   172  func TestMaybeCreateLockedWithFullBackends(t *testing.T) {
   173  	rc, err := NewClient("",
   174  		newTestBackendFactory(),
   175  		WithClientMaxBackendPerHost(1),
   176  		WithClientEnableAutoCreateBackend())
   177  	assert.NoError(t, err)
   178  	c := rc.(*client)
   179  	defer func() {
   180  		assert.NoError(t, c.Close())
   181  	}()
   182  	c.mu.backends["b1"] = []Backend{
   183  		&testBackend{busy: false},
   184  	}
   185  	assert.False(t, c.maybeCreateLocked("b1"))
   186  }
   187  
   188  func TestInitBackendsAndMaxBackendsPerHostNotMatch(t *testing.T) {
   189  	rc, err := NewClient(
   190  		"",
   191  		newTestBackendFactory(),
   192  		WithClientCreateTaskChanSize(2),
   193  		WithClientInitBackends([]string{"b1", "b2"}, []int{3, 1}))
   194  	assert.NoError(t, err)
   195  	c := rc.(*client)
   196  	defer func() {
   197  		assert.NoError(t, c.Close())
   198  	}()
   199  
   200  	assert.Equal(t, 3, c.options.maxBackendsPerHost)
   201  }
   202  
   203  func TestGetBackendWithCreateBackend(t *testing.T) {
   204  	rc, err := NewClient(
   205  		"",
   206  		newTestBackendFactory(),
   207  		WithClientCreateTaskChanSize(1))
   208  	assert.NoError(t, err)
   209  	c := rc.(*client)
   210  	defer func() {
   211  		assert.NoError(t, c.Close())
   212  	}()
   213  
   214  	b, err := c.getBackend("b1", false)
   215  	assert.NoError(t, err)
   216  	assert.NotNil(t, b)
   217  	assert.Equal(t, 1, len(c.mu.backends["b1"]))
   218  }
   219  
   220  func TestCloseIdleBackends(t *testing.T) {
   221  	rc, err := NewClient(
   222  		"",
   223  		newTestBackendFactory(),
   224  		WithClientMaxBackendPerHost(2),
   225  		WithClientMaxBackendMaxIdleDuration(time.Millisecond*100),
   226  		WithClientCreateTaskChanSize(1),
   227  		WithClientEnableAutoCreateBackend())
   228  	assert.NoError(t, err)
   229  	c := rc.(*client)
   230  	defer func() {
   231  		assert.NoError(t, c.Close())
   232  	}()
   233  
   234  	b, err := c.getBackend("b1", false)
   235  	assert.NoError(t, err)
   236  	assert.NotNil(t, b)
   237  	b.(*testBackend).busy = true
   238  
   239  	_, err = c.getBackend("b1", false)
   240  	assert.NoError(t, err)
   241  	for {
   242  		c.mu.Lock()
   243  		v := len(c.mu.backends["b1"])
   244  		c.mu.Unlock()
   245  		if v == 2 {
   246  			break
   247  		}
   248  		time.Sleep(time.Millisecond * 10)
   249  	}
   250  
   251  	b, err = c.getBackend("b1", false)
   252  	assert.NoError(t, err)
   253  	assert.NotNil(t, b)
   254  
   255  	b2, err := c.getBackend("b1", false)
   256  	assert.NoError(t, err)
   257  	assert.NotNil(t, b2)
   258  	assert.NotEqual(t, b, b2)
   259  
   260  	go func() {
   261  		ctx, cancel := context.WithTimeout(context.TODO(), time.Second*10)
   262  		defer cancel()
   263  		st, err := b2.NewStream(false)
   264  		assert.NoError(t, err)
   265  		for {
   266  			assert.NoError(t, st.Send(ctx, newTestMessage(1)))
   267  			time.Sleep(time.Millisecond * 10)
   268  		}
   269  	}()
   270  
   271  	for {
   272  		c.mu.Lock()
   273  		v := len(c.mu.backends["b1"])
   274  		c.mu.Unlock()
   275  		if v == 1 {
   276  			tb := b.(*testBackend)
   277  			tb.RLock()
   278  			closed := tb.closed
   279  			tb.RUnlock()
   280  			if closed {
   281  				tb2 := b2.(*testBackend)
   282  				tb2.RLock()
   283  				assert.False(t, tb2.closed)
   284  				tb2.RUnlock()
   285  
   286  				c.mu.Lock()
   287  				assert.Equal(t, 1, len(c.mu.backends["b1"]))
   288  				c.mu.Unlock()
   289  				return
   290  			}
   291  		}
   292  		time.Sleep(time.Millisecond * 10)
   293  	}
   294  }
   295  
   296  func TestLockedBackendCannotClosedWithGCIdleTask(t *testing.T) {
   297  	rc, err := NewClient(
   298  		"",
   299  		newTestBackendFactory(),
   300  		WithClientMaxBackendPerHost(2),
   301  		WithClientMaxBackendMaxIdleDuration(time.Millisecond*100),
   302  		WithClientCreateTaskChanSize(1))
   303  	assert.NoError(t, err)
   304  	c := rc.(*client)
   305  	defer func() {
   306  		assert.NoError(t, c.Close())
   307  	}()
   308  
   309  	b, err := c.getBackend("b1", true)
   310  	assert.NoError(t, err)
   311  	assert.NotNil(t, b)
   312  	assert.True(t, b.Locked())
   313  	b.(*testBackend).RWMutex.Lock()
   314  	b.(*testBackend).activeTime = time.Time{}
   315  	b.(*testBackend).RWMutex.Unlock()
   316  
   317  	time.Sleep(time.Second * 1)
   318  	c.mu.Lock()
   319  	assert.Equal(t, 1, len(c.mu.backends["b1"]))
   320  	c.mu.Unlock()
   321  }
   322  
   323  func TestGetBackendsWithAllInactiveAndWillCreateNew(t *testing.T) {
   324  	rc, err := NewClient(
   325  		"",
   326  		newTestBackendFactory(),
   327  		WithClientMaxBackendPerHost(1),
   328  		WithClientCreateTaskChanSize(1))
   329  	assert.NoError(t, err)
   330  	c := rc.(*client)
   331  	defer func() {
   332  		assert.NoError(t, c.Close())
   333  	}()
   334  
   335  	b, err := c.getBackend("b1", false)
   336  	assert.NoError(t, err)
   337  	assert.NotNil(t, b)
   338  
   339  	b.(*testBackend).activeTime = time.Time{}
   340  	b, _ = c.getBackend("b1", false)
   341  	assert.Nil(t, b)
   342  
   343  	for {
   344  		b, err := c.getBackend("b1", false)
   345  		if err == nil {
   346  			assert.NotNil(t, b)
   347  			return
   348  		}
   349  	}
   350  }