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 }