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  }