vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletmanager/tm_state_test.go (about) 1 /* 2 Copyright 2020 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 tabletmanager 18 19 import ( 20 "context" 21 "encoding/json" 22 "os" 23 "testing" 24 "time" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 29 "vitess.io/vitess/go/test/utils" 30 "vitess.io/vitess/go/vt/key" 31 "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" 32 "vitess.io/vitess/go/vt/servenv" 33 "vitess.io/vitess/go/vt/topo" 34 "vitess.io/vitess/go/vt/topo/faketopo" 35 "vitess.io/vitess/go/vt/topo/memorytopo" 36 "vitess.io/vitess/go/vt/vterrors" 37 "vitess.io/vitess/go/vt/vttablet/tabletservermock" 38 39 tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" 40 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 41 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 42 ) 43 44 func TestStateOpenClose(t *testing.T) { 45 ts := memorytopo.NewServer("cell1") 46 tm := newTestTM(t, ts, 1, "ks", "0") 47 48 // Re-Open should be a no-op 49 tm.tmState.mu.Lock() 50 savedCtx := tm.tmState.ctx 51 tm.tmState.mu.Unlock() 52 53 tm.tmState.Open() 54 55 tm.tmState.mu.Lock() 56 assert.Equal(t, savedCtx, tm.tmState.ctx) 57 tm.tmState.mu.Unlock() 58 59 tm.Close() 60 tm.tmState.mu.Lock() 61 assert.False(t, tm.tmState.isOpen) 62 tm.tmState.mu.Unlock() 63 } 64 65 func TestStateRefreshFromTopo(t *testing.T) { 66 ctx := context.Background() 67 ts := memorytopo.NewServer("cell1") 68 tm := newTestTM(t, ts, 1, "ks", "0") 69 defer tm.Stop() 70 71 err := tm.RefreshState(ctx) 72 require.NoError(t, err) 73 } 74 75 func TestStateResharding(t *testing.T) { 76 ctx := context.Background() 77 ts := memorytopo.NewServer("cell1") 78 tm := newTestTM(t, ts, 1, "ks", "0") 79 defer tm.Stop() 80 81 tm.tmState.mu.Lock() 82 tm.tmState.tablet.Type = topodatapb.TabletType_PRIMARY 83 tm.tmState.mu.Unlock() 84 85 si := &topo.ShardInfo{ 86 Shard: &topodatapb.Shard{ 87 SourceShards: []*topodatapb.Shard_SourceShard{{ 88 Uid: 1, 89 }}, 90 }, 91 } 92 tm.tmState.RefreshFromTopoInfo(ctx, si, nil) 93 tm.tmState.mu.Lock() 94 assert.True(t, tm.tmState.isResharding) 95 tm.tmState.mu.Unlock() 96 97 qsc := tm.QueryServiceControl.(*tabletservermock.Controller) 98 assert.Equal(t, topodatapb.TabletType_PRIMARY, qsc.CurrentTarget().TabletType) 99 assert.False(t, qsc.IsServing()) 100 } 101 102 func TestStateDenyList(t *testing.T) { 103 ctx := context.Background() 104 ts := memorytopo.NewServer("cell1") 105 tm := newTestTM(t, ts, 1, "ks", "0") 106 defer tm.Stop() 107 108 fmd := tm.MysqlDaemon.(*fakemysqldaemon.FakeMysqlDaemon) 109 fmd.Schema = &tabletmanagerdatapb.SchemaDefinition{ 110 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ 111 Name: "t1", 112 }}, 113 } 114 si := &topo.ShardInfo{ 115 Shard: &topodatapb.Shard{ 116 TabletControls: []*topodatapb.Shard_TabletControl{{ 117 TabletType: topodatapb.TabletType_REPLICA, 118 Cells: []string{"cell1"}, 119 DeniedTables: []string{"t1"}, 120 }}, 121 }, 122 } 123 tm.tmState.RefreshFromTopoInfo(ctx, si, nil) 124 tm.tmState.mu.Lock() 125 assert.Equal(t, map[topodatapb.TabletType][]string{topodatapb.TabletType_REPLICA: {"t1"}}, tm.tmState.deniedTables) 126 tm.tmState.mu.Unlock() 127 128 qsc := tm.QueryServiceControl.(*tabletservermock.Controller) 129 b, _ := json.Marshal(qsc.GetQueryRules(denyListQueryList)) 130 assert.Equal(t, `[{"Description":"enforce denied tables","Name":"denied_table","TableNames":["t1"],"Action":"FAIL_RETRY"}]`, string(b)) 131 } 132 133 func TestStateTabletControls(t *testing.T) { 134 ctx := context.Background() 135 ts := memorytopo.NewServer("cell1") 136 tm := newTestTM(t, ts, 1, "ks", "0") 137 defer tm.Stop() 138 139 ks := &topodatapb.SrvKeyspace{ 140 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{{ 141 ServedType: topodatapb.TabletType_REPLICA, 142 ShardTabletControls: []*topodatapb.ShardTabletControl{{ 143 Name: "0", 144 QueryServiceDisabled: true, 145 }}, 146 }}, 147 } 148 tm.tmState.RefreshFromTopoInfo(ctx, nil, ks) 149 want := map[topodatapb.TabletType]bool{ 150 topodatapb.TabletType_REPLICA: true, 151 } 152 tm.tmState.mu.Lock() 153 assert.Equal(t, want, tm.tmState.tabletControls) 154 tm.tmState.mu.Unlock() 155 156 qsc := tm.QueryServiceControl.(*tabletservermock.Controller) 157 assert.Equal(t, topodatapb.TabletType_REPLICA, qsc.CurrentTarget().TabletType) 158 assert.False(t, qsc.IsServing()) 159 } 160 161 func TestStateIsShardServingisInSrvKeyspace(t *testing.T) { 162 ctx := context.Background() 163 ts := memorytopo.NewServer("cell1") 164 tm := newTestTM(t, ts, 1, "ks", "0") 165 defer tm.Stop() 166 167 tm.tmState.mu.Lock() 168 tm.tmState.tablet.Type = topodatapb.TabletType_PRIMARY 169 tm.tmState.updateLocked(ctx) 170 tm.tmState.mu.Unlock() 171 172 leftKeyRange, err := key.ParseShardingSpec("-80") 173 if err != nil || len(leftKeyRange) != 1 { 174 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) 175 } 176 177 rightKeyRange, err := key.ParseShardingSpec("80-") 178 if err != nil || len(rightKeyRange) != 1 { 179 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) 180 } 181 182 keyRange, err := key.ParseShardingSpec("0") 183 if err != nil || len(keyRange) != 1 { 184 t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(keyRange)) 185 } 186 187 // Shard not in the SrvKeyspace, ServedType not in SrvKeyspace 188 ks := &topodatapb.SrvKeyspace{ 189 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 190 { 191 ServedType: topodatapb.TabletType_DRAINED, 192 ShardReferences: []*topodatapb.ShardReference{ 193 { 194 Name: "-80", 195 KeyRange: leftKeyRange[0], 196 }, 197 { 198 Name: "80-", 199 KeyRange: rightKeyRange[0], 200 }, 201 }, 202 }, 203 }, 204 } 205 want := map[topodatapb.TabletType]bool{} 206 tm.tmState.RefreshFromTopoInfo(ctx, nil, ks) 207 208 tm.tmState.mu.Lock() 209 assert.False(t, tm.tmState.isInSrvKeyspace) 210 assert.Equal(t, want, tm.tmState.isShardServing) 211 tm.tmState.mu.Unlock() 212 213 assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get()) 214 215 // Shard not in the SrvKeyspace, ServedType in SrvKeyspace 216 ks = &topodatapb.SrvKeyspace{ 217 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 218 { 219 ServedType: topodatapb.TabletType_PRIMARY, 220 ShardReferences: []*topodatapb.ShardReference{ 221 { 222 Name: "-80", 223 KeyRange: leftKeyRange[0], 224 }, 225 { 226 Name: "80-", 227 KeyRange: rightKeyRange[0], 228 }, 229 }, 230 }, 231 }, 232 } 233 want = map[topodatapb.TabletType]bool{} 234 tm.tmState.RefreshFromTopoInfo(ctx, nil, ks) 235 236 tm.tmState.mu.Lock() 237 assert.False(t, tm.tmState.isInSrvKeyspace) 238 assert.Equal(t, want, tm.tmState.isShardServing) 239 tm.tmState.mu.Unlock() 240 241 assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get()) 242 243 // Shard in the SrvKeyspace, ServedType in the SrvKeyspace 244 ks = &topodatapb.SrvKeyspace{ 245 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 246 { 247 ServedType: topodatapb.TabletType_PRIMARY, 248 ShardReferences: []*topodatapb.ShardReference{ 249 { 250 Name: "0", 251 KeyRange: keyRange[0], 252 }, 253 }, 254 }, 255 }, 256 } 257 want = map[topodatapb.TabletType]bool{ 258 topodatapb.TabletType_PRIMARY: true, 259 } 260 tm.tmState.RefreshFromTopoInfo(ctx, nil, ks) 261 262 tm.tmState.mu.Lock() 263 assert.True(t, tm.tmState.isInSrvKeyspace) 264 assert.Equal(t, want, tm.tmState.isShardServing) 265 tm.tmState.mu.Unlock() 266 267 assert.Equal(t, int64(1), statsIsInSrvKeyspace.Get()) 268 269 // Shard in the SrvKeyspace, ServedType not in the SrvKeyspace 270 ks = &topodatapb.SrvKeyspace{ 271 Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ 272 { 273 ServedType: topodatapb.TabletType_RDONLY, 274 ShardReferences: []*topodatapb.ShardReference{ 275 { 276 Name: "0", 277 KeyRange: keyRange[0], 278 }, 279 }, 280 }, 281 }, 282 } 283 want = map[topodatapb.TabletType]bool{ 284 topodatapb.TabletType_RDONLY: true, 285 } 286 tm.tmState.RefreshFromTopoInfo(ctx, nil, ks) 287 288 tm.tmState.mu.Lock() 289 assert.False(t, tm.tmState.isInSrvKeyspace) 290 assert.Equal(t, want, tm.tmState.isShardServing) 291 tm.tmState.mu.Unlock() 292 293 assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get()) 294 295 // Test tablet type change - shard in the SrvKeyspace, ServedType in the SrvKeyspace 296 err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_RDONLY, DBActionNone) 297 require.NoError(t, err) 298 tm.tmState.mu.Lock() 299 assert.True(t, tm.tmState.isInSrvKeyspace) 300 tm.tmState.mu.Unlock() 301 302 assert.Equal(t, int64(1), statsIsInSrvKeyspace.Get()) 303 304 // Test tablet type change - shard in the SrvKeyspace, ServedType in the SrvKeyspace 305 err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_DRAINED, DBActionNone) 306 require.NoError(t, err) 307 tm.tmState.mu.Lock() 308 assert.False(t, tm.tmState.isInSrvKeyspace) 309 tm.tmState.mu.Unlock() 310 311 assert.Equal(t, int64(0), statsIsInSrvKeyspace.Get()) 312 313 // Test tablet isOpen 314 tm.tmState.mu.Lock() 315 tm.tmState.isOpen = false 316 tm.tmState.isInSrvKeyspace = false 317 tm.tmState.tablet.Type = topodatapb.TabletType_REPLICA 318 tm.tmState.isShardServing = map[topodatapb.TabletType]bool{ 319 topodatapb.TabletType_REPLICA: true, 320 } 321 tm.tmState.mu.Unlock() 322 323 tm.tmState.Open() 324 325 tm.tmState.mu.Lock() 326 assert.True(t, tm.tmState.isInSrvKeyspace) 327 tm.tmState.mu.Unlock() 328 329 assert.Equal(t, int64(1), statsIsInSrvKeyspace.Get()) 330 } 331 332 func TestStateNonServing(t *testing.T) { 333 ctx := context.Background() 334 ts := memorytopo.NewServer("cell1") 335 tm := newTestTM(t, ts, 1, "ks", "0") 336 defer tm.Stop() 337 338 tm.tmState.mu.Lock() 339 tm.tmState.tablet.Type = topodatapb.TabletType_SPARE 340 tm.tmState.updateLocked(ctx) 341 tm.tmState.mu.Unlock() 342 343 qsc := tm.QueryServiceControl.(*tabletservermock.Controller) 344 assert.Equal(t, topodatapb.TabletType_SPARE, qsc.CurrentTarget().TabletType) 345 assert.False(t, qsc.IsServing()) 346 } 347 348 func TestStateChangeTabletType(t *testing.T) { 349 ctx := context.Background() 350 ts := memorytopo.NewServer("cell1") 351 statsTabletTypeCount.ResetAll() 352 tm := newTestTM(t, ts, 2, "ks", "0") 353 defer tm.Stop() 354 355 assert.Equal(t, 1, len(statsTabletTypeCount.Counts())) 356 assert.Equal(t, int64(1), statsTabletTypeCount.Counts()["replica"]) 357 358 alias := &topodatapb.TabletAlias{ 359 Cell: "cell1", 360 Uid: 2, 361 } 362 363 err := tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_PRIMARY, DBActionSetReadWrite) 364 require.NoError(t, err) 365 ti, err := ts.GetTablet(ctx, alias) 366 require.NoError(t, err) 367 assert.Equal(t, topodatapb.TabletType_PRIMARY, ti.Type) 368 assert.NotNil(t, ti.PrimaryTermStartTime) 369 assert.Equal(t, "primary", statsTabletType.Get()) 370 assert.Equal(t, 2, len(statsTabletTypeCount.Counts())) 371 assert.Equal(t, int64(1), statsTabletTypeCount.Counts()["primary"]) 372 373 err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_REPLICA, DBActionNone) 374 require.NoError(t, err) 375 ti, err = ts.GetTablet(ctx, alias) 376 require.NoError(t, err) 377 assert.Equal(t, topodatapb.TabletType_REPLICA, ti.Type) 378 assert.Nil(t, ti.PrimaryTermStartTime) 379 assert.Equal(t, "replica", statsTabletType.Get()) 380 assert.Equal(t, 2, len(statsTabletTypeCount.Counts())) 381 assert.Equal(t, int64(2), statsTabletTypeCount.Counts()["replica"]) 382 } 383 384 /* 385 This test verifies, even if SetServingType returns error we should still publish 386 387 the new table type 388 */ 389 func TestStateChangeTabletTypeWithFailure(t *testing.T) { 390 ctx := context.Background() 391 ts := memorytopo.NewServer("cell1") 392 statsTabletTypeCount.ResetAll() 393 // create TM with replica and put a hook to return error during SetServingType 394 tm := newTestTM(t, ts, 2, "ks", "0") 395 qsc := tm.QueryServiceControl.(*tabletservermock.Controller) 396 qsc.SetServingTypeError = vterrors.Errorf(vtrpcpb.Code_RESOURCE_EXHAUSTED, "mocking resource exhaustion error ") 397 defer tm.Stop() 398 399 assert.Equal(t, 1, len(statsTabletTypeCount.Counts())) 400 assert.Equal(t, int64(1), statsTabletTypeCount.Counts()["replica"]) 401 402 alias := &topodatapb.TabletAlias{ 403 Cell: "cell1", 404 Uid: 2, 405 } 406 407 // change table type to primary 408 err := tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_PRIMARY, DBActionSetReadWrite) 409 errMsg := "Cannot start query service: Code: RESOURCE_EXHAUSTED\nmocking resource exhaustion error \n: mocking resource exhaustion error " 410 require.EqualError(t, err, errMsg) 411 412 ti, err := ts.GetTablet(ctx, alias) 413 require.NoError(t, err) 414 // even though SetServingType failed. It still is expected to publish the new table type 415 assert.Equal(t, topodatapb.TabletType_PRIMARY, ti.Type) 416 assert.NotNil(t, ti.PrimaryTermStartTime) 417 assert.Equal(t, "primary", statsTabletType.Get()) 418 assert.Equal(t, 2, len(statsTabletTypeCount.Counts())) 419 assert.Equal(t, int64(1), statsTabletTypeCount.Counts()["primary"]) 420 421 err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_REPLICA, DBActionNone) 422 require.EqualError(t, err, errMsg) 423 ti, err = ts.GetTablet(ctx, alias) 424 require.NoError(t, err) 425 // even though SetServingType failed. It still is expected to publish the new table type 426 assert.Equal(t, topodatapb.TabletType_REPLICA, ti.Type) 427 assert.Nil(t, ti.PrimaryTermStartTime) 428 assert.Equal(t, "replica", statsTabletType.Get()) 429 assert.Equal(t, 2, len(statsTabletTypeCount.Counts())) 430 assert.Equal(t, int64(2), statsTabletTypeCount.Counts()["replica"]) 431 432 // since the table type is spare, it will exercise reason != "" in UpdateLocked and thus 433 // populate error object differently as compare to above scenarios 434 err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_SPARE, DBActionNone) 435 errMsg = "SetServingType(serving=false) failed: Code: RESOURCE_EXHAUSTED\nmocking resource exhaustion error \n: mocking resource exhaustion error " 436 require.EqualError(t, err, errMsg) 437 ti, err = ts.GetTablet(ctx, alias) 438 require.NoError(t, err) 439 // even though SetServingType failed. It still is expected to publish the new table type 440 assert.Equal(t, topodatapb.TabletType_SPARE, ti.Type) 441 assert.Nil(t, ti.PrimaryTermStartTime) 442 assert.Equal(t, "spare", statsTabletType.Get()) 443 assert.Equal(t, 3, len(statsTabletTypeCount.Counts())) 444 assert.Equal(t, int64(1), statsTabletTypeCount.Counts()["spare"]) 445 } 446 447 // TestChangeTypeErrorWhileWritingToTopo tests the case where we fail while writing to the topo-server 448 func TestChangeTypeErrorWhileWritingToTopo(t *testing.T) { 449 testcases := []struct { 450 name string 451 writePersists bool 452 numberOfReadErrors int 453 expectedTabletType topodatapb.TabletType 454 expectedError string 455 }{ 456 { 457 name: "Write persists even when error thrown from topo server", 458 writePersists: true, 459 numberOfReadErrors: 5, 460 expectedTabletType: topodatapb.TabletType_PRIMARY, 461 }, { 462 name: "Topo server throws error and the write also fails", 463 writePersists: false, 464 numberOfReadErrors: 17, 465 expectedTabletType: topodatapb.TabletType_REPLICA, 466 expectedError: "deadline exceeded: tablets/cell1-0000000002/Tablet", 467 }, 468 } 469 470 for _, testcase := range testcases { 471 t.Run(testcase.name, func(t *testing.T) { 472 factory := faketopo.NewFakeTopoFactory() 473 // add cell1 to the factory. This returns a fake connection which we will use to set the get and update errors as we require. 474 fakeConn := factory.AddCell("cell1") 475 ts := faketopo.NewFakeTopoServer(factory) 476 statsTabletTypeCount.ResetAll() 477 tm := newTestTM(t, ts, 2, "ks", "0") 478 defer tm.Stop() 479 480 // ChangeTabletType calls topotools.ChangeType which in-turn issues 481 // a GET request and an UPDATE request to the topo server. 482 // We want the first GET request to pass without any failure 483 // We want the UPDATE request to fail 484 fakeConn.AddGetError(false) 485 fakeConn.AddUpdateError(true, testcase.writePersists) 486 // Since the UPDATE request failed, we will try a GET request on the 487 // topo server until it succeeds. 488 for i := 0; i < testcase.numberOfReadErrors; i++ { 489 fakeConn.AddGetError(true) 490 } 491 ctx := context.Background() 492 err := tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_PRIMARY, DBActionSetReadWrite) 493 if testcase.expectedError != "" { 494 require.EqualError(t, err, testcase.expectedError) 495 } else { 496 require.NoError(t, err) 497 } 498 499 alias := &topodatapb.TabletAlias{ 500 Cell: "cell1", 501 Uid: 2, 502 } 503 ti, err := ts.GetTablet(ctx, alias) 504 require.NoError(t, err) 505 require.Equal(t, testcase.expectedTabletType, ti.Type) 506 507 // assert that next change type succeeds irrespective of previous failures 508 err = tm.tmState.ChangeTabletType(context.Background(), topodatapb.TabletType_REPLICA, DBActionNone) 509 require.NoError(t, err) 510 }) 511 } 512 } 513 514 func TestPublishStateNew(t *testing.T) { 515 defer func(saved time.Duration) { publishRetryInterval = saved }(publishRetryInterval) 516 publishRetryInterval = 1 * time.Millisecond 517 518 // This flow doesn't test the failure scenario, which 519 // we can't do using memorytopo, but we do test the retry 520 // code path. 521 522 ctx := context.Background() 523 ts := memorytopo.NewServer("cell1") 524 tm := newTestTM(t, ts, 42, "ks", "0") 525 ttablet, err := tm.TopoServer.GetTablet(ctx, tm.tabletAlias) 526 require.NoError(t, err) 527 utils.MustMatch(t, tm.Tablet(), ttablet.Tablet) 528 529 tab1 := tm.Tablet() 530 tab1.Keyspace = "tab1" 531 tm.tmState.mu.Lock() 532 tm.tmState.tablet = tab1 533 tm.tmState.publishStateLocked(ctx) 534 tm.tmState.mu.Unlock() 535 ttablet, err = tm.TopoServer.GetTablet(ctx, tm.tabletAlias) 536 require.NoError(t, err) 537 utils.MustMatch(t, tab1, ttablet.Tablet) 538 539 tab2 := tm.Tablet() 540 tab2.Keyspace = "tab2" 541 tm.tmState.mu.Lock() 542 tm.tmState.tablet = tab2 543 tm.tmState.mu.Unlock() 544 tm.tmState.retryPublish() 545 ttablet, err = tm.TopoServer.GetTablet(ctx, tm.tabletAlias) 546 require.NoError(t, err) 547 utils.MustMatch(t, tab2, ttablet.Tablet) 548 549 // If hostname doesn't match, it should not update. 550 tab3 := tm.Tablet() 551 tab3.Hostname = "tab3" 552 tm.tmState.mu.Lock() 553 tm.tmState.tablet = tab3 554 tm.tmState.publishStateLocked(ctx) 555 tm.tmState.mu.Unlock() 556 ttablet, err = tm.TopoServer.GetTablet(ctx, tm.tabletAlias) 557 require.NoError(t, err) 558 utils.MustMatch(t, tab2, ttablet.Tablet) 559 560 // Same for retryPublish. 561 tm.tmState.retryPublish() 562 ttablet, err = tm.TopoServer.GetTablet(ctx, tm.tabletAlias) 563 require.NoError(t, err) 564 utils.MustMatch(t, tab2, ttablet.Tablet) 565 } 566 567 func TestPublishDeleted(t *testing.T) { 568 ctx := context.Background() 569 ts := memorytopo.NewServer("cell1") 570 tm := newTestTM(t, ts, 2, "ks", "0") 571 defer tm.Stop() 572 573 alias := &topodatapb.TabletAlias{ 574 Cell: "cell1", 575 Uid: 2, 576 } 577 578 err := tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_PRIMARY, DBActionSetReadWrite) 579 require.NoError(t, err) 580 581 err = ts.DeleteTablet(ctx, alias) 582 require.NoError(t, err) 583 584 // we need to make sure to catch the signal 585 servenv.ExitChan = make(chan os.Signal, 1) 586 // Now change the tablet type and publish 587 err = tm.tmState.ChangeTabletType(ctx, topodatapb.TabletType_REPLICA, DBActionNone) 588 require.NoError(t, err) 589 tm.tmState.mu.Lock() 590 assert.False(t, tm.tmState.isPublishing) 591 tm.tmState.mu.Unlock() 592 }