github.com/matrixorigin/matrixone@v1.2.0/pkg/logservice/hakeeper_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 logservice 16 17 import ( 18 "context" 19 "sync" 20 "testing" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 24 25 "github.com/google/uuid" 26 "github.com/lni/dragonboat/v4" 27 "github.com/lni/goutils/leaktest" 28 "github.com/lni/vfs" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 32 "github.com/matrixorigin/matrixone/pkg/common/moerr" 33 "github.com/matrixorigin/matrixone/pkg/common/morpc" 34 "github.com/matrixorigin/matrixone/pkg/hakeeper" 35 pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 36 ) 37 38 func TestHAKeeperClientConfigIsValidated(t *testing.T) { 39 cfg := HAKeeperClientConfig{} 40 cc1, err := NewCNHAKeeperClient(context.TODO(), cfg) 41 assert.Nil(t, cc1) 42 assert.Error(t, err) 43 cc2, err := NewTNHAKeeperClient(context.TODO(), cfg) 44 assert.Nil(t, cc2) 45 assert.Error(t, err) 46 cc3, err := NewLogHAKeeperClient(context.TODO(), cfg) 47 assert.Nil(t, cc3) 48 assert.Error(t, err) 49 } 50 51 func TestHAKeeperClientsCanBeCreated(t *testing.T) { 52 fn := func(t *testing.T, s *Service) { 53 cfg := HAKeeperClientConfig{ 54 ServiceAddresses: []string{testServiceAddress}, 55 } 56 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 57 defer cancel() 58 c1, err := NewCNHAKeeperClient(ctx, cfg) 59 require.NoError(t, err) 60 assert.NoError(t, c1.Close()) 61 c2, err := NewTNHAKeeperClient(ctx, cfg) 62 assert.NoError(t, err) 63 assert.NoError(t, c2.Close()) 64 c3, err := NewLogHAKeeperClient(ctx, cfg) 65 assert.NoError(t, err) 66 assert.NoError(t, c3.Close()) 67 } 68 runServiceTest(t, true, true, fn) 69 } 70 71 func TestHAKeeperClientCanNotConnectToNonHAKeeperNode(t *testing.T) { 72 fn := func(t *testing.T, s *Service) { 73 cfg := HAKeeperClientConfig{ 74 ServiceAddresses: []string{testServiceAddress}, 75 } 76 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 77 defer cancel() 78 _, err := NewCNHAKeeperClient(ctx, cfg) 79 require.True(t, moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper)) 80 _, err = NewTNHAKeeperClient(ctx, cfg) 81 require.True(t, moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper)) 82 _, err = NewLogHAKeeperClient(ctx, cfg) 83 require.True(t, moerr.IsMoErrCode(err, moerr.ErrNoHAKeeper)) 84 } 85 runServiceTest(t, false, true, fn) 86 } 87 88 func TestHAKeeperClientConnectByReverseProxy(t *testing.T) { 89 fn := func(t *testing.T, s *Service) { 90 done := false 91 for i := 0; i < 1000; i++ { 92 si, ok, err := GetShardInfo(testServiceAddress, hakeeper.DefaultHAKeeperShardID) 93 if err != nil || !ok { 94 time.Sleep(10 * time.Millisecond) 95 continue 96 } 97 done = true 98 require.NoError(t, err) 99 assert.True(t, ok) 100 assert.Equal(t, uint64(1), si.ReplicaID) 101 addr, ok := si.Replicas[si.ReplicaID] 102 assert.True(t, ok) 103 assert.Equal(t, testServiceAddress, addr) 104 break 105 } 106 if !done { 107 t.Fatalf("failed to get shard info") 108 } 109 // now shard info can be queried 110 cfg := HAKeeperClientConfig{ 111 ServiceAddresses: []string{"localhost:53033"}, // obvious not reachable 112 DiscoveryAddress: testServiceAddress, 113 } 114 ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) 115 defer cancel() 116 c, err := NewLogHAKeeperClient(ctx, cfg) 117 require.NoError(t, err) 118 defer func() { 119 assert.NoError(t, c.Close()) 120 }() 121 122 hb := s.store.getHeartbeatMessage() 123 cb, err := c.SendLogHeartbeat(ctx, hb) 124 require.NoError(t, err) 125 assert.Equal(t, 0, len(cb.Commands)) 126 127 sc := pb.ScheduleCommand{ 128 UUID: s.ID(), 129 ServiceType: pb.TNService, 130 ShutdownStore: &pb.ShutdownStore{ 131 StoreID: "hello world", 132 }, 133 } 134 require.NoError(t, s.store.addScheduleCommands(ctx, 0, []pb.ScheduleCommand{sc})) 135 cb, err = c.SendLogHeartbeat(ctx, hb) 136 require.NoError(t, err) 137 require.Equal(t, 1, len(cb.Commands)) 138 require.Equal(t, sc, cb.Commands[0]) 139 } 140 runServiceTest(t, true, true, fn) 141 } 142 143 func TestHAKeeperClientSendCNHeartbeat(t *testing.T) { 144 fn := func(t *testing.T, s *Service) { 145 cfg := HAKeeperClientConfig{ 146 ServiceAddresses: []string{testServiceAddress}, 147 } 148 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 149 defer cancel() 150 c1, err := NewCNHAKeeperClient(ctx, cfg) 151 require.NoError(t, err) 152 defer func() { 153 assert.NoError(t, c1.Close()) 154 }() 155 156 // should be transparently handled 157 cc := c1.(*managedHAKeeperClient) 158 assert.NoError(t, cc.mu.client.close()) 159 cc.mu.client = nil 160 161 hb := pb.CNStoreHeartbeat{ 162 UUID: s.ID(), 163 ServiceAddress: "addr1", 164 } 165 _, err = c1.SendCNHeartbeat(ctx, hb) 166 require.NoError(t, err) 167 168 c2, err := NewTNHAKeeperClient(ctx, cfg) 169 require.NoError(t, err) 170 defer func() { 171 assert.NoError(t, c2.Close()) 172 }() 173 174 // should be transparently handled 175 cc = c2.(*managedHAKeeperClient) 176 assert.NoError(t, cc.mu.client.close()) 177 cc.mu.client = nil 178 179 hb2 := pb.TNStoreHeartbeat{ 180 UUID: s.ID(), 181 ServiceAddress: "addr2", 182 LogtailServerAddress: "addr3", 183 } 184 cb, err := c2.SendTNHeartbeat(ctx, hb2) 185 require.NoError(t, err) 186 assert.Equal(t, 0, len(cb.Commands)) 187 188 // should be transparently handled 189 cc = c1.(*managedHAKeeperClient) 190 assert.NoError(t, cc.mu.client.close()) 191 cc.mu.client = nil 192 193 cd, err := c1.GetClusterDetails(ctx) 194 require.NoError(t, err) 195 cn := pb.CNStore{ 196 UUID: s.ID(), 197 ServiceAddress: "addr1", 198 WorkState: metadata.WorkState_Working, 199 UpTime: cd.CNStores[0].UpTime, 200 } 201 tn := pb.TNStore{ 202 UUID: s.ID(), 203 ServiceAddress: "addr2", 204 LogtailServerAddress: "addr3", 205 } 206 assert.Equal(t, []pb.CNStore{cn}, cd.CNStores) 207 assert.Equal(t, []pb.TNStore{tn}, cd.TNStores) 208 } 209 runServiceTest(t, true, true, fn) 210 } 211 212 func TestHAKeeperClientSendTNHeartbeat(t *testing.T) { 213 fn := func(t *testing.T, s *Service) { 214 cfg := HAKeeperClientConfig{ 215 ServiceAddresses: []string{testServiceAddress}, 216 } 217 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 218 defer cancel() 219 c, err := NewTNHAKeeperClient(ctx, cfg) 220 require.NoError(t, err) 221 defer func() { 222 assert.NoError(t, c.Close()) 223 }() 224 hb := pb.TNStoreHeartbeat{ 225 UUID: s.ID(), 226 } 227 cb, err := c.SendTNHeartbeat(ctx, hb) 228 require.NoError(t, err) 229 assert.Equal(t, 0, len(cb.Commands)) 230 231 sc := pb.ScheduleCommand{ 232 UUID: s.ID(), 233 ServiceType: pb.TNService, 234 ShutdownStore: &pb.ShutdownStore{ 235 StoreID: "hello world", 236 }, 237 } 238 require.NoError(t, s.store.addScheduleCommands(ctx, 0, []pb.ScheduleCommand{sc})) 239 cb, err = c.SendTNHeartbeat(ctx, hb) 240 require.NoError(t, err) 241 require.Equal(t, 1, len(cb.Commands)) 242 require.Equal(t, sc, cb.Commands[0]) 243 } 244 runServiceTest(t, true, true, fn) 245 } 246 247 func TestHAKeeperClientSendLogHeartbeat(t *testing.T) { 248 fn := func(t *testing.T, s *Service) { 249 cfg := HAKeeperClientConfig{ 250 ServiceAddresses: []string{testServiceAddress}, 251 } 252 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 253 defer cancel() 254 c, err := NewLogHAKeeperClient(ctx, cfg) 255 require.NoError(t, err) 256 defer func() { 257 assert.NoError(t, c.Close()) 258 }() 259 260 // should be transparently handled 261 cc := c.(*managedHAKeeperClient) 262 assert.NoError(t, cc.mu.client.close()) 263 cc.mu.client = nil 264 265 hb := s.store.getHeartbeatMessage() 266 cb, err := c.SendLogHeartbeat(ctx, hb) 267 require.NoError(t, err) 268 assert.Equal(t, 0, len(cb.Commands)) 269 270 sc := pb.ScheduleCommand{ 271 UUID: s.ID(), 272 ServiceType: pb.TNService, 273 ShutdownStore: &pb.ShutdownStore{ 274 StoreID: "hello world", 275 }, 276 } 277 require.NoError(t, s.store.addScheduleCommands(ctx, 0, []pb.ScheduleCommand{sc})) 278 cb, err = c.SendLogHeartbeat(ctx, hb) 279 require.NoError(t, err) 280 require.Equal(t, 1, len(cb.Commands)) 281 require.Equal(t, sc, cb.Commands[0]) 282 } 283 runServiceTest(t, true, true, fn) 284 } 285 286 func testNotHAKeeperErrorIsHandled(t *testing.T, fn func(*testing.T, *managedHAKeeperClient)) { 287 defer leaktest.AfterTest(t)() 288 cfg1 := DefaultConfig() 289 cfg1.UUID = uuid.New().String() 290 cfg1.FS = vfs.NewStrictMem() 291 cfg1.DeploymentID = 1 292 cfg1.RTTMillisecond = 5 293 cfg1.DataDir = "data-1" 294 cfg1.LogServicePort = 9002 295 cfg1.RaftPort = 9000 296 cfg1.GossipPort = 9001 297 cfg1.GossipSeedAddresses = []string{"127.0.0.1:9011"} 298 cfg1.DisableWorkers = true 299 cfg2 := DefaultConfig() 300 cfg2.UUID = uuid.New().String() 301 cfg2.FS = vfs.NewStrictMem() 302 cfg2.DeploymentID = 1 303 cfg2.RTTMillisecond = 5 304 cfg2.DataDir = "data-2" 305 cfg2.LogServicePort = 9012 306 cfg2.RaftPort = 9010 307 cfg2.GossipPort = 9011 308 cfg2.GossipSeedAddresses = []string{"127.0.0.1:9001"} 309 cfg2.DisableWorkers = true 310 service1, err := NewService(cfg1, 311 newFS(), 312 nil, 313 WithBackendFilter(func(msg morpc.Message, backendAddr string) bool { 314 return true 315 }), 316 ) 317 require.NoError(t, err) 318 defer func() { 319 assert.NoError(t, service1.Close()) 320 }() 321 service2, err := NewService(cfg2, 322 newFS(), 323 nil, 324 WithBackendFilter(func(msg morpc.Message, backendAddr string) bool { 325 return true 326 }), 327 ) 328 require.NoError(t, err) 329 defer func() { 330 assert.NoError(t, service2.Close()) 331 }() 332 // service2 is HAKeeper 333 peers := make(map[uint64]dragonboat.Target) 334 peers[1] = service2.ID() 335 assert.NoError(t, service2.store.startHAKeeperReplica(1, peers, false)) 336 // manually construct a HAKeeper client that is connected to service1 337 pool := &sync.Pool{} 338 pool.New = func() interface{} { 339 return &RPCRequest{pool: pool} 340 } 341 respPool := &sync.Pool{} 342 respPool.New = func() interface{} { 343 return &RPCResponse{pool: respPool} 344 } 345 cfg := HAKeeperClientConfig{ 346 ServiceAddresses: []string{cfg1.LogServiceServiceAddr(), cfg2.LogServiceServiceAddr()}, 347 } 348 c := &hakeeperClient{ 349 cfg: cfg, 350 pool: pool, 351 respPool: respPool, 352 } 353 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 354 defer cancel() 355 cc, err := getRPCClient( 356 ctx, 357 cfg1.LogServiceServiceAddr(), 358 c.respPool, 359 defaultMaxMessageSize, 360 false, 361 0, 362 ) 363 require.NoError(t, err) 364 c.addr = cfg1.LogServiceServiceAddr() 365 c.client = cc 366 client := &managedHAKeeperClient{cfg: cfg} 367 client.mu.client = c 368 defer func() { 369 require.NoError(t, client.Close()) 370 }() 371 fn(t, client) 372 } 373 374 func TestGetClusterDetailsWhenNotConnectedToHAKeeper(t *testing.T) { 375 fn := func(t *testing.T, c *managedHAKeeperClient) { 376 oldc := c.mu.client 377 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 378 defer cancel() 379 _, err := c.GetClusterDetails(ctx) 380 require.NoError(t, err) 381 require.True(t, oldc != c.mu.client) 382 } 383 testNotHAKeeperErrorIsHandled(t, fn) 384 } 385 386 func TestSendCNHeartbeatWhenNotConnectedToHAKeeper(t *testing.T) { 387 fn := func(t *testing.T, c *managedHAKeeperClient) { 388 oldc := c.mu.client 389 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 390 defer cancel() 391 _, err := c.SendCNHeartbeat(ctx, pb.CNStoreHeartbeat{}) 392 require.NoError(t, err) 393 require.True(t, oldc != c.mu.client) 394 } 395 testNotHAKeeperErrorIsHandled(t, fn) 396 } 397 398 func TestSendTNHeartbeatWhenNotConnectedToHAKeeper(t *testing.T) { 399 fn := func(t *testing.T, c *managedHAKeeperClient) { 400 oldc := c.mu.client 401 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 402 defer cancel() 403 _, err := c.SendTNHeartbeat(ctx, pb.TNStoreHeartbeat{}) 404 require.NoError(t, err) 405 require.True(t, oldc != c.mu.client) 406 } 407 testNotHAKeeperErrorIsHandled(t, fn) 408 } 409 410 func TestSendLogHeartbeatWhenNotConnectedToHAKeeper(t *testing.T) { 411 fn := func(t *testing.T, c *managedHAKeeperClient) { 412 oldc := c.mu.client 413 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 414 defer cancel() 415 _, err := c.SendLogHeartbeat(ctx, pb.LogStoreHeartbeat{}) 416 require.NoError(t, err) 417 require.True(t, oldc != c.mu.client) 418 } 419 testNotHAKeeperErrorIsHandled(t, fn) 420 } 421 422 func TestHAKeeperClientUpdateCNLabel(t *testing.T) { 423 fn := func(t *testing.T, s *Service) { 424 cfg := HAKeeperClientConfig{ 425 ServiceAddresses: []string{testServiceAddress}, 426 } 427 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 428 defer cancel() 429 c1, err := NewProxyHAKeeperClient(ctx, cfg) 430 require.NoError(t, err) 431 c2, err := NewCNHAKeeperClient(ctx, cfg) 432 require.NoError(t, err) 433 defer func() { 434 assert.NoError(t, c1.Close()) 435 assert.NoError(t, c2.Close()) 436 }() 437 438 label := pb.CNStoreLabel{ 439 UUID: s.ID(), 440 Labels: map[string]metadata.LabelList{ 441 "account": {Labels: []string{"a", "b"}}, 442 "role": {Labels: []string{"1", "2"}}, 443 }, 444 } 445 err = c1.UpdateCNLabel(ctx, label) 446 require.Error(t, err) 447 448 hb := pb.CNStoreHeartbeat{ 449 UUID: s.ID(), 450 ServiceAddress: "addr1", 451 } 452 _, err = c2.SendCNHeartbeat(ctx, hb) 453 require.NoError(t, err) 454 455 label = pb.CNStoreLabel{ 456 UUID: s.ID(), 457 Labels: map[string]metadata.LabelList{ 458 "account": {Labels: []string{"a", "b"}}, 459 "role": {Labels: []string{"1", "2"}}, 460 }, 461 } 462 err = c1.UpdateCNLabel(ctx, label) 463 require.NoError(t, err) 464 465 state, err := c1.GetClusterState(ctx) 466 info, ok1 := state.CNState.Stores[s.ID()] 467 assert.True(t, ok1) 468 labels1, ok2 := info.Labels["account"] 469 assert.True(t, ok2) 470 assert.Equal(t, labels1.Labels, []string{"a", "b"}) 471 labels2, ok3 := info.Labels["role"] 472 assert.True(t, ok3) 473 assert.Equal(t, labels2.Labels, []string{"1", "2"}) 474 require.NoError(t, err) 475 476 label = pb.CNStoreLabel{ 477 UUID: s.ID(), 478 Labels: map[string]metadata.LabelList{ 479 "account": {Labels: []string{"a", "b"}}, 480 }, 481 } 482 err = c1.UpdateCNLabel(ctx, label) 483 require.NoError(t, err) 484 485 state, err = c1.GetClusterState(ctx) 486 require.NoError(t, err) 487 info, ok1 = state.CNState.Stores[s.ID()] 488 assert.True(t, ok1) 489 labels1, ok2 = info.Labels["account"] 490 assert.True(t, ok2) 491 assert.Equal(t, labels1.Labels, []string{"a", "b"}) 492 _, ok3 = info.Labels["role"] 493 assert.False(t, ok3) 494 } 495 runServiceTest(t, true, true, fn) 496 } 497 498 func TestHAKeeperClientUpdateCNWorkState(t *testing.T) { 499 fn := func(t *testing.T, s *Service) { 500 cfg := HAKeeperClientConfig{ 501 ServiceAddresses: []string{testServiceAddress}, 502 } 503 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 504 defer cancel() 505 c1, err := NewProxyHAKeeperClient(ctx, cfg) 506 require.NoError(t, err) 507 c2, err := NewCNHAKeeperClient(ctx, cfg) 508 require.NoError(t, err) 509 defer func() { 510 assert.NoError(t, c1.Close()) 511 assert.NoError(t, c2.Close()) 512 }() 513 514 workState := pb.CNWorkState{ 515 UUID: s.ID(), 516 State: metadata.WorkState_Unknown, 517 } 518 err = c1.UpdateCNWorkState(ctx, workState) 519 require.Error(t, err) 520 521 hb := pb.CNStoreHeartbeat{ 522 UUID: s.ID(), 523 ServiceAddress: "addr1", 524 } 525 _, err = c2.SendCNHeartbeat(ctx, hb) 526 require.NoError(t, err) 527 528 workState = pb.CNWorkState{ 529 UUID: s.ID(), 530 State: metadata.WorkState_Working, 531 } 532 err = c1.UpdateCNWorkState(ctx, workState) 533 require.NoError(t, err) 534 535 state, err := c1.GetClusterState(ctx) 536 require.NoError(t, err) 537 info, ok1 := state.CNState.Stores[s.ID()] 538 assert.True(t, ok1) 539 require.Equal(t, metadata.WorkState_Working, info.WorkState) 540 541 workState = pb.CNWorkState{ 542 UUID: s.ID(), 543 State: metadata.WorkState_Draining, 544 } 545 err = c1.UpdateCNWorkState(ctx, workState) 546 require.NoError(t, err) 547 548 state, err = c1.GetClusterState(ctx) 549 require.NoError(t, err) 550 info, ok1 = state.CNState.Stores[s.ID()] 551 assert.True(t, ok1) 552 require.Equal(t, metadata.WorkState_Draining, info.WorkState) 553 554 workState = pb.CNWorkState{ 555 UUID: s.ID(), 556 State: metadata.WorkState_Working, 557 } 558 err = c1.UpdateCNWorkState(ctx, workState) 559 require.NoError(t, err) 560 561 state, err = c1.GetClusterState(ctx) 562 require.NoError(t, err) 563 info, ok1 = state.CNState.Stores[s.ID()] 564 assert.True(t, ok1) 565 require.Equal(t, metadata.WorkState_Working, info.WorkState) 566 } 567 runServiceTest(t, true, true, fn) 568 } 569 570 func TestHAKeeperClientPatchCNStore(t *testing.T) { 571 fn := func(t *testing.T, s *Service) { 572 cfg := HAKeeperClientConfig{ 573 ServiceAddresses: []string{testServiceAddress}, 574 } 575 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 576 defer cancel() 577 c1, err := NewProxyHAKeeperClient(ctx, cfg) 578 require.NoError(t, err) 579 c2, err := NewCNHAKeeperClient(ctx, cfg) 580 require.NoError(t, err) 581 defer func() { 582 assert.NoError(t, c1.Close()) 583 assert.NoError(t, c2.Close()) 584 }() 585 586 stateLabel := pb.CNStateLabel{ 587 UUID: s.ID(), 588 State: metadata.WorkState_Unknown, 589 Labels: map[string]metadata.LabelList{ 590 "account": {Labels: []string{"a", "b"}}, 591 "role": {Labels: []string{"1", "2"}}, 592 }, 593 } 594 err = c1.PatchCNStore(ctx, stateLabel) 595 require.Error(t, err) 596 597 hb := pb.CNStoreHeartbeat{ 598 UUID: s.ID(), 599 ServiceAddress: "addr1", 600 } 601 _, err = c2.SendCNHeartbeat(ctx, hb) 602 require.NoError(t, err) 603 604 stateLabel = pb.CNStateLabel{ 605 UUID: s.ID(), 606 State: metadata.WorkState_Working, 607 Labels: map[string]metadata.LabelList{ 608 "account": {Labels: []string{"a", "b"}}, 609 "role": {Labels: []string{"1", "2"}}, 610 }, 611 } 612 err = c1.PatchCNStore(ctx, stateLabel) 613 require.NoError(t, err) 614 615 state, err := c1.GetClusterState(ctx) 616 require.NoError(t, err) 617 info, ok1 := state.CNState.Stores[s.ID()] 618 assert.True(t, ok1) 619 require.Equal(t, metadata.WorkState_Working, info.WorkState) 620 labels1, ok2 := info.Labels["account"] 621 assert.True(t, ok2) 622 assert.Equal(t, labels1.Labels, []string{"a", "b"}) 623 labels2, ok3 := info.Labels["role"] 624 assert.True(t, ok3) 625 assert.Equal(t, labels2.Labels, []string{"1", "2"}) 626 627 stateLabel = pb.CNStateLabel{ 628 UUID: s.ID(), 629 State: metadata.WorkState_Draining, 630 } 631 err = c1.PatchCNStore(ctx, stateLabel) 632 require.NoError(t, err) 633 634 state, err = c1.GetClusterState(ctx) 635 require.NoError(t, err) 636 info, ok1 = state.CNState.Stores[s.ID()] 637 assert.True(t, ok1) 638 require.Equal(t, metadata.WorkState_Draining, info.WorkState) 639 labels1, ok2 = info.Labels["account"] 640 assert.True(t, ok2) 641 labels2, ok3 = info.Labels["role"] 642 assert.True(t, ok3) 643 assert.Equal(t, labels2.Labels, []string{"1", "2"}) 644 645 stateLabel = pb.CNStateLabel{ 646 UUID: s.ID(), 647 Labels: map[string]metadata.LabelList{ 648 "account": {Labels: []string{"a", "b"}}, 649 }, 650 } 651 err = c1.PatchCNStore(ctx, stateLabel) 652 require.NoError(t, err) 653 654 state, err = c1.GetClusterState(ctx) 655 require.NoError(t, err) 656 info, ok1 = state.CNState.Stores[s.ID()] 657 assert.True(t, ok1) 658 require.Equal(t, metadata.WorkState_Working, info.WorkState) 659 labels1, ok2 = info.Labels["account"] 660 assert.True(t, ok2) 661 assert.Equal(t, labels1.Labels, []string{"a", "b"}) 662 labels2, ok3 = info.Labels["role"] 663 assert.False(t, ok3) 664 } 665 runServiceTest(t, true, true, fn) 666 } 667 668 func TestHAKeeperClientDeleteCNStore(t *testing.T) { 669 fn := func(t *testing.T, s *Service) { 670 cfg := HAKeeperClientConfig{ 671 ServiceAddresses: []string{testServiceAddress}, 672 } 673 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 674 defer cancel() 675 c1, err := NewProxyHAKeeperClient(ctx, cfg) 676 require.NoError(t, err) 677 c2, err := NewCNHAKeeperClient(ctx, cfg) 678 require.NoError(t, err) 679 defer func() { 680 assert.NoError(t, c1.Close()) 681 assert.NoError(t, c2.Close()) 682 }() 683 684 hb := pb.CNStoreHeartbeat{ 685 UUID: s.ID(), 686 ServiceAddress: "addr1", 687 } 688 _, err = c2.SendCNHeartbeat(ctx, hb) 689 require.NoError(t, err) 690 state, err := c1.GetClusterState(ctx) 691 require.NoError(t, err) 692 _, ok := state.CNState.Stores[s.ID()] 693 assert.True(t, ok) 694 695 cnStore := pb.DeleteCNStore{ 696 StoreID: s.ID(), 697 } 698 err = c1.DeleteCNStore(ctx, cnStore) 699 require.NoError(t, err) 700 701 state, err = c1.GetClusterState(ctx) 702 require.NoError(t, err) 703 _, ok = state.CNState.Stores[s.ID()] 704 assert.False(t, ok) 705 } 706 runServiceTest(t, true, true, fn) 707 } 708 709 func TestHAKeeperClientSendProxyHeartbeat(t *testing.T) { 710 fn := func(t *testing.T, s *Service) { 711 cfg := HAKeeperClientConfig{ 712 ServiceAddresses: []string{testServiceAddress}, 713 } 714 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 715 defer cancel() 716 c1, err := NewProxyHAKeeperClient(ctx, cfg) 717 require.NoError(t, err) 718 defer func() { 719 assert.NoError(t, c1.Close()) 720 }() 721 722 hb := pb.ProxyHeartbeat{ 723 UUID: s.ID(), 724 ListenAddress: "addr1", 725 } 726 cb, err := c1.SendProxyHeartbeat(ctx, hb) 727 require.NoError(t, err) 728 assert.Equal(t, 0, len(cb.Commands)) 729 730 cd, err := c1.GetClusterDetails(ctx) 731 require.NoError(t, err) 732 p := pb.ProxyStore{ 733 UUID: s.ID(), 734 ListenAddress: "addr1", 735 } 736 assert.Equal(t, []pb.ProxyStore{p}, cd.ProxyStores) 737 } 738 runServiceTest(t, true, true, fn) 739 }