vitess.io/vitess@v0.16.2/go/vt/vtorc/inst/analysis_dao_test.go (about) 1 /* 2 Copyright 2022 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 inst 18 19 import ( 20 "testing" 21 22 "github.com/stretchr/testify/require" 23 24 "vitess.io/vitess/go/vt/external/golib/sqlutils" 25 26 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 27 "vitess.io/vitess/go/vt/vtorc/db" 28 "vitess.io/vitess/go/vt/vtorc/test" 29 ) 30 31 // TestGetReplicationAnalysisDecision tests the code of GetReplicationAnalysis decision-making. It doesn't check the SQL query 32 // run by it. It only checks the analysis part after the rows have been read. This tests fakes the db and explicitly returns the 33 // rows that are specified in the test. 34 func TestGetReplicationAnalysisDecision(t *testing.T) { 35 tests := []struct { 36 name string 37 info []*test.InfoForRecoveryAnalysis 38 codeWanted AnalysisCode 39 shardWanted string 40 keyspaceWanted string 41 wantErr string 42 }{ 43 { 44 name: "ClusterHasNoPrimary", 45 info: []*test.InfoForRecoveryAnalysis{{ 46 TabletInfo: &topodatapb.Tablet{ 47 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 48 Hostname: "localhost", 49 Keyspace: "ks", 50 Shard: "0", 51 Type: topodatapb.TabletType_REPLICA, 52 MysqlHostname: "localhost", 53 MysqlPort: 6709, 54 }, 55 DurabilityPolicy: "none", 56 LastCheckValid: 1, 57 }}, 58 keyspaceWanted: "ks", 59 shardWanted: "0", 60 codeWanted: ClusterHasNoPrimary, 61 }, { 62 name: "DeadPrimary", 63 info: []*test.InfoForRecoveryAnalysis{{ 64 TabletInfo: &topodatapb.Tablet{ 65 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 66 Hostname: "localhost", 67 Keyspace: "ks", 68 Shard: "0", 69 Type: topodatapb.TabletType_PRIMARY, 70 MysqlHostname: "localhost", 71 MysqlPort: 6709, 72 }, 73 DurabilityPolicy: "none", 74 LastCheckValid: 0, 75 CountReplicas: 4, 76 CountValidReplicas: 4, 77 CountValidReplicatingReplicas: 0, 78 IsPrimary: 1, 79 }}, 80 keyspaceWanted: "ks", 81 shardWanted: "0", 82 codeWanted: DeadPrimary, 83 }, { 84 name: "DeadPrimaryWithoutReplicas", 85 info: []*test.InfoForRecoveryAnalysis{{ 86 TabletInfo: &topodatapb.Tablet{ 87 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 88 Hostname: "localhost", 89 Keyspace: "ks", 90 Shard: "0", 91 Type: topodatapb.TabletType_PRIMARY, 92 MysqlHostname: "localhost", 93 MysqlPort: 6709, 94 }, 95 DurabilityPolicy: "none", 96 LastCheckValid: 0, 97 CountReplicas: 0, 98 IsPrimary: 1, 99 }}, 100 keyspaceWanted: "ks", 101 shardWanted: "0", 102 codeWanted: DeadPrimaryWithoutReplicas, 103 }, { 104 name: "DeadPrimaryAndReplicas", 105 info: []*test.InfoForRecoveryAnalysis{{ 106 TabletInfo: &topodatapb.Tablet{ 107 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 108 Hostname: "localhost", 109 Keyspace: "ks", 110 Shard: "0", 111 Type: topodatapb.TabletType_PRIMARY, 112 MysqlHostname: "localhost", 113 MysqlPort: 6709, 114 }, 115 DurabilityPolicy: "none", 116 LastCheckValid: 0, 117 CountReplicas: 3, 118 IsPrimary: 1, 119 }}, 120 keyspaceWanted: "ks", 121 shardWanted: "0", 122 codeWanted: DeadPrimaryAndReplicas, 123 }, { 124 name: "DeadPrimaryAndSomeReplicas", 125 info: []*test.InfoForRecoveryAnalysis{{ 126 TabletInfo: &topodatapb.Tablet{ 127 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 128 Hostname: "localhost", 129 Keyspace: "ks", 130 Shard: "0", 131 Type: topodatapb.TabletType_PRIMARY, 132 MysqlHostname: "localhost", 133 MysqlPort: 6709, 134 }, 135 DurabilityPolicy: "none", 136 LastCheckValid: 0, 137 CountReplicas: 4, 138 CountValidReplicas: 2, 139 CountValidReplicatingReplicas: 0, 140 IsPrimary: 1, 141 }}, 142 keyspaceWanted: "ks", 143 shardWanted: "0", 144 codeWanted: DeadPrimaryAndSomeReplicas, 145 }, { 146 name: "PrimaryHasPrimary", 147 info: []*test.InfoForRecoveryAnalysis{{ 148 TabletInfo: &topodatapb.Tablet{ 149 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 150 Hostname: "localhost", 151 Keyspace: "ks", 152 Shard: "0", 153 Type: topodatapb.TabletType_PRIMARY, 154 MysqlHostname: "localhost", 155 MysqlPort: 6709, 156 }, 157 DurabilityPolicy: "none", 158 LastCheckValid: 1, 159 CountReplicas: 4, 160 CountValidReplicas: 4, 161 IsPrimary: 0, 162 }}, 163 keyspaceWanted: "ks", 164 shardWanted: "0", 165 codeWanted: PrimaryHasPrimary, 166 }, { 167 name: "PrimaryIsReadOnly", 168 info: []*test.InfoForRecoveryAnalysis{{ 169 TabletInfo: &topodatapb.Tablet{ 170 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 171 Hostname: "localhost", 172 Keyspace: "ks", 173 Shard: "0", 174 Type: topodatapb.TabletType_PRIMARY, 175 MysqlHostname: "localhost", 176 MysqlPort: 6709, 177 }, 178 DurabilityPolicy: "none", 179 LastCheckValid: 1, 180 CountReplicas: 4, 181 CountValidReplicas: 4, 182 IsPrimary: 1, 183 ReadOnly: 1, 184 }}, 185 keyspaceWanted: "ks", 186 shardWanted: "0", 187 codeWanted: PrimaryIsReadOnly, 188 }, { 189 name: "PrimarySemiSyncMustNotBeSet", 190 info: []*test.InfoForRecoveryAnalysis{{ 191 TabletInfo: &topodatapb.Tablet{ 192 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 193 Hostname: "localhost", 194 Keyspace: "ks", 195 Shard: "0", 196 Type: topodatapb.TabletType_PRIMARY, 197 MysqlHostname: "localhost", 198 MysqlPort: 6709, 199 }, 200 DurabilityPolicy: "none", 201 LastCheckValid: 1, 202 CountReplicas: 4, 203 CountValidReplicas: 4, 204 IsPrimary: 1, 205 SemiSyncPrimaryEnabled: 1, 206 }}, 207 keyspaceWanted: "ks", 208 shardWanted: "0", 209 codeWanted: PrimarySemiSyncMustNotBeSet, 210 }, { 211 name: "PrimarySemiSyncMustBeSet", 212 info: []*test.InfoForRecoveryAnalysis{{ 213 TabletInfo: &topodatapb.Tablet{ 214 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 215 Hostname: "localhost", 216 Keyspace: "ks", 217 Shard: "0", 218 Type: topodatapb.TabletType_PRIMARY, 219 MysqlHostname: "localhost", 220 MysqlPort: 6709, 221 }, 222 DurabilityPolicy: "semi_sync", 223 LastCheckValid: 1, 224 CountReplicas: 4, 225 CountValidReplicas: 4, 226 IsPrimary: 1, 227 SemiSyncPrimaryEnabled: 0, 228 }}, 229 keyspaceWanted: "ks", 230 shardWanted: "0", 231 codeWanted: PrimarySemiSyncMustBeSet, 232 }, { 233 name: "NotConnectedToPrimary", 234 info: []*test.InfoForRecoveryAnalysis{{ 235 TabletInfo: &topodatapb.Tablet{ 236 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 237 Hostname: "localhost", 238 Keyspace: "ks", 239 Shard: "0", 240 Type: topodatapb.TabletType_PRIMARY, 241 MysqlHostname: "localhost", 242 MysqlPort: 6708, 243 }, 244 DurabilityPolicy: "none", 245 LastCheckValid: 1, 246 CountReplicas: 4, 247 CountValidReplicas: 4, 248 CountValidReplicatingReplicas: 3, 249 CountValidOracleGTIDReplicas: 4, 250 CountLoggingReplicas: 2, 251 IsPrimary: 1, 252 }, { 253 TabletInfo: &topodatapb.Tablet{ 254 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 255 Hostname: "localhost", 256 Keyspace: "ks", 257 Shard: "0", 258 Type: topodatapb.TabletType_REPLICA, 259 MysqlHostname: "localhost", 260 MysqlPort: 6709, 261 }, 262 LastCheckValid: 1, 263 ReadOnly: 1, 264 IsPrimary: 1, 265 }}, 266 keyspaceWanted: "ks", 267 shardWanted: "0", 268 codeWanted: NotConnectedToPrimary, 269 }, { 270 name: "ReplicaIsWritable", 271 info: []*test.InfoForRecoveryAnalysis{{ 272 TabletInfo: &topodatapb.Tablet{ 273 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 274 Hostname: "localhost", 275 Keyspace: "ks", 276 Shard: "0", 277 Type: topodatapb.TabletType_PRIMARY, 278 MysqlHostname: "localhost", 279 MysqlPort: 6708, 280 }, 281 DurabilityPolicy: "none", 282 LastCheckValid: 1, 283 CountReplicas: 4, 284 CountValidReplicas: 4, 285 CountValidReplicatingReplicas: 3, 286 CountValidOracleGTIDReplicas: 4, 287 CountLoggingReplicas: 2, 288 IsPrimary: 1, 289 }, { 290 TabletInfo: &topodatapb.Tablet{ 291 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 292 Hostname: "localhost", 293 Keyspace: "ks", 294 Shard: "0", 295 Type: topodatapb.TabletType_REPLICA, 296 MysqlHostname: "localhost", 297 MysqlPort: 6709, 298 }, 299 DurabilityPolicy: "none", 300 SourceHost: "localhost", 301 SourcePort: 6708, 302 LastCheckValid: 1, 303 ReadOnly: 0, 304 }}, 305 keyspaceWanted: "ks", 306 shardWanted: "0", 307 codeWanted: ReplicaIsWritable, 308 }, { 309 name: "ConnectedToWrongPrimary", 310 info: []*test.InfoForRecoveryAnalysis{{ 311 TabletInfo: &topodatapb.Tablet{ 312 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 313 Hostname: "localhost", 314 Keyspace: "ks", 315 Shard: "0", 316 Type: topodatapb.TabletType_PRIMARY, 317 MysqlHostname: "localhost", 318 MysqlPort: 6708, 319 }, 320 DurabilityPolicy: "none", 321 LastCheckValid: 1, 322 CountReplicas: 4, 323 CountValidReplicas: 4, 324 CountValidReplicatingReplicas: 3, 325 CountValidOracleGTIDReplicas: 4, 326 CountLoggingReplicas: 2, 327 IsPrimary: 1, 328 }, { 329 TabletInfo: &topodatapb.Tablet{ 330 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 331 Hostname: "localhost", 332 Keyspace: "ks", 333 Shard: "0", 334 Type: topodatapb.TabletType_REPLICA, 335 MysqlHostname: "localhost", 336 MysqlPort: 6709, 337 }, 338 DurabilityPolicy: "none", 339 SourceHost: "localhost", 340 SourcePort: 6706, 341 LastCheckValid: 1, 342 ReadOnly: 1, 343 }}, 344 keyspaceWanted: "ks", 345 shardWanted: "0", 346 codeWanted: ConnectedToWrongPrimary, 347 }, { 348 name: "ReplicationStopped", 349 info: []*test.InfoForRecoveryAnalysis{{ 350 TabletInfo: &topodatapb.Tablet{ 351 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 352 Hostname: "localhost", 353 Keyspace: "ks", 354 Shard: "0", 355 Type: topodatapb.TabletType_PRIMARY, 356 MysqlHostname: "localhost", 357 MysqlPort: 6708, 358 }, 359 DurabilityPolicy: "none", 360 LastCheckValid: 1, 361 CountReplicas: 4, 362 CountValidReplicas: 4, 363 CountValidReplicatingReplicas: 3, 364 CountValidOracleGTIDReplicas: 4, 365 CountLoggingReplicas: 2, 366 IsPrimary: 1, 367 }, { 368 TabletInfo: &topodatapb.Tablet{ 369 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 370 Hostname: "localhost", 371 Keyspace: "ks", 372 Shard: "0", 373 Type: topodatapb.TabletType_REPLICA, 374 MysqlHostname: "localhost", 375 MysqlPort: 6709, 376 }, 377 DurabilityPolicy: "none", 378 SourceHost: "localhost", 379 SourcePort: 6708, 380 LastCheckValid: 1, 381 ReadOnly: 1, 382 ReplicationStopped: 1, 383 }}, 384 keyspaceWanted: "ks", 385 shardWanted: "0", 386 codeWanted: ReplicationStopped, 387 }, 388 { 389 name: "ReplicaSemiSyncMustBeSet", 390 info: []*test.InfoForRecoveryAnalysis{{ 391 TabletInfo: &topodatapb.Tablet{ 392 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 393 Hostname: "localhost", 394 Keyspace: "ks", 395 Shard: "0", 396 Type: topodatapb.TabletType_PRIMARY, 397 MysqlHostname: "localhost", 398 MysqlPort: 6708, 399 }, 400 DurabilityPolicy: "semi_sync", 401 LastCheckValid: 1, 402 CountReplicas: 4, 403 CountValidReplicas: 4, 404 CountValidReplicatingReplicas: 3, 405 CountValidOracleGTIDReplicas: 4, 406 CountLoggingReplicas: 2, 407 IsPrimary: 1, 408 SemiSyncPrimaryEnabled: 1, 409 }, { 410 TabletInfo: &topodatapb.Tablet{ 411 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 412 Hostname: "localhost", 413 Keyspace: "ks", 414 Shard: "0", 415 Type: topodatapb.TabletType_REPLICA, 416 MysqlHostname: "localhost", 417 MysqlPort: 6709, 418 }, 419 PrimaryTabletInfo: &topodatapb.Tablet{ 420 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 421 Hostname: "localhost", 422 Keyspace: "ks", 423 Shard: "0", 424 Type: topodatapb.TabletType_PRIMARY, 425 MysqlHostname: "localhost", 426 MysqlPort: 6708, 427 }, 428 DurabilityPolicy: "semi_sync", 429 SourceHost: "localhost", 430 SourcePort: 6708, 431 LastCheckValid: 1, 432 ReadOnly: 1, 433 SemiSyncReplicaEnabled: 0, 434 }}, 435 keyspaceWanted: "ks", 436 shardWanted: "0", 437 codeWanted: ReplicaSemiSyncMustBeSet, 438 }, { 439 name: "ReplicaSemiSyncMustNotBeSet", 440 info: []*test.InfoForRecoveryAnalysis{{ 441 TabletInfo: &topodatapb.Tablet{ 442 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 443 Hostname: "localhost", 444 Keyspace: "ks", 445 Shard: "0", 446 Type: topodatapb.TabletType_PRIMARY, 447 MysqlHostname: "localhost", 448 MysqlPort: 6708, 449 }, 450 DurabilityPolicy: "none", 451 LastCheckValid: 1, 452 CountReplicas: 4, 453 CountValidReplicas: 4, 454 CountValidReplicatingReplicas: 3, 455 CountValidOracleGTIDReplicas: 4, 456 CountLoggingReplicas: 2, 457 IsPrimary: 1, 458 }, { 459 TabletInfo: &topodatapb.Tablet{ 460 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 461 Hostname: "localhost", 462 Keyspace: "ks", 463 Shard: "0", 464 Type: topodatapb.TabletType_REPLICA, 465 MysqlHostname: "localhost", 466 MysqlPort: 6709, 467 }, 468 PrimaryTabletInfo: &topodatapb.Tablet{ 469 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 470 Hostname: "localhost", 471 Keyspace: "ks", 472 Shard: "0", 473 Type: topodatapb.TabletType_PRIMARY, 474 MysqlHostname: "localhost", 475 MysqlPort: 6708, 476 }, 477 DurabilityPolicy: "none", 478 SourceHost: "localhost", 479 SourcePort: 6708, 480 LastCheckValid: 1, 481 ReadOnly: 1, 482 SemiSyncReplicaEnabled: 1, 483 }}, 484 keyspaceWanted: "ks", 485 shardWanted: "0", 486 codeWanted: ReplicaSemiSyncMustNotBeSet, 487 }, { 488 name: "SnapshotKeyspace", 489 info: []*test.InfoForRecoveryAnalysis{{ 490 TabletInfo: &topodatapb.Tablet{ 491 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 492 Hostname: "localhost", 493 Keyspace: "ks", 494 Shard: "0", 495 Type: topodatapb.TabletType_REPLICA, 496 MysqlHostname: "localhost", 497 MysqlPort: 6709, 498 }, 499 // Snapshot Keyspace 500 KeyspaceType: 1, 501 DurabilityPolicy: "none", 502 LastCheckValid: 1, 503 }}, 504 keyspaceWanted: "ks", 505 shardWanted: "0", 506 codeWanted: NoProblem, 507 }, { 508 name: "EmptyDurabilityPolicy", 509 info: []*test.InfoForRecoveryAnalysis{{ 510 TabletInfo: &topodatapb.Tablet{ 511 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 512 Hostname: "localhost", 513 Keyspace: "ks", 514 Shard: "0", 515 Type: topodatapb.TabletType_REPLICA, 516 MysqlHostname: "localhost", 517 MysqlPort: 6709, 518 }, 519 LastCheckValid: 1, 520 }}, 521 // We will ignore these keyspaces too until the durability policy is set in the topo server 522 keyspaceWanted: "ks", 523 shardWanted: "0", 524 codeWanted: NoProblem, 525 }, { 526 // If the database_instance table for a tablet is empty (discovery of MySQL information hasn't happened yet or failed) 527 // then we shouldn't run a failure fix on it until the discovery succeeds 528 name: "Empty database_instance table", 529 info: []*test.InfoForRecoveryAnalysis{{ 530 TabletInfo: &topodatapb.Tablet{ 531 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 101}, 532 Hostname: "localhost", 533 Keyspace: "ks", 534 Shard: "0", 535 Type: topodatapb.TabletType_PRIMARY, 536 MysqlHostname: "localhost", 537 MysqlPort: 6708, 538 }, 539 DurabilityPolicy: "semi_sync", 540 LastCheckValid: 1, 541 CountReplicas: 4, 542 CountValidReplicas: 4, 543 CountValidReplicatingReplicas: 3, 544 CountValidOracleGTIDReplicas: 4, 545 CountLoggingReplicas: 2, 546 IsPrimary: 1, 547 SemiSyncPrimaryEnabled: 1, 548 }, { 549 TabletInfo: &topodatapb.Tablet{ 550 Alias: &topodatapb.TabletAlias{Cell: "zon1", Uid: 100}, 551 Hostname: "localhost", 552 Keyspace: "ks", 553 Shard: "0", 554 Type: topodatapb.TabletType_REPLICA, 555 MysqlHostname: "localhost", 556 MysqlPort: 6709, 557 }, 558 IsInvalid: 1, 559 DurabilityPolicy: "semi_sync", 560 }}, 561 keyspaceWanted: "ks", 562 shardWanted: "0", 563 codeWanted: NoProblem, 564 }, 565 } 566 for _, tt := range tests { 567 t.Run(tt.name, func(t *testing.T) { 568 oldDB := db.Db 569 defer func() { 570 db.Db = oldDB 571 }() 572 573 var rowMaps []sqlutils.RowMap 574 for _, analysis := range tt.info { 575 analysis.SetValuesFromTabletInfo() 576 rowMaps = append(rowMaps, analysis.ConvertToRowMap()) 577 } 578 db.Db = test.NewTestDB([][]sqlutils.RowMap{rowMaps}) 579 580 got, err := GetReplicationAnalysis("", "", &ReplicationAnalysisHints{}) 581 if tt.wantErr != "" { 582 require.EqualError(t, err, tt.wantErr) 583 return 584 } 585 require.NoError(t, err) 586 if tt.codeWanted == NoProblem { 587 require.Len(t, got, 0) 588 return 589 } 590 require.Len(t, got, 1) 591 require.Equal(t, tt.codeWanted, got[0].Analysis) 592 require.Equal(t, tt.keyspaceWanted, got[0].AnalyzedKeyspace) 593 require.Equal(t, tt.shardWanted, got[0].AnalyzedShard) 594 }) 595 } 596 } 597 598 // TestGetReplicationAnalysis tests the entire GetReplicationAnalysis. It inserts data into the database and runs the function. 599 // The database is not faked. This is intended to give more test coverage. This test is more comprehensive but more expensive than TestGetReplicationAnalysisDecision. 600 // This test is somewhere between a unit test, and an end-to-end test. It is specifically useful for testing situations which are hard to come by in end-to-end test, but require 601 // real-world data to test specifically. 602 func TestGetReplicationAnalysis(t *testing.T) { 603 // The initialSQL is a set of insert commands copied from a dump of an actual running VTOrc instances. The relevant insert commands are here. 604 // This is a dump taken from a test running 4 tablets, zone1-101 is the primary, zone1-100 is a replica, zone1-112 is a rdonly and zone2-200 is a cross-cell replica. 605 initialSQL := []string{ 606 `INSERT INTO database_instance VALUES('localhost',6747,'2022-12-28 07:26:04','2022-12-28 07:26:04',213696377,'8.0.31','ROW',1,1,'vt-0000000112-bin.000001',15963,'localhost',6714,1,1,'vt-0000000101-bin.000001',15583,'vt-0000000101-bin.000001',15583,0,0,1,'','',1,0,'vt-0000000112-relay-bin.000002',15815,0,1,0,'zone1','',0,0,0,1,'729a4cc4-8680-11ed-a104-47706090afbd:1-54','729a5138-8680-11ed-9240-92a06c3be3c2','2022-12-28 07:26:04','',1,0,0,'zone1-0000000112','Homebrew','8.0','FULL',10816929,0,0,'ON',1,'729a4cc4-8680-11ed-a104-47706090afbd','','729a4cc4-8680-11ed-a104-47706090afbd,729a5138-8680-11ed-9240-92a06c3be3c2',1,1,'',1000000000000000000,1,0,0,0,'',0,'','','[]','',0);`, 607 `INSERT INTO database_instance VALUES('localhost',6711,'2022-12-28 07:26:04','2022-12-28 07:26:04',1094500338,'8.0.31','ROW',1,1,'vt-0000000100-bin.000001',15963,'localhost',6714,1,1,'vt-0000000101-bin.000001',15583,'vt-0000000101-bin.000001',15583,0,0,1,'','',1,0,'vt-0000000100-relay-bin.000002',15815,0,1,0,'zone1','',0,0,0,1,'729a4cc4-8680-11ed-a104-47706090afbd:1-54','729a5138-8680-11ed-acf8-d6b0ef9f4eaa','2022-12-28 07:26:04','',1,0,0,'zone1-0000000100','Homebrew','8.0','FULL',10103920,0,1,'ON',1,'729a4cc4-8680-11ed-a104-47706090afbd','','729a4cc4-8680-11ed-a104-47706090afbd,729a5138-8680-11ed-acf8-d6b0ef9f4eaa',1,1,'',1000000000000000000,1,0,1,0,'',0,'','','[]','',0);`, 608 `INSERT INTO database_instance VALUES('localhost',6714,'2022-12-28 07:26:04','2022-12-28 07:26:04',390954723,'8.0.31','ROW',1,1,'vt-0000000101-bin.000001',15583,'',0,0,0,'',0,'',0,NULL,NULL,0,'','',0,0,'',0,0,0,0,'zone1','',0,0,0,1,'729a4cc4-8680-11ed-a104-47706090afbd:1-54','729a4cc4-8680-11ed-a104-47706090afbd','2022-12-28 07:26:04','',0,0,0,'zone1-0000000101','Homebrew','8.0','FULL',11366095,1,1,'ON',1,'','','729a4cc4-8680-11ed-a104-47706090afbd',-1,-1,'',1000000000000000000,1,1,0,2,'',0,'','','[]','',0);`, 609 `INSERT INTO database_instance VALUES('localhost',6756,'2022-12-28 07:26:05','2022-12-28 07:26:05',444286571,'8.0.31','ROW',1,1,'vt-0000000200-bin.000001',15963,'localhost',6714,1,1,'vt-0000000101-bin.000001',15583,'vt-0000000101-bin.000001',15583,0,0,1,'','',1,0,'vt-0000000200-relay-bin.000002',15815,0,1,0,'zone2','',0,0,0,1,'729a4cc4-8680-11ed-a104-47706090afbd:1-54','729a497c-8680-11ed-8ad4-3f51d747db75','2022-12-28 07:26:05','',1,0,0,'zone2-0000000200','Homebrew','8.0','FULL',10443112,0,1,'ON',1,'729a4cc4-8680-11ed-a104-47706090afbd','','729a4cc4-8680-11ed-a104-47706090afbd,729a497c-8680-11ed-8ad4-3f51d747db75',1,1,'',1000000000000000000,1,0,1,0,'',0,'','','[]','',0);`, 610 `INSERT INTO vitess_tablet VALUES('zone1-0000000100','localhost',6711,'ks','0','zone1',2,'0001-01-01 00:00:00+00:00',X'616c6961733a7b63656c6c3a227a6f6e653122207569643a3130307d20686f73746e616d653a226c6f63616c686f73742220706f72745f6d61703a7b6b65793a2267727063222076616c75653a363731307d20706f72745f6d61703a7b6b65793a227674222076616c75653a363730397d206b657973706163653a226b73222073686172643a22302220747970653a5245504c494341206d7973716c5f686f73746e616d653a226c6f63616c686f737422206d7973716c5f706f72743a363731312064625f7365727665725f76657273696f6e3a22382e302e3331222064656661756c745f636f6e6e5f636f6c6c6174696f6e3a3435');`, 611 `INSERT INTO vitess_tablet VALUES('zone1-0000000101','localhost',6714,'ks','0','zone1',1,'2022-12-28 07:23:25.129898+00:00',X'616c6961733a7b63656c6c3a227a6f6e653122207569643a3130317d20686f73746e616d653a226c6f63616c686f73742220706f72745f6d61703a7b6b65793a2267727063222076616c75653a363731337d20706f72745f6d61703a7b6b65793a227674222076616c75653a363731327d206b657973706163653a226b73222073686172643a22302220747970653a5052494d415259206d7973716c5f686f73746e616d653a226c6f63616c686f737422206d7973716c5f706f72743a36373134207072696d6172795f7465726d5f73746172745f74696d653a7b7365636f6e64733a31363732323132323035206e616e6f7365636f6e64733a3132393839383030307d2064625f7365727665725f76657273696f6e3a22382e302e3331222064656661756c745f636f6e6e5f636f6c6c6174696f6e3a3435');`, 612 `INSERT INTO vitess_tablet VALUES('zone1-0000000112','localhost',6747,'ks','0','zone1',3,'0001-01-01 00:00:00+00:00',X'616c6961733a7b63656c6c3a227a6f6e653122207569643a3131327d20686f73746e616d653a226c6f63616c686f73742220706f72745f6d61703a7b6b65793a2267727063222076616c75653a363734367d20706f72745f6d61703a7b6b65793a227674222076616c75653a363734357d206b657973706163653a226b73222073686172643a22302220747970653a52444f4e4c59206d7973716c5f686f73746e616d653a226c6f63616c686f737422206d7973716c5f706f72743a363734372064625f7365727665725f76657273696f6e3a22382e302e3331222064656661756c745f636f6e6e5f636f6c6c6174696f6e3a3435');`, 613 `INSERT INTO vitess_tablet VALUES('zone2-0000000200','localhost',6756,'ks','0','zone2',2,'0001-01-01 00:00:00+00:00',X'616c6961733a7b63656c6c3a227a6f6e653222207569643a3230307d20686f73746e616d653a226c6f63616c686f73742220706f72745f6d61703a7b6b65793a2267727063222076616c75653a363735357d20706f72745f6d61703a7b6b65793a227674222076616c75653a363735347d206b657973706163653a226b73222073686172643a22302220747970653a5245504c494341206d7973716c5f686f73746e616d653a226c6f63616c686f737422206d7973716c5f706f72743a363735362064625f7365727665725f76657273696f6e3a22382e302e3331222064656661756c745f636f6e6e5f636f6c6c6174696f6e3a3435');`, 614 `INSERT INTO vitess_keyspace VALUES('ks',0,'semi_sync');`, 615 } 616 617 // The test is intended to be used as follows. The initial data is stored into the database. Following this, some specific queries are run that each individual test specifies to get the desired state. 618 tests := []struct { 619 name string 620 sql []string 621 codeWanted AnalysisCode 622 shardWanted string 623 keyspaceWanted string 624 }{ 625 { 626 name: "No additions", 627 sql: nil, 628 codeWanted: NoProblem, 629 }, { 630 name: "Removing Primary Tablet's Vitess record", 631 sql: []string{ 632 // This query removes the primary tablet's vitess_tablet record 633 `delete from vitess_tablet where port = 6714`, 634 }, 635 codeWanted: ClusterHasNoPrimary, 636 keyspaceWanted: "ks", 637 shardWanted: "0", 638 }, { 639 name: "Removing Primary Tablet's MySQL record", 640 sql: []string{ 641 // This query removes the primary tablet's database_instance record 642 `delete from database_instance where port = 6714`, 643 }, 644 // As long as we have the vitess record stating that this tablet is the primary 645 // It would be incorrect to run a PRS. 646 // This situation only happens when we haven't been able to read the MySQL information even once for this tablet. 647 // So it is likely a new tablet. 648 codeWanted: NoProblem, 649 }, { 650 name: "Removing Replica Tablet's MySQL record", 651 sql: []string{ 652 // This query removes the replica tablet's database_instance record 653 `delete from database_instance where port = 6711`, 654 }, 655 // As long as we don't have the MySQL information, we shouldn't do anything. 656 // We should wait for the MySQL information to be refreshed once. 657 // This situation only happens when we haven't been able to read the MySQL information even once for this tablet. 658 // So it is likely a new tablet. 659 codeWanted: NoProblem, 660 }, 661 } 662 663 for _, tt := range tests { 664 t.Run(tt.name, func(t *testing.T) { 665 // Each test should clear the database. The easiest way to do that is to run all the initialization commands again 666 defer func() { 667 db.ClearVTOrcDatabase() 668 }() 669 670 for _, query := range append(initialSQL, tt.sql...) { 671 _, err := db.ExecVTOrc(query) 672 require.NoError(t, err) 673 } 674 675 got, err := GetReplicationAnalysis("", "", &ReplicationAnalysisHints{}) 676 require.NoError(t, err) 677 if tt.codeWanted == NoProblem { 678 require.Len(t, got, 0) 679 return 680 } 681 require.Len(t, got, 1) 682 require.Equal(t, tt.codeWanted, got[0].Analysis) 683 require.Equal(t, tt.keyspaceWanted, got[0].AnalyzedKeyspace) 684 require.Equal(t, tt.shardWanted, got[0].AnalyzedShard) 685 }) 686 } 687 }