github.com/matrixorigin/matrixone@v1.2.0/pkg/clusterservice/cluster_test.go (about)

     1  // Copyright 2023 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 clusterservice
    16  
    17  import (
    18  	"context"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    24  	logpb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    25  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    26  	"github.com/mohae/deepcopy"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestClusterReady(t *testing.T) {
    32  	runClusterTest(
    33  		time.Hour,
    34  		func(hc *testHAKeeperClient, c *cluster) {
    35  			cc := make(chan struct{})
    36  			go func() {
    37  				defer close(cc)
    38  				c.GetCNService(NewSelector(), nil)
    39  			}()
    40  			select {
    41  			case <-cc:
    42  			case <-time.After(time.Second * 5):
    43  				assert.Fail(t, "wait ready timeout")
    44  			}
    45  		})
    46  }
    47  
    48  func TestClusterForceRefresh(t *testing.T) {
    49  	runClusterTest(
    50  		time.Hour,
    51  		func(hc *testHAKeeperClient, c *cluster) {
    52  			cnt := 0
    53  			apply := func(c metadata.CNService) bool {
    54  				cnt++
    55  				return true
    56  			}
    57  			c.GetCNService(NewServiceIDSelector("cn0"), apply)
    58  			assert.Equal(t, 0, cnt)
    59  
    60  			hc.addCN("cn0")
    61  			cnt = 0
    62  			c.ForceRefresh(true)
    63  			c.GetCNService(NewServiceIDSelector("cn0"), apply)
    64  			assert.Equal(t, 1, cnt)
    65  		})
    66  }
    67  
    68  func TestClusterRefresh(t *testing.T) {
    69  	runClusterTest(
    70  		time.Millisecond*10,
    71  		func(hc *testHAKeeperClient, c *cluster) {
    72  			cnt := 0
    73  			apply := func(c metadata.TNService) bool {
    74  				cnt++
    75  				return true
    76  			}
    77  			c.GetTNService(NewServiceIDSelector("dn0"), apply)
    78  			assert.Equal(t, 0, cnt)
    79  
    80  			hc.addTN("dn0")
    81  			time.Sleep(time.Millisecond * 100)
    82  			c.GetTNService(NewServiceIDSelector("dn0"), apply)
    83  			assert.Equal(t, 1, cnt)
    84  		})
    85  }
    86  
    87  func BenchmarkGetService(b *testing.B) {
    88  	runClusterTest(
    89  		time.Hour,
    90  		func(hc *testHAKeeperClient, c *cluster) {
    91  			cnt := 0
    92  			apply := func(c metadata.TNService) bool {
    93  				cnt++
    94  				return true
    95  			}
    96  			c.GetTNService(NewServiceIDSelector("dn0"), apply)
    97  
    98  			hc.addTN("dn0")
    99  			c.ForceRefresh(true)
   100  
   101  			b.ResetTimer()
   102  			for i := 0; i < b.N; i++ {
   103  				c.GetTNService(NewServiceIDSelector("dn0"), apply)
   104  			}
   105  		})
   106  }
   107  
   108  func TestCluster_DebugUpdateCNLabel(t *testing.T) {
   109  	runClusterTest(
   110  		time.Hour,
   111  		func(hc *testHAKeeperClient, c *cluster) {
   112  			var cns []metadata.CNService
   113  			apply := func(c metadata.CNService) bool {
   114  				cns = append(cns, c)
   115  				return true
   116  			}
   117  			hc.addCN("cn0")
   118  			err := c.DebugUpdateCNLabel("cn0", map[string][]string{"k1": {"v1"}})
   119  			require.NoError(t, err)
   120  			c.ForceRefresh(true)
   121  			c.GetCNService(NewServiceIDSelector("cn0"), apply)
   122  			require.Equal(t, 1, len(cns))
   123  			require.Equal(t, "cn0", cns[0].ServiceID)
   124  			require.Equal(t, map[string]metadata.LabelList{
   125  				"k1": {Labels: []string{"v1"}},
   126  			}, cns[0].Labels)
   127  		})
   128  }
   129  
   130  func runClusterTest(
   131  	refreshInterval time.Duration,
   132  	fn func(*testHAKeeperClient, *cluster)) {
   133  	runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
   134  	hc := &testHAKeeperClient{}
   135  	c := NewMOCluster(hc, refreshInterval)
   136  	defer c.Close()
   137  	fn(hc, c.(*cluster))
   138  }
   139  
   140  type testHAKeeperClient struct {
   141  	sync.RWMutex
   142  	value logpb.ClusterDetails
   143  	err   error
   144  }
   145  
   146  func (c *testHAKeeperClient) addCN(serviceIDs ...string) {
   147  	c.Lock()
   148  	defer c.Unlock()
   149  	for _, id := range serviceIDs {
   150  		c.value.CNStores = append(c.value.CNStores, logpb.CNStore{
   151  			UUID:      id,
   152  			WorkState: metadata.WorkState_Working,
   153  		})
   154  	}
   155  }
   156  
   157  func (c *testHAKeeperClient) addTN(serviceIDs ...string) {
   158  	c.Lock()
   159  	defer c.Unlock()
   160  	for _, id := range serviceIDs {
   161  		c.value.TNStores = append(c.value.TNStores, logpb.TNStore{
   162  			UUID: id,
   163  		})
   164  	}
   165  }
   166  
   167  func (c *testHAKeeperClient) Close() error                                   { return nil }
   168  func (c *testHAKeeperClient) AllocateID(ctx context.Context) (uint64, error) { return 0, nil }
   169  func (c *testHAKeeperClient) AllocateIDByKey(ctx context.Context, key string) (uint64, error) {
   170  	return 0, nil
   171  }
   172  func (c *testHAKeeperClient) GetClusterDetails(ctx context.Context) (logpb.ClusterDetails, error) {
   173  	c.RLock()
   174  	defer c.RUnlock()
   175  	// deep copy the cluster details to avoid data race.
   176  	copied := deepcopy.Copy(c.value)
   177  	return copied.(logpb.ClusterDetails), c.err
   178  }
   179  func (c *testHAKeeperClient) GetClusterState(ctx context.Context) (logpb.CheckerState, error) {
   180  	return logpb.CheckerState{}, nil
   181  }
   182  func (c *testHAKeeperClient) GetCNState(ctx context.Context) (logpb.CNState, error) {
   183  	return logpb.CNState{}, nil
   184  }
   185  func (c *testHAKeeperClient) UpdateCNLabel(ctx context.Context, label logpb.CNStoreLabel) error {
   186  	c.Lock()
   187  	defer c.Unlock()
   188  	for i, cn := range c.value.CNStores {
   189  		if cn.UUID == label.UUID {
   190  			c.value.CNStores[i].Labels = label.Labels
   191  		}
   192  	}
   193  	return nil
   194  }
   195  func (c *testHAKeeperClient) UpdateCNWorkState(ctx context.Context, state logpb.CNWorkState) error {
   196  	c.Lock()
   197  	defer c.Unlock()
   198  	for i, cn := range c.value.CNStores {
   199  		if cn.UUID == state.UUID {
   200  			c.value.CNStores[i].WorkState = state.State
   201  		}
   202  	}
   203  	return nil
   204  }