vitess.io/vitess@v0.16.2/go/test/endtoend/keyspace/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 sequence 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "encoding/json" 23 "flag" 24 "os" 25 "strings" 26 "testing" 27 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/require" 30 31 "vitess.io/vitess/go/test/endtoend/cluster" 32 "vitess.io/vitess/go/vt/proto/topodata" 33 ) 34 35 var ( 36 clusterForKSTest *cluster.LocalProcessCluster 37 keyspaceShardedName = "test_ks_sharded" 38 keyspaceUnshardedName = "test_ks_unsharded" 39 cell = "zone1" 40 cell2 = "zone2" 41 hostname = "localhost" 42 servedTypes = map[topodata.TabletType]bool{topodata.TabletType_PRIMARY: true, topodata.TabletType_REPLICA: true, topodata.TabletType_RDONLY: true} 43 sqlSchema = `create table vt_insert_test ( 44 id bigint auto_increment, 45 msg varchar(64), 46 keyspace_id bigint(20) unsigned NOT NULL, 47 primary key (id) 48 ) Engine=InnoDB` 49 vSchema = `{ 50 "sharded": true, 51 "vindexes": { 52 "hash_index": { 53 "type": "hash" 54 } 55 }, 56 "tables": { 57 "vt_insert_test": { 58 "column_vindexes": [ 59 { 60 "column": "keyspace_id", 61 "name": "hash_index" 62 } 63 ] 64 } 65 } 66 }` 67 shardKIdMap = map[string][]uint64{ 68 "-80": {527875958493693904, 626750931627689502, 69 345387386794260318, 332484755310826578, 70 1842642426274125671, 1326307661227634652, 71 1761124146422844620, 1661669973250483744, 72 3361397649937244239, 2444880764308344533}, 73 "80-": {9767889778372766922, 9742070682920810358, 74 10296850775085416642, 9537430901666854108, 75 10440455099304929791, 11454183276974683945, 76 11185910247776122031, 10460396697869122981, 77 13379616110062597001, 12826553979133932576}, 78 } 79 ) 80 81 func TestMain(m *testing.M) { 82 defer cluster.PanicHandler(nil) 83 flag.Parse() 84 85 exitCode := func() int { 86 clusterForKSTest = cluster.NewCluster(cell, hostname) 87 defer clusterForKSTest.Teardown() 88 89 // Start topo server 90 if err := clusterForKSTest.StartTopo(); err != nil { 91 return 1 92 } 93 94 if err := clusterForKSTest.TopoProcess.ManageTopoDir("mkdir", "/vitess/"+cell2); err != nil { 95 return 1 96 } 97 98 if err := clusterForKSTest.VtctlProcess.AddCellInfo(cell2); err != nil { 99 return 1 100 } 101 102 // Start sharded keyspace 103 keyspaceSharded := &cluster.Keyspace{ 104 Name: keyspaceShardedName, 105 SchemaSQL: sqlSchema, 106 VSchema: vSchema, 107 } 108 if err := clusterForKSTest.StartKeyspace(*keyspaceSharded, []string{"-80", "80-"}, 1, false); err != nil { 109 return 1 110 } 111 if err := clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", keyspaceShardedName); err != nil { 112 return 1 113 } 114 115 // Start unsharded keyspace 116 keyspaceUnsharded := &cluster.Keyspace{ 117 Name: keyspaceUnshardedName, 118 SchemaSQL: sqlSchema, 119 } 120 if err := clusterForKSTest.StartKeyspace(*keyspaceUnsharded, []string{keyspaceUnshardedName}, 1, false); err != nil { 121 return 1 122 } 123 if err := clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", keyspaceUnshardedName); err != nil { 124 return 1 125 } 126 127 // Start vtgate 128 if err := clusterForKSTest.StartVtgate(); err != nil { 129 return 1 130 } 131 132 return m.Run() 133 }() 134 os.Exit(exitCode) 135 } 136 137 // TestDurabilityPolicyField tests that the DurabilityPolicy field of a keyspace can be set during creation, read and updated later 138 // from vtctld server and the vtctl binary 139 func TestDurabilityPolicyField(t *testing.T) { 140 vtctldClientProcess := cluster.VtctldClientProcessInstance("localhost", clusterForKSTest.VtctldProcess.GrpcPort, clusterForKSTest.TmpDirectory) 141 142 out, err := vtctldClientProcess.ExecuteCommandWithOutput("CreateKeyspace", "ks_durability", "--durability-policy=semi_sync") 143 require.NoError(t, err, out) 144 checkDurabilityPolicy(t, "semi_sync") 145 146 out, err = vtctldClientProcess.ExecuteCommandWithOutput("SetKeyspaceDurabilityPolicy", "ks_durability", "--durability-policy=none") 147 require.NoError(t, err, out) 148 checkDurabilityPolicy(t, "none") 149 150 out, err = vtctldClientProcess.ExecuteCommandWithOutput("DeleteKeyspace", "ks_durability") 151 require.NoError(t, err, out) 152 153 out, err = clusterForKSTest.VtctlProcess.ExecuteCommandWithOutput("CreateKeyspace", "--", "--durability-policy=semi_sync", "ks_durability") 154 require.NoError(t, err, out) 155 checkDurabilityPolicy(t, "semi_sync") 156 157 out, err = clusterForKSTest.VtctlProcess.ExecuteCommandWithOutput("DeleteKeyspace", "ks_durability") 158 require.NoError(t, err, out) 159 } 160 161 func checkDurabilityPolicy(t *testing.T, durabilityPolicy string) { 162 var keyspace topodata.Keyspace 163 out, err := clusterForKSTest.VtctlclientProcess.ExecuteCommandWithOutput("GetKeyspace", "ks_durability") 164 require.NoError(t, err, out) 165 err = json.Unmarshal([]byte(out), &keyspace) 166 require.NoError(t, err) 167 require.Equal(t, keyspace.DurabilityPolicy, durabilityPolicy) 168 } 169 170 func TestGetSrvKeyspaceNames(t *testing.T) { 171 defer cluster.PanicHandler(t) 172 output, err := clusterForKSTest.VtctlclientProcess.ExecuteCommandWithOutput("GetSrvKeyspaceNames", cell) 173 require.Nil(t, err) 174 assert.Contains(t, strings.Split(output, "\n"), keyspaceUnshardedName) 175 assert.Contains(t, strings.Split(output, "\n"), keyspaceShardedName) 176 } 177 178 func TestGetSrvKeyspacePartitions(t *testing.T) { 179 defer cluster.PanicHandler(t) 180 shardedSrvKeyspace := getSrvKeyspace(t, cell, keyspaceShardedName) 181 otherShardRefFound := false 182 for _, partition := range shardedSrvKeyspace.Partitions { 183 if servedTypes[partition.ServedType] { 184 for _, shardRef := range partition.ShardReferences { 185 assert.True(t, shardRef.Name == "-80" || shardRef.Name == "80-") 186 } 187 } else { 188 otherShardRefFound = true 189 } 190 } 191 assert.True(t, !otherShardRefFound) 192 193 unShardedSrvKeyspace := getSrvKeyspace(t, cell, keyspaceUnshardedName) 194 otherShardRefFound = false 195 for _, partition := range unShardedSrvKeyspace.Partitions { 196 if servedTypes[partition.ServedType] { 197 for _, shardRef := range partition.ShardReferences { 198 assert.True(t, shardRef.Name == keyspaceUnshardedName) 199 } 200 } else { 201 otherShardRefFound = true 202 } 203 } 204 assert.True(t, !otherShardRefFound) 205 } 206 207 func TestShardNames(t *testing.T) { 208 defer cluster.PanicHandler(t) 209 output, err := clusterForKSTest.VtctlclientProcess.ExecuteCommandWithOutput("GetSrvKeyspace", cell, keyspaceShardedName) 210 require.Nil(t, err) 211 var srvKeyspace topodata.SrvKeyspace 212 213 err = json.Unmarshal([]byte(output), &srvKeyspace) 214 require.Nil(t, err) 215 } 216 217 func TestGetKeyspace(t *testing.T) { 218 defer cluster.PanicHandler(t) 219 output, err := clusterForKSTest.VtctlclientProcess.ExecuteCommandWithOutput("GetKeyspace", keyspaceUnshardedName) 220 require.Nil(t, err) 221 222 var keyspace topodata.Keyspace 223 224 err = json.Unmarshal([]byte(output), &keyspace) 225 require.Nil(t, err) 226 } 227 228 func TestDeleteKeyspace(t *testing.T) { 229 defer cluster.PanicHandler(t) 230 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateKeyspace", "test_delete_keyspace") 231 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateShard", "test_delete_keyspace/0") 232 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--", "--keyspace=test_delete_keyspace", "--shard=0", "zone1-0000000100", "primary") 233 234 // Can't delete keyspace if there are shards present. 235 err := clusterForKSTest.VtctlclientProcess.ExecuteCommand("DeleteKeyspace", "test_delete_keyspace") 236 require.Error(t, err) 237 238 // Can't delete shard if there are tablets present. 239 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("DeleteShard", "--", "--even_if_serving", "test_delete_keyspace/0") 240 require.Error(t, err) 241 242 // Use recursive DeleteShard to remove tablets. 243 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("DeleteShard", "--", "--even_if_serving", "--recursive", "test_delete_keyspace/0") 244 // Now non-recursive DeleteKeyspace should work. 245 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("DeleteKeyspace", "test_delete_keyspace") 246 247 // Start over and this time use recursive DeleteKeyspace to do everything. 248 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateKeyspace", "test_delete_keyspace") 249 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateShard", "test_delete_keyspace/0") 250 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--", "--port=1234", "--keyspace=test_delete_keyspace", "--shard=0", "zone1-0000000100", "primary") 251 252 // Create the serving/replication entries and check that they exist, 253 // so we can later check they're deleted. 254 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", "test_delete_keyspace") 255 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", cell, "test_delete_keyspace/0") 256 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetSrvKeyspace", cell, "test_delete_keyspace") 257 258 // Recursive DeleteKeyspace 259 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("DeleteKeyspace", "--", "--recursive", "test_delete_keyspace") 260 261 // Check that everything is gone. 262 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetKeyspace", "test_delete_keyspace") 263 require.Error(t, err) 264 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShard", "test_delete_keyspace/0") 265 require.Error(t, err) 266 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetTablet", "zone1-0000000100") 267 require.Error(t, err) 268 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", cell, "test_delete_keyspace/0") 269 require.Error(t, err) 270 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetSrvKeyspace", cell, "test_delete_keyspace") 271 require.Error(t, err) 272 } 273 274 // TODO: Fix this test, not running in CI 275 // TODO: (ajm188) if this test gets fixed, the flags need to be updated to comply with VEP-4 as well. 276 // tells that in zone2 after deleting shard, there is no shard #264 and in zone1 there is only 1 #269 277 /*func RemoveKeyspaceCell(t *testing.T) { 278 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateKeyspace", "test_delete_keyspace_removekscell") 279 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateShard", "test_delete_keyspace_removekscell/0") 280 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("CreateShard", "test_delete_keyspace_removekscell/1") 281 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--port=1234", "-keyspace=test_delete_keyspace_removekscell", "--shard=0", "zone1-0000000100", "primary") 282 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--port=1234", "-keyspace=test_delete_keyspace_removekscell", "--shard=1", "zone1-0000000101", "primary") 283 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--port=1234", "-keyspace=test_delete_keyspace_removekscell", "--shard=0", "zone2-0000000100", "replica") 284 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--port=1234", "-keyspace=test_delete_keyspace_removekscell", "--shard=1", "zone2-0000000101", "replica") 285 286 // Create the serving/replication entries and check that they exist, so we can later check they're deleted. 287 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", "test_delete_keyspace_removekscell") 288 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/0") 289 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/1") 290 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetSrvKeyspace", "zone2", "test_delete_keyspace_removekscell") 291 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetSrvKeyspace", "zone1", "test_delete_keyspace_removekscell") 292 293 // Just remove the shard from one cell (including tablets), 294 // but leaving the global records and other cells/shards alone. 295 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RemoveShardCell", "--recursive", "test_delete_keyspace_removekscell/0", "zone2") 296 297 //Check that the shard is gone from zone2. 298 srvKeyspaceZone2 := getSrvKeyspace(t, cell2, "test_delete_keyspace_removekscell") 299 300 for _, partition := range srvKeyspaceZone2.Partitions { 301 assert.Equal(t, len(partition.ShardReferences), 1) 302 } 303 304 srvKeyspaceZone1 := getSrvKeyspace(t, cell, "test_delete_keyspace_removekscell") 305 for _, partition := range srvKeyspaceZone1.Partitions { 306 assert.Equal(t, len(partition.ShardReferences), 2) 307 } 308 309 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", "test_delete_keyspace_removekscell") 310 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetKeyspace", "test_delete_keyspace_removekscell") 311 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShard", "test_delete_keyspace_removekscell/0") 312 313 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetTablet", "zone1-0000000100") 314 315 err := clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetTablet", "zone2-0000000100") 316 require.Error(t, err) 317 318 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetTablet", "zone2-0000000101") 319 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone1", "test_delete_keyspace_removekscell/0") 320 321 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/0") 322 require.Error(t, err) 323 324 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/1") 325 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetSrvKeyspace", "zone2", "test_delete_keyspace_removekscell") 326 327 // Add it back to do another test. 328 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("InitTablet", "--port=1234", "--keyspace=test_delete_keyspace_removekscell", "--shard=0", "zone2-0000000100", "replica") 329 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", "test_delete_keyspace_removekscell") 330 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/0") 331 332 // Now use RemoveKeyspaceCell to remove all shards. 333 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RemoveKeyspaceCell", "-recursive", "test_delete_keyspace_removekscell", "zone2") 334 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", "test_delete_keyspace_removekscell") 335 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone1", "test_delete_keyspace_removekscell/0") 336 337 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/0") 338 require.Error(t, err) 339 340 err = clusterForKSTest.VtctlclientProcess.ExecuteCommand("GetShardReplication", "zone2", "test_delete_keyspace_removekscell/1") 341 require.Error(t, err) 342 343 // Clean up 344 _ = clusterForKSTest.VtctlclientProcess.ExecuteCommand("DeleteKeyspace", "-recursive", "test_delete_keyspace_removekscell") 345 } */ 346 347 func TestShardCountForAllKeyspaces(t *testing.T) { 348 defer cluster.PanicHandler(t) 349 testShardCountForKeyspace(t, keyspaceUnshardedName, 1) 350 testShardCountForKeyspace(t, keyspaceShardedName, 2) 351 } 352 353 func testShardCountForKeyspace(t *testing.T, keyspace string, count int) { 354 srvKeyspace := getSrvKeyspace(t, cell, keyspace) 355 356 // for each served type PRIMARY REPLICA RDONLY, the shard ref count should match 357 for _, partition := range srvKeyspace.Partitions { 358 if servedTypes[partition.ServedType] { 359 assert.Equal(t, len(partition.ShardReferences), count) 360 } 361 } 362 } 363 364 func TestShardNameForAllKeyspaces(t *testing.T) { 365 defer cluster.PanicHandler(t) 366 testShardNameForKeyspace(t, keyspaceUnshardedName, []string{"test_ks_unsharded"}) 367 testShardNameForKeyspace(t, keyspaceShardedName, []string{"-80", "80-"}) 368 } 369 370 func testShardNameForKeyspace(t *testing.T, keyspace string, shardNames []string) { 371 srvKeyspace := getSrvKeyspace(t, cell, keyspace) 372 373 // for each served type PRIMARY REPLICA RDONLY, the shard ref count should match 374 for _, partition := range srvKeyspace.Partitions { 375 if servedTypes[partition.ServedType] { 376 for _, shardRef := range partition.ShardReferences { 377 assert.Contains(t, shardNames, shardRef.Name) 378 } 379 } 380 } 381 } 382 383 func TestKeyspaceToShardName(t *testing.T) { 384 defer cluster.PanicHandler(t) 385 var id []byte 386 srvKeyspace := getSrvKeyspace(t, cell, keyspaceShardedName) 387 388 // for each served type PRIMARY REPLICA RDONLY, the shard ref count should match 389 for _, partition := range srvKeyspace.Partitions { 390 if partition.ServedType == topodata.TabletType_PRIMARY { 391 for _, shardRef := range partition.ShardReferences { 392 shardKIDs := shardKIdMap[shardRef.Name] 393 for _, kid := range shardKIDs { 394 id = packKeyspaceID(kid) 395 assert.True(t, bytes.Compare(shardRef.KeyRange.Start, id) <= 0 && 396 (len(shardRef.KeyRange.End) == 0 || bytes.Compare(id, shardRef.KeyRange.End) < 0)) 397 } 398 } 399 } 400 } 401 402 srvKeyspace = getSrvKeyspace(t, cell, keyspaceUnshardedName) 403 404 for _, partition := range srvKeyspace.Partitions { 405 if partition.ServedType == topodata.TabletType_PRIMARY { 406 for _, shardRef := range partition.ShardReferences { 407 assert.Equal(t, shardRef.Name, keyspaceUnshardedName) 408 } 409 } 410 } 411 } 412 413 // packKeyspaceID packs this into big-endian and returns byte[] to do a byte-wise comparison. 414 func packKeyspaceID(keyspaceID uint64) []byte { 415 var keybytes [8]byte 416 binary.BigEndian.PutUint64(keybytes[:], keyspaceID) 417 return (keybytes[:]) 418 } 419 420 func getSrvKeyspace(t *testing.T, cell string, ksname string) *topodata.SrvKeyspace { 421 output, err := clusterForKSTest.VtctlclientProcess.ExecuteCommandWithOutput("GetSrvKeyspace", cell, ksname) 422 require.Nil(t, err) 423 var srvKeyspace topodata.SrvKeyspace 424 425 err = json.Unmarshal([]byte(output), &srvKeyspace) 426 require.Nil(t, err) 427 return &srvKeyspace 428 }