vitess.io/vitess@v0.16.2/go/vt/topo/topotests/srv_keyspace_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package topotests 18 19 import ( 20 "context" 21 "reflect" 22 "sort" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/stretchr/testify/require" 28 "google.golang.org/protobuf/proto" 29 30 "vitess.io/vitess/go/json2" 31 "vitess.io/vitess/go/vt/key" 32 "vitess.io/vitess/go/vt/topo" 33 "vitess.io/vitess/go/vt/topo/memorytopo" 34 35 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 36 ) 37 38 // waitForInitialSrvKeyspace waits for the initial SrvKeyspace to 39 // appear, and match the provided srvKeyspace. 40 func waitForInitialSrvKeyspace(t *testing.T, ts *topo.Server, cell, keyspace string) (current *topo.WatchSrvKeyspaceData, changes <-chan *topo.WatchSrvKeyspaceData, cancel context.CancelFunc) { 41 ctx, cancel := context.WithCancel(context.Background()) 42 start := time.Now() 43 var err error 44 for { 45 current, changes, err = ts.WatchSrvKeyspace(ctx, cell, keyspace) 46 switch { 47 case topo.IsErrType(err, topo.NoNode): 48 // hasn't appeared yet 49 if time.Since(start) > 10*time.Second { 50 t.Fatalf("time out waiting for file to appear") 51 } 52 time.Sleep(10 * time.Millisecond) 53 continue 54 case err == nil: 55 return 56 default: 57 t.Fatalf("watch failed: %v", err) 58 } 59 } 60 } 61 62 func TestWatchSrvKeyspaceNoNode(t *testing.T) { 63 cell := "cell1" 64 keyspace := "ks1" 65 ctx := context.Background() 66 ts := memorytopo.NewServer(cell) 67 68 // No SrvKeyspace -> ErrNoNode 69 _, _, err := ts.WatchSrvKeyspace(ctx, cell, keyspace) 70 if !topo.IsErrType(err, topo.NoNode) { 71 t.Errorf("Got invalid result from WatchSrvKeyspace(not there): %v", err) 72 } 73 } 74 75 func TestWatchSrvKeyspace(t *testing.T) { 76 77 cell := "cell1" 78 keyspace := "ks1" 79 ctx := context.Background() 80 ts := memorytopo.NewServer(cell) 81 82 // Create initial value 83 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, &topodatapb.SrvKeyspace{}); err != nil { 84 t.Fatalf("Update(/keyspaces/ks1/SrvKeyspace) failed: %v", err) 85 } 86 87 // Starting the watch should now work, and return an empty 88 // SrvKeyspace. 89 wanted := &topodatapb.SrvKeyspace{} 90 current, changes, cancel := waitForInitialSrvKeyspace(t, ts, cell, keyspace) 91 if !proto.Equal(current.Value, wanted) { 92 t.Fatalf("got bad data: %v expected: %v", current.Value, wanted) 93 } 94 95 // Update the value with bad data, wait until error. 96 conn, err := ts.ConnForCell(ctx, cell) 97 if err != nil { 98 t.Fatalf("ConnForCell failed: %v", err) 99 } 100 if _, err := conn.Update(ctx, "/keyspaces/"+keyspace+"/SrvKeyspace", []byte("BAD PROTO DATA"), nil); err != nil { 101 t.Fatalf("Update(/keyspaces/ks1/SrvKeyspace) failed: %v", err) 102 } 103 for { 104 wd, ok := <-changes 105 if !ok { 106 t.Fatalf("watch channel unexpectedly closed") 107 } 108 if wd.Err != nil { 109 if strings.Contains(wd.Err.Error(), "error unpacking SrvKeyspace object") { 110 break 111 } 112 t.Fatalf("watch channel unexpectedly got unknown error: %v", wd.Err) 113 } 114 if !proto.Equal(wd.Value, wanted) { 115 t.Fatalf("got bad data: %v expected: %v", wd.Value, wanted) 116 } 117 t.Log("got duplicate right value, skipping.") 118 } 119 120 // Cancel should still work here, although it does nothing. 121 cancel() 122 123 // Bad data in topo, setting the watch should now fail. 124 _, _, err = ts.WatchSrvKeyspace(ctx, cell, keyspace) 125 if err == nil || !strings.Contains(err.Error(), "error unpacking initial SrvKeyspace object") { 126 t.Fatalf("expected an initial error setting watch on bad content, but got: %v", err) 127 } 128 129 // Update content, wait until Watch works again 130 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, wanted); err != nil { 131 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 132 } 133 start := time.Now() 134 for { 135 current, changes, err = ts.WatchSrvKeyspace(ctx, cell, keyspace) 136 if err != nil { 137 if strings.Contains(err.Error(), "error unpacking initial SrvKeyspace object") { 138 // hasn't changed yet 139 if time.Since(start) > 10*time.Second { 140 t.Fatalf("time out waiting for file to appear") 141 } 142 time.Sleep(10 * time.Millisecond) 143 continue 144 } 145 t.Fatalf("got unexpected error while setting watch: %v", err) 146 } 147 if !proto.Equal(current.Value, wanted) { 148 t.Fatalf("got bad data: %v expected: %v", current.Value, wanted) 149 } 150 break 151 } 152 153 // Delete node, wait for error (skip any duplicate). 154 if err := ts.DeleteSrvKeyspace(ctx, cell, keyspace); err != nil { 155 t.Fatalf("DeleteSrvKeyspace() failed: %v", err) 156 } 157 for { 158 wd, ok := <-changes 159 if !ok { 160 t.Fatalf("watch channel unexpectedly closed") 161 } 162 if topo.IsErrType(wd.Err, topo.NoNode) { 163 break 164 } 165 if wd.Err != nil { 166 t.Fatalf("watch channel unexpectedly got unknown error: %v", wd.Err) 167 } 168 if !proto.Equal(wd.Value, wanted) { 169 t.Fatalf("got bad data: %v expected: %v", wd.Value, wanted) 170 } 171 t.Log("got duplicate right value, skipping.") 172 } 173 } 174 175 func TestWatchSrvKeyspaceCancel(t *testing.T) { 176 cell := "cell1" 177 keyspace := "ks1" 178 ctx := context.Background() 179 ts := memorytopo.NewServer(cell) 180 181 // No SrvKeyspace -> ErrNoNode 182 _, _, err := ts.WatchSrvKeyspace(ctx, cell, keyspace) 183 if !topo.IsErrType(err, topo.NoNode) { 184 t.Errorf("Got invalid result from WatchSrvKeyspace(not there): %v", err) 185 } 186 187 // Create initial value 188 wanted := &topodatapb.SrvKeyspace{} 189 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, wanted); err != nil { 190 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 191 } 192 193 // Starting the watch should now work. 194 current, changes, cancel := waitForInitialSrvKeyspace(t, ts, cell, keyspace) 195 if !proto.Equal(current.Value, wanted) { 196 t.Fatalf("got bad data: %v expected: %v", current.Value, wanted) 197 } 198 199 // Cancel watch, wait for error. 200 cancel() 201 for { 202 wd, ok := <-changes 203 if !ok { 204 t.Fatalf("watch channel unexpectedly closed") 205 } 206 if topo.IsErrType(wd.Err, topo.Interrupted) { 207 break 208 } 209 if wd.Err != nil { 210 t.Fatalf("watch channel unexpectedly got unknown error: %v", wd.Err) 211 } 212 if !proto.Equal(wd.Value, wanted) { 213 t.Fatalf("got bad data: %v expected: %v", wd.Value, wanted) 214 } 215 t.Log("got duplicate right value, skipping.") 216 } 217 218 // Cancel should still work here, although it does nothing. 219 cancel() 220 } 221 222 func TestUpdateSrvKeyspacePartitions(t *testing.T) { 223 cell := "cell1" 224 cell2 := "cell2" 225 keyspace := "ks1" 226 ctx := context.Background() 227 ts := memorytopo.NewServer(cell, cell2) 228 229 keyRange, err := key.ParseShardingSpec("-") 230 if err != nil || len(keyRange) != 1 { 231 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(keyRange)) 232 } 233 // Create initial value 234 initial := &topodatapb.SrvKeyspace{ 235 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 236 { 237 ServedType: topodatapb.TabletType_PRIMARY, 238 ShardReferences: []*topodatapb.ShardReference{ 239 { 240 Name: "-", 241 KeyRange: keyRange[0], 242 }, 243 }, 244 }, 245 }, 246 } 247 248 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { 249 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 250 } 251 252 if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { 253 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 254 } 255 256 ks := &topodatapb.Keyspace{} 257 if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { 258 t.Fatalf("CreateKeyspace() failed: %v", err) 259 } 260 261 leftKeyRange, err := key.ParseShardingSpec("-80") 262 if err != nil || len(leftKeyRange) != 1 { 263 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 264 } 265 266 rightKeyRange, err := key.ParseShardingSpec("80-") 267 if err != nil || len(leftKeyRange) != 1 { 268 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 269 } 270 271 targetKs := &topodatapb.SrvKeyspace{ 272 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 273 { 274 ServedType: topodatapb.TabletType_PRIMARY, 275 ShardReferences: []*topodatapb.ShardReference{ 276 { 277 Name: "-", 278 KeyRange: keyRange[0], 279 }, 280 { 281 Name: "-80", 282 KeyRange: leftKeyRange[0], 283 }, 284 { 285 Name: "80-", 286 KeyRange: rightKeyRange[0], 287 }, 288 }, 289 }, 290 }, 291 } 292 293 shards := []*topo.ShardInfo{ 294 topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), 295 topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), 296 } 297 298 ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests") 299 if err != nil { 300 t.Fatalf("LockKeyspace() failed: %v", err) 301 } 302 defer unlock(&err) 303 304 if err := ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}); err != nil { 305 t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err) 306 } 307 308 srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) 309 if err != nil { 310 t.Fatalf("GetSrvKeyspace() failed: %v", err) 311 } 312 313 got, err := json2.MarshalPB(srvKeyspace) 314 if err != nil { 315 t.Fatalf("MarshalPB() failed: %v", err) 316 } 317 318 want, err := json2.MarshalPB(targetKs) 319 if err != nil { 320 t.Fatalf("MarshalPB() failed: %v", err) 321 } 322 323 if string(got) != string(want) { 324 t.Errorf("AddSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) 325 } 326 327 // removing works 328 targetKs = &topodatapb.SrvKeyspace{ 329 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 330 { 331 ServedType: topodatapb.TabletType_PRIMARY, 332 ShardReferences: []*topodatapb.ShardReference{ 333 { 334 Name: "-", 335 KeyRange: keyRange[0], 336 }, 337 }, 338 }, 339 }, 340 } 341 342 if err = ts.DeleteSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}); err != nil { 343 t.Fatalf("DeleteSrvKeyspacePartitions() failed: %v", err) 344 } 345 346 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) 347 if err != nil { 348 t.Fatalf("GetSrvKeyspace() failed: %v", err) 349 } 350 351 got, err = json2.MarshalPB(srvKeyspace) 352 if err != nil { 353 t.Fatalf("MarshalPB() failed: %v", err) 354 } 355 356 want, err = json2.MarshalPB(targetKs) 357 if err != nil { 358 t.Fatalf("MarshalPB() failed: %v", err) 359 } 360 361 if string(got) != string(want) { 362 t.Errorf("DeleteSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) 363 } 364 365 // You can add to partitions that do not exist 366 targetKs = &topodatapb.SrvKeyspace{ 367 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 368 { 369 ServedType: topodatapb.TabletType_PRIMARY, 370 ShardReferences: []*topodatapb.ShardReference{ 371 { 372 Name: "-", 373 KeyRange: keyRange[0], 374 }, 375 }, 376 }, 377 { 378 ServedType: topodatapb.TabletType_REPLICA, 379 ShardReferences: []*topodatapb.ShardReference{ 380 { 381 Name: "-80", 382 KeyRange: leftKeyRange[0], 383 }, 384 { 385 Name: "80-", 386 KeyRange: rightKeyRange[0], 387 }, 388 }, 389 }, 390 }, 391 } 392 393 if err = ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, []string{cell}); err != nil { 394 t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err) 395 } 396 397 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) 398 if err != nil { 399 t.Fatalf("GetSrvKeyspace() failed: %v", err) 400 } 401 402 got, err = json2.MarshalPB(srvKeyspace) 403 if err != nil { 404 t.Fatalf("MarshalPB() failed: %v", err) 405 } 406 407 want, err = json2.MarshalPB(targetKs) 408 if err != nil { 409 t.Fatalf("MarshalPB() failed: %v", err) 410 } 411 412 if string(got) != string(want) { 413 t.Errorf("SrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) 414 } 415 416 // it works in multiple cells 417 418 if err = ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, nil); err != nil { 419 t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err) 420 } 421 422 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) 423 if err != nil { 424 t.Fatalf("GetSrvKeyspace() failed: %v", err) 425 } 426 427 got, err = json2.MarshalPB(srvKeyspace) 428 if err != nil { 429 t.Fatalf("MarshalPB() failed: %v", err) 430 } 431 432 want, err = json2.MarshalPB(targetKs) 433 if err != nil { 434 t.Fatalf("MarshalPB() failed: %v", err) 435 } 436 437 if string(got) != string(want) { 438 t.Errorf("AddSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) 439 } 440 441 // Now let's get the srvKeyspace in cell2. Partition should have been added there too. 442 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) 443 if err != nil { 444 t.Fatalf("GetSrvKeyspace() failed: %v", err) 445 } 446 447 got, err = json2.MarshalPB(srvKeyspace) 448 if err != nil { 449 t.Fatalf("MarshalPB() failed: %v", err) 450 } 451 452 want, err = json2.MarshalPB(targetKs) 453 if err != nil { 454 t.Fatalf("MarshalPB() failed: %v", err) 455 } 456 457 if string(got) != string(want) { 458 t.Errorf("GetSrvKeyspace() failure. Got %v, want: %v", string(got), string(want)) 459 } 460 461 } 462 463 func TestUpdateUpdateDisableQueryService(t *testing.T) { 464 cell := "cell1" 465 cell2 := "cell2" 466 keyspace := "ks1" 467 ctx := context.Background() 468 ts := memorytopo.NewServer(cell, cell2) 469 470 leftKeyRange, err := key.ParseShardingSpec("-80") 471 if err != nil || len(leftKeyRange) != 1 { 472 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 473 } 474 475 rightKeyRange, err := key.ParseShardingSpec("80-") 476 if err != nil || len(rightKeyRange) != 1 { 477 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 478 } 479 // Create initial value 480 initial := &topodatapb.SrvKeyspace{ 481 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 482 { 483 ServedType: topodatapb.TabletType_PRIMARY, 484 ShardReferences: []*topodatapb.ShardReference{ 485 { 486 Name: "-80", 487 KeyRange: leftKeyRange[0], 488 }, 489 { 490 Name: "80-", 491 KeyRange: rightKeyRange[0], 492 }, 493 }, 494 }, 495 }, 496 } 497 498 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { 499 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 500 } 501 502 if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { 503 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 504 } 505 506 ks := &topodatapb.Keyspace{} 507 if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { 508 t.Fatalf("CreateKeyspace() failed: %v", err) 509 } 510 511 targetKs := &topodatapb.SrvKeyspace{ 512 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 513 { 514 ServedType: topodatapb.TabletType_PRIMARY, 515 ShardReferences: []*topodatapb.ShardReference{ 516 { 517 Name: "-80", 518 KeyRange: leftKeyRange[0], 519 }, 520 { 521 Name: "80-", 522 KeyRange: rightKeyRange[0], 523 }, 524 }, 525 ShardTabletControls: []*topodatapb.ShardTabletControl{ 526 { 527 Name: "-80", 528 KeyRange: leftKeyRange[0], 529 QueryServiceDisabled: true, 530 }, 531 { 532 Name: "80-", 533 KeyRange: rightKeyRange[0], 534 QueryServiceDisabled: true, 535 }, 536 }, 537 }, 538 }, 539 } 540 541 shards := []*topo.ShardInfo{ 542 topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), 543 topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), 544 } 545 546 ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests") 547 if err != nil { 548 t.Fatalf("LockKeyspace() failed: %v", err) 549 } 550 defer unlock(&err) 551 552 if err := ts.UpdateDisableQueryService(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}, true /* disableQueryService */); err != nil { 553 t.Fatalf("UpdateDisableQueryService() failed: %v", err) 554 } 555 556 srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) 557 if err != nil { 558 t.Fatalf("GetSrvKeyspace() failed: %v", err) 559 } 560 561 got, err := json2.MarshalPB(srvKeyspace) 562 if err != nil { 563 t.Fatalf("MarshalPB() failed: %v", err) 564 } 565 566 want, err := json2.MarshalPB(targetKs) 567 if err != nil { 568 t.Fatalf("MarshalPB() failed: %v", err) 569 } 570 571 if string(got) != string(want) { 572 t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) 573 } 574 575 // cell2 is untouched 576 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) 577 if err != nil { 578 t.Fatalf("GetSrvKeyspace() failed: %v", err) 579 } 580 581 got, err = json2.MarshalPB(srvKeyspace) 582 if err != nil { 583 t.Fatalf("MarshalPB() failed: %v", err) 584 } 585 586 want, err = json2.MarshalPB(initial) 587 if err != nil { 588 t.Fatalf("MarshalPB() failed: %v", err) 589 } 590 591 if string(got) != string(want) { 592 t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) 593 } 594 595 // You can enable query service 596 targetKs = &topodatapb.SrvKeyspace{ 597 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 598 { 599 ServedType: topodatapb.TabletType_PRIMARY, 600 ShardReferences: []*topodatapb.ShardReference{ 601 { 602 Name: "-80", 603 KeyRange: leftKeyRange[0], 604 }, 605 { 606 Name: "80-", 607 KeyRange: rightKeyRange[0], 608 }, 609 }, 610 ShardTabletControls: []*topodatapb.ShardTabletControl{ 611 { 612 Name: "-80", 613 KeyRange: leftKeyRange[0], 614 QueryServiceDisabled: false, 615 }, 616 { 617 Name: "80-", 618 KeyRange: rightKeyRange[0], 619 QueryServiceDisabled: false, 620 }, 621 }, 622 }, 623 }, 624 } 625 626 shards = []*topo.ShardInfo{ 627 topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), 628 topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), 629 } 630 631 if err := ts.UpdateDisableQueryService(ctx, keyspace, shards, topodatapb.TabletType_PRIMARY, []string{cell}, false /* disableQueryService */); err != nil { 632 t.Fatalf("UpdateDisableQueryService() failed: %v", err) 633 } 634 635 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) 636 if err != nil { 637 t.Fatalf("GetSrvKeyspace() failed: %v", err) 638 } 639 640 got, err = json2.MarshalPB(srvKeyspace) 641 if err != nil { 642 t.Fatalf("MarshalPB() failed: %v", err) 643 } 644 645 want, err = json2.MarshalPB(targetKs) 646 if err != nil { 647 t.Fatalf("MarshalPB() failed: %v", err) 648 } 649 650 if string(got) != string(want) { 651 t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) 652 } 653 } 654 655 func TestGetShardServingTypes(t *testing.T) { 656 cell := "cell1" 657 cell2 := "cell2" 658 keyspace := "ks1" 659 ctx := context.Background() 660 ts := memorytopo.NewServer(cell, cell2) 661 662 leftKeyRange, err := key.ParseShardingSpec("-80") 663 if err != nil || len(leftKeyRange) != 1 { 664 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 665 } 666 667 rightKeyRange, err := key.ParseShardingSpec("80-") 668 if err != nil || len(rightKeyRange) != 1 { 669 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 670 } 671 // Create initial value 672 initial := &topodatapb.SrvKeyspace{ 673 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 674 { 675 ServedType: topodatapb.TabletType_PRIMARY, 676 ShardReferences: []*topodatapb.ShardReference{ 677 { 678 Name: "-80", 679 KeyRange: leftKeyRange[0], 680 }, 681 { 682 Name: "80-", 683 KeyRange: rightKeyRange[0], 684 }, 685 }, 686 }, 687 { 688 ServedType: topodatapb.TabletType_REPLICA, 689 ShardReferences: []*topodatapb.ShardReference{ 690 { 691 Name: "80-", 692 KeyRange: rightKeyRange[0], 693 }, 694 }, 695 }, 696 { 697 ServedType: topodatapb.TabletType_RDONLY, 698 ShardReferences: []*topodatapb.ShardReference{ 699 { 700 Name: "-80", 701 KeyRange: leftKeyRange[0], 702 }, 703 }, 704 }, 705 }, 706 } 707 708 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { 709 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 710 } 711 712 if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { 713 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 714 } 715 716 ks := &topodatapb.Keyspace{} 717 if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { 718 t.Fatalf("CreateKeyspace() failed: %v", err) 719 } 720 721 shardInfo := topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil) 722 723 got, err := ts.GetShardServingTypes(ctx, shardInfo) 724 if err != nil { 725 t.Fatalf("GetShardServingTypes() failed: %v", err) 726 } 727 728 want := []topodatapb.TabletType{topodatapb.TabletType_PRIMARY, topodatapb.TabletType_RDONLY} 729 730 if !reflect.DeepEqual(got, want) { 731 t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) 732 } 733 734 shardInfo = topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil) 735 736 got, err = ts.GetShardServingTypes(ctx, shardInfo) 737 if err != nil { 738 t.Fatalf("GetShardServingTypes() failed: %v", err) 739 } 740 741 want = []topodatapb.TabletType{topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA} 742 743 if !reflect.DeepEqual(got, want) { 744 t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) 745 } 746 747 keyRange, _ := key.ParseShardingSpec("-") 748 749 shardInfo = topo.NewShardInfo(keyspace, "-", &topodatapb.Shard{KeyRange: keyRange[0]}, nil) 750 751 got, err = ts.GetShardServingTypes(ctx, shardInfo) 752 if err != nil { 753 t.Fatalf("GetShardServingTypes() failed: %v", err) 754 } 755 756 want = []topodatapb.TabletType{} 757 758 if !reflect.DeepEqual(got, want) { 759 t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) 760 } 761 } 762 763 func TestGetShardServingCells(t *testing.T) { 764 cell := "cell1" 765 cell2 := "cell2" 766 keyspace := "ks1" 767 ctx := context.Background() 768 ts := memorytopo.NewServer(cell, cell2) 769 770 leftKeyRange, err := key.ParseShardingSpec("-80") 771 if err != nil || len(leftKeyRange) != 1 { 772 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 773 } 774 775 rightKeyRange, err := key.ParseShardingSpec("80-") 776 if err != nil || len(rightKeyRange) != 1 { 777 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 778 } 779 // Create initial value 780 initial := &topodatapb.SrvKeyspace{ 781 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 782 { 783 ServedType: topodatapb.TabletType_PRIMARY, 784 ShardReferences: []*topodatapb.ShardReference{ 785 { 786 Name: "-80", 787 KeyRange: leftKeyRange[0], 788 }, 789 { 790 Name: "80-", 791 KeyRange: rightKeyRange[0], 792 }, 793 }, 794 }, 795 { 796 ServedType: topodatapb.TabletType_REPLICA, 797 ShardReferences: []*topodatapb.ShardReference{ 798 { 799 Name: "80-", 800 KeyRange: rightKeyRange[0], 801 }, 802 }, 803 }, 804 { 805 ServedType: topodatapb.TabletType_RDONLY, 806 ShardReferences: []*topodatapb.ShardReference{ 807 { 808 Name: "-80", 809 KeyRange: leftKeyRange[0], 810 }, 811 }, 812 }, 813 }, 814 } 815 816 shardInfo := topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil) 817 818 got, err := ts.GetShardServingCells(ctx, shardInfo) 819 if err != nil { 820 t.Fatalf("GetShardServingTypes() failed: %v", err) 821 } 822 823 want := []string{} 824 825 if !reflect.DeepEqual(got, want) { 826 t.Errorf("GetShardServingCells() failure. Got %v, want: %v", got, want) 827 } 828 829 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { 830 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 831 } 832 833 ks := &topodatapb.Keyspace{} 834 if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { 835 t.Fatalf("CreateKeyspace() failed: %v", err) 836 } 837 838 got, err = ts.GetShardServingCells(ctx, shardInfo) 839 if err != nil { 840 t.Fatalf("GetShardServingCells() failed: %v", err) 841 } 842 843 want = []string{cell} 844 845 if !reflect.DeepEqual(got, want) { 846 t.Errorf("GetShardServingCells() failure. Got %v, want: %v", got, want) 847 } 848 849 if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { 850 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 851 } 852 853 got, err = ts.GetShardServingCells(ctx, shardInfo) 854 if err != nil { 855 t.Fatalf("GetShardServingCells() failed: %v", err) 856 } 857 858 want = []string{cell, cell2} 859 860 sort.Strings(got) 861 862 if !reflect.DeepEqual(got, want) { 863 t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) 864 } 865 } 866 867 func TestMasterMigrateServedType(t *testing.T) { 868 cell := "cell1" 869 cell2 := "cell2" 870 keyspace := "ks1" 871 ctx := context.Background() 872 ts := memorytopo.NewServer(cell, cell2) 873 874 initialKeyRange, err := key.ParseShardingSpec("-") 875 if err != nil || len(initialKeyRange) != 1 { 876 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(initialKeyRange)) 877 } 878 879 leftKeyRange, err := key.ParseShardingSpec("-80") 880 if err != nil || len(leftKeyRange) != 1 { 881 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 882 } 883 884 rightKeyRange, err := key.ParseShardingSpec("80-") 885 if err != nil || len(rightKeyRange) != 1 { 886 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 887 } 888 // Create initial value 889 initial := &topodatapb.SrvKeyspace{ 890 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 891 { 892 ServedType: topodatapb.TabletType_PRIMARY, 893 ShardReferences: []*topodatapb.ShardReference{ 894 { 895 Name: "-", 896 KeyRange: initialKeyRange[0], 897 }, 898 }, 899 ShardTabletControls: []*topodatapb.ShardTabletControl{ 900 { 901 Name: "-", 902 KeyRange: initialKeyRange[0], 903 QueryServiceDisabled: true, 904 }, 905 }, 906 }, 907 { 908 ServedType: topodatapb.TabletType_REPLICA, 909 ShardReferences: []*topodatapb.ShardReference{ 910 { 911 Name: "-", 912 KeyRange: initialKeyRange[0], 913 }, 914 }, 915 ShardTabletControls: []*topodatapb.ShardTabletControl{ 916 { 917 Name: "-", 918 KeyRange: initialKeyRange[0], 919 QueryServiceDisabled: true, 920 }, 921 }, 922 }, 923 { 924 ServedType: topodatapb.TabletType_RDONLY, 925 ShardReferences: []*topodatapb.ShardReference{ 926 { 927 Name: "-", 928 KeyRange: initialKeyRange[0], 929 }, 930 }, 931 }, 932 }, 933 } 934 935 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { 936 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 937 } 938 939 if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { 940 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 941 } 942 943 sourceShards := []*topo.ShardInfo{ 944 topo.NewShardInfo(keyspace, "-", &topodatapb.Shard{KeyRange: initialKeyRange[0]}, nil), 945 } 946 947 destinationShards := []*topo.ShardInfo{ 948 topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), 949 topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), 950 } 951 952 ks := &topodatapb.Keyspace{} 953 if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { 954 t.Fatalf("CreateKeyspace() failed: %v", err) 955 } 956 957 ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests") 958 if err != nil { 959 t.Fatalf("LockKeyspace() failed: %v", err) 960 } 961 defer unlock(&err) 962 963 // You can migrate a single cell at a time 964 965 err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_RDONLY, []string{cell}) 966 if err != nil { 967 t.Fatalf("MigrateServedType() failed: %v", err) 968 } 969 970 targetKs := &topodatapb.SrvKeyspace{ 971 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 972 { 973 ServedType: topodatapb.TabletType_PRIMARY, 974 ShardReferences: []*topodatapb.ShardReference{ 975 { 976 Name: "-", 977 KeyRange: initialKeyRange[0], 978 }, 979 }, 980 ShardTabletControls: []*topodatapb.ShardTabletControl{ 981 { 982 Name: "-", 983 KeyRange: initialKeyRange[0], 984 QueryServiceDisabled: true, 985 }, 986 }, 987 }, 988 { 989 ServedType: topodatapb.TabletType_REPLICA, 990 ShardReferences: []*topodatapb.ShardReference{ 991 { 992 Name: "-", 993 KeyRange: initialKeyRange[0], 994 }, 995 }, 996 ShardTabletControls: []*topodatapb.ShardTabletControl{ 997 { 998 Name: "-", 999 KeyRange: initialKeyRange[0], 1000 QueryServiceDisabled: true, 1001 }, 1002 }, 1003 }, 1004 { 1005 ServedType: topodatapb.TabletType_RDONLY, 1006 ShardReferences: []*topodatapb.ShardReference{ 1007 { 1008 Name: "-80", 1009 KeyRange: leftKeyRange[0], 1010 }, 1011 { 1012 Name: "80-", 1013 KeyRange: rightKeyRange[0], 1014 }, 1015 }, 1016 }, 1017 }, 1018 } 1019 1020 srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) 1021 if err != nil { 1022 t.Fatalf("GetSrvKeyspace() failed: %v", err) 1023 } 1024 1025 got, err := json2.MarshalPB(srvKeyspace) 1026 if err != nil { 1027 t.Fatalf("MarshalPB() failed: %v", err) 1028 } 1029 1030 want, err := json2.MarshalPB(targetKs) 1031 if err != nil { 1032 t.Fatalf("MarshalPB() failed: %v", err) 1033 } 1034 1035 if string(got) != string(want) { 1036 t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) 1037 } 1038 1039 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) 1040 if err != nil { 1041 t.Fatalf("GetSrvKeyspace() failed: %v", err) 1042 } 1043 1044 got, err = json2.MarshalPB(srvKeyspace) 1045 if err != nil { 1046 t.Fatalf("MarshalPB() failed: %v", err) 1047 } 1048 1049 want, err = json2.MarshalPB(initial) 1050 if err != nil { 1051 t.Fatalf("MarshalPB() failed: %v", err) 1052 } 1053 1054 if string(got) != string(want) { 1055 t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) 1056 } 1057 1058 // migrating all cells 1059 1060 err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_RDONLY, nil) 1061 if err != nil { 1062 t.Fatalf("MigrateServedType() failed: %v", err) 1063 } 1064 1065 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) 1066 if err != nil { 1067 t.Fatalf("GetSrvKeyspace() failed: %v", err) 1068 } 1069 1070 got, err = json2.MarshalPB(srvKeyspace) 1071 if err != nil { 1072 t.Fatalf("MarshalPB() failed: %v", err) 1073 } 1074 1075 want, err = json2.MarshalPB(targetKs) 1076 if err != nil { 1077 t.Fatalf("MarshalPB() failed: %v", err) 1078 } 1079 1080 if string(got) != string(want) { 1081 t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) 1082 } 1083 1084 // migrating primary type cleans up shard tablet controls records 1085 1086 targetKs = &topodatapb.SrvKeyspace{ 1087 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 1088 { 1089 ServedType: topodatapb.TabletType_PRIMARY, 1090 ShardReferences: []*topodatapb.ShardReference{ 1091 { 1092 Name: "-80", 1093 KeyRange: leftKeyRange[0], 1094 }, 1095 { 1096 Name: "80-", 1097 KeyRange: rightKeyRange[0], 1098 }, 1099 }, 1100 }, 1101 { 1102 ServedType: topodatapb.TabletType_REPLICA, 1103 ShardReferences: []*topodatapb.ShardReference{ 1104 { 1105 Name: "-", 1106 KeyRange: initialKeyRange[0], 1107 }, 1108 }, 1109 }, 1110 { 1111 ServedType: topodatapb.TabletType_RDONLY, 1112 ShardReferences: []*topodatapb.ShardReference{ 1113 { 1114 Name: "-80", 1115 KeyRange: leftKeyRange[0], 1116 }, 1117 { 1118 Name: "80-", 1119 KeyRange: rightKeyRange[0], 1120 }, 1121 }, 1122 }, 1123 }, 1124 } 1125 1126 err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_PRIMARY, nil) 1127 if err != nil { 1128 t.Fatalf("MigrateServedType() failed: %v", err) 1129 } 1130 1131 srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) 1132 if err != nil { 1133 t.Fatalf("GetSrvKeyspace() failed: %v", err) 1134 } 1135 1136 got, err = json2.MarshalPB(srvKeyspace) 1137 if err != nil { 1138 t.Fatalf("MarshalPB() failed: %v", err) 1139 } 1140 1141 want, err = json2.MarshalPB(targetKs) 1142 if err != nil { 1143 t.Fatalf("MarshalPB() failed: %v", err) 1144 } 1145 1146 if string(got) != string(want) { 1147 t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) 1148 } 1149 } 1150 1151 func TestValidateSrvKeyspace(t *testing.T) { 1152 cell := "cell1" 1153 cell2 := "cell2" 1154 keyspace := "ks1" 1155 ctx := context.Background() 1156 ts := memorytopo.NewServer(cell, cell2) 1157 1158 leftKeyRange, err := key.ParseShardingSpec("-80") 1159 if err != nil || len(leftKeyRange) != 1 { 1160 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 1161 } 1162 1163 rightKeyRange, err := key.ParseShardingSpec("80-") 1164 if err != nil || len(rightKeyRange) != 1 { 1165 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 1166 } 1167 1168 correct := &topodatapb.SrvKeyspace{ 1169 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 1170 { 1171 ServedType: topodatapb.TabletType_PRIMARY, 1172 ShardReferences: []*topodatapb.ShardReference{ 1173 { 1174 Name: "-80", 1175 KeyRange: leftKeyRange[0], 1176 }, 1177 { 1178 Name: "80-", 1179 KeyRange: rightKeyRange[0], 1180 }, 1181 }, 1182 }, 1183 }, 1184 } 1185 1186 incorrect := &topodatapb.SrvKeyspace{ 1187 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 1188 { 1189 ServedType: topodatapb.TabletType_PRIMARY, 1190 ShardReferences: []*topodatapb.ShardReference{ 1191 { 1192 Name: "80-", 1193 KeyRange: rightKeyRange[0], 1194 }, 1195 }, 1196 }, 1197 }, 1198 } 1199 1200 if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, correct); err != nil { 1201 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 1202 } 1203 1204 if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, incorrect); err != nil { 1205 t.Fatalf("UpdateSrvKeyspace() failed: %v", err) 1206 } 1207 errMsg := "keyspace partition for PRIMARY in cell cell2 does not start with min key" 1208 err = ts.ValidateSrvKeyspace(ctx, keyspace, "cell1,cell2") 1209 require.EqualError(t, err, errMsg) 1210 1211 err = ts.ValidateSrvKeyspace(ctx, keyspace, "cell1") 1212 require.NoError(t, err) 1213 err = ts.ValidateSrvKeyspace(ctx, keyspace, "cell2") 1214 require.EqualError(t, err, errMsg) 1215 err = ts.ValidateSrvKeyspace(ctx, keyspace, "") 1216 require.EqualError(t, err, errMsg) 1217 }