Repository: vitessio/vitess
Pull request #5595 (2019-12-19 07:02:14)

Vertical split testcase migrated in go
**Vertical split testcase**
Vertical split endtoend testcase migrated from python and using default RBR mode.

Signed-off-by: saurabh408 <saurabh.408@gmail.com>


Patch:
diff --git a/go.mod b/go.mod
index 9b281e72f5..af52af7313 100644
--- a/go.mod
+++ b/go.mod
@@ -25,6 +25,7 @@ require (
 	github.com/golang/mock v1.3.1
 	github.com/golang/protobuf v1.3.2
 	github.com/golang/snappy v0.0.0-20170215233205-553a64147049
+	github.com/google/btree v1.0.0 // indirect
 	github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf // indirect
 	github.com/gorilla/websocket v0.0.0-20160912153041-2d1e4548da23
 	github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
@@ -49,6 +50,8 @@ require (
 	github.com/minio/minio-go v0.0.0-20190131015406-c8a261de75c1
 	github.com/mitchellh/go-testing-interface v1.0.0 // indirect
 	github.com/mitchellh/mapstructure v1.1.2 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.1 // indirect
 	github.com/olekukonko/tablewriter v0.0.0-20160115111002-cca8bbc07984
 	github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02
 	github.com/opentracing/opentracing-go v1.1.0
diff --git a/go/vt/vtgate/vindexes/binary.go b/go/vt/vtgate/vindexes/binary.go
index 2affb723c0..50d0500a9b 100644
--- a/go/vt/vtgate/vindexes/binary.go
+++ b/go/vt/vtgate/vindexes/binary.go
@@ -54,11 +54,6 @@ func (vind *Binary) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *Binary) NeedsVCursor() bool {
-	return false
-}
-
 // Verify returns true if ids maps to ksids.
 func (vind *Binary) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) {
 	out := make([]bool, len(ids))
diff --git a/go/vt/vtgate/vindexes/binarymd5.go b/go/vt/vtgate/vindexes/binarymd5.go
index c2327b9ae2..be6cea7931 100644
--- a/go/vt/vtgate/vindexes/binarymd5.go
+++ b/go/vt/vtgate/vindexes/binarymd5.go
@@ -53,11 +53,6 @@ func (vind *BinaryMD5) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *BinaryMD5) NeedsVCursor() bool {
-	return false
-}
-
 // Verify returns true if ids maps to ksids.
 func (vind *BinaryMD5) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) {
 	out := make([]bool, len(ids))
diff --git a/go/vt/vtgate/vindexes/consistent_lookup.go b/go/vt/vtgate/vindexes/consistent_lookup.go
index a2bc94915e..6d862e7c8c 100644
--- a/go/vt/vtgate/vindexes/consistent_lookup.go
+++ b/go/vt/vtgate/vindexes/consistent_lookup.go
@@ -75,11 +75,6 @@ func (lu *ConsistentLookup) IsUnique() bool {
 	return false
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lu *ConsistentLookup) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lu *ConsistentLookup) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
@@ -134,11 +129,6 @@ func (lu *ConsistentLookupUnique) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lu *ConsistentLookupUnique) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lu *ConsistentLookupUnique) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
diff --git a/go/vt/vtgate/vindexes/hash.go b/go/vt/vtgate/vindexes/hash.go
index 21b93dfe88..1811750402 100644
--- a/go/vt/vtgate/vindexes/hash.go
+++ b/go/vt/vtgate/vindexes/hash.go
@@ -64,11 +64,6 @@ func (vind *Hash) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *Hash) NeedsVCursor() bool {
-	return false
-}
-
 // Map can map ids to key.Destination objects.
 func (vind *Hash) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, len(ids))
diff --git a/go/vt/vtgate/vindexes/lookup.go b/go/vt/vtgate/vindexes/lookup.go
index 5474cc1788..6f13abb0e5 100644
--- a/go/vt/vtgate/vindexes/lookup.go
+++ b/go/vt/vtgate/vindexes/lookup.go
@@ -61,11 +61,6 @@ func (ln *LookupNonUnique) IsUnique() bool {
 	return false
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (ln *LookupNonUnique) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (ln *LookupNonUnique) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
@@ -216,11 +211,6 @@ func (lu *LookupUnique) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lu *LookupUnique) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lu *LookupUnique) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
diff --git a/go/vt/vtgate/vindexes/lookup_hash.go b/go/vt/vtgate/vindexes/lookup_hash.go
index a9d2ec0102..46809ad4b7 100644
--- a/go/vt/vtgate/vindexes/lookup_hash.go
+++ b/go/vt/vtgate/vindexes/lookup_hash.go
@@ -93,11 +93,6 @@ func (lh *LookupHash) IsUnique() bool {
 	return false
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lh *LookupHash) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lh *LookupHash) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
@@ -249,11 +244,6 @@ func (lhu *LookupHashUnique) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lhu *LookupHashUnique) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lhu *LookupHashUnique) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
diff --git a/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go b/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go
index fccec4ec11..f56d302c81 100644
--- a/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go
+++ b/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go
@@ -94,11 +94,6 @@ func (lh *LookupUnicodeLooseMD5Hash) IsUnique() bool {
 	return false
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lh *LookupUnicodeLooseMD5Hash) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lh *LookupUnicodeLooseMD5Hash) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
@@ -261,11 +256,6 @@ func (lhu *LookupUnicodeLooseMD5HashUnique) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (lhu *LookupUnicodeLooseMD5HashUnique) NeedsVCursor() bool {
-	return true
-}
-
 // Map can map ids to key.Destination objects.
 func (lhu *LookupUnicodeLooseMD5HashUnique) Map(vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
diff --git a/go/vt/vtgate/vindexes/null.go b/go/vt/vtgate/vindexes/null.go
index 5f8b9b7f1a..d3fc3fc56b 100644
--- a/go/vt/vtgate/vindexes/null.go
+++ b/go/vt/vtgate/vindexes/null.go
@@ -48,9 +48,9 @@ func (vind *Null) String() string {
 	return vind.name
 }
 
-// Cost returns the cost of this index as 100.
+// Cost returns the cost of this index as 0.
 func (vind *Null) Cost() int {
-	return 100
+	return 0
 }
 
 // IsUnique returns true since the Vindex is unique.
@@ -58,11 +58,6 @@ func (vind *Null) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *Null) NeedsVCursor() bool {
-	return false
-}
-
 // Map can map ids to key.Destination objects.
 func (vind *Null) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, 0, len(ids))
diff --git a/go/vt/vtgate/vindexes/numeric.go b/go/vt/vtgate/vindexes/numeric.go
index 3b34b8a229..8ebdbe5c2d 100644
--- a/go/vt/vtgate/vindexes/numeric.go
+++ b/go/vt/vtgate/vindexes/numeric.go
@@ -57,11 +57,6 @@ func (*Numeric) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (*Numeric) NeedsVCursor() bool {
-	return false
-}
-
 // Verify returns true if ids and ksids match.
 func (*Numeric) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) {
 	out := make([]bool, len(ids))
diff --git a/go/vt/vtgate/vindexes/numeric_static_map.go b/go/vt/vtgate/vindexes/numeric_static_map.go
index 6a1ac7ecbc..39832aa377 100644
--- a/go/vt/vtgate/vindexes/numeric_static_map.go
+++ b/go/vt/vtgate/vindexes/numeric_static_map.go
@@ -80,11 +80,6 @@ func (vind *NumericStaticMap) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *NumericStaticMap) NeedsVCursor() bool {
-	return false
-}
-
 // Verify returns true if ids and ksids match.
 func (vind *NumericStaticMap) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) {
 	out := make([]bool, len(ids))
diff --git a/go/vt/vtgate/vindexes/region_experimental.go b/go/vt/vtgate/vindexes/region_experimental.go
index 340e880e24..ba10a10f7d 100644
--- a/go/vt/vtgate/vindexes/region_experimental.go
+++ b/go/vt/vtgate/vindexes/region_experimental.go
@@ -79,11 +79,6 @@ func (ge *RegionExperimental) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (ge *RegionExperimental) NeedsVCursor() bool {
-	return false
-}
-
 // Map satisfies MultiColumn.
 func (ge *RegionExperimental) Map(vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) {
 	destinations := make([]key.Destination, 0, len(rowsColValues))
diff --git a/go/vt/vtgate/vindexes/reverse_bits.go b/go/vt/vtgate/vindexes/reverse_bits.go
index d79d1f8a23..f199eaaea3 100644
--- a/go/vt/vtgate/vindexes/reverse_bits.go
+++ b/go/vt/vtgate/vindexes/reverse_bits.go
@@ -59,11 +59,6 @@ func (vind *ReverseBits) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *ReverseBits) NeedsVCursor() bool {
-	return false
-}
-
 // Map returns the corresponding KeyspaceId values for the given ids.
 func (vind *ReverseBits) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, len(ids))
diff --git a/go/vt/vtgate/vindexes/unicodeloosemd5.go b/go/vt/vtgate/vindexes/unicodeloosemd5.go
index c62cf0ff80..ef3a70c9f1 100644
--- a/go/vt/vtgate/vindexes/unicodeloosemd5.go
+++ b/go/vt/vtgate/vindexes/unicodeloosemd5.go
@@ -62,11 +62,6 @@ func (vind *UnicodeLooseMD5) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *UnicodeLooseMD5) NeedsVCursor() bool {
-	return false
-}
-
 // Verify returns true if ids maps to ksids.
 func (vind *UnicodeLooseMD5) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) {
 	out := make([]bool, len(ids))
diff --git a/go/vt/vtgate/vindexes/vindex.go b/go/vt/vtgate/vindexes/vindex.go
index ce7951aec6..3d06668def 100644
--- a/go/vt/vtgate/vindexes/vindex.go
+++ b/go/vt/vtgate/vindexes/vindex.go
@@ -56,15 +56,8 @@ type Vindex interface {
 	Cost() int
 
 	// IsUnique returns true if the Vindex is unique.
-	// A Unique Vindex is allowed to return non-unique values like
-	// a keyrange. This is in situations where the vindex does not
-	// have enough information to map to a keyspace id. If so, such
-	// a vindex cannot be primary.
+	// Which means Map() maps to either a KeyRange or a single KeyspaceID.
 	IsUnique() bool
-
-	// NeedsVCursor returns true if the Vindex makes calls into the
-	// VCursor. Such vindexes cannot be used by vreplication.
-	NeedsVCursor() bool
 }
 
 // SingleColumn defines the interface for a single column vindex.
diff --git a/go/vt/vtgate/vindexes/xxhash.go b/go/vt/vtgate/vindexes/xxhash.go
index 8f17730116..fd648e3117 100644
--- a/go/vt/vtgate/vindexes/xxhash.go
+++ b/go/vt/vtgate/vindexes/xxhash.go
@@ -56,11 +56,6 @@ func (vind *XXHash) IsUnique() bool {
 	return true
 }
 
-// NeedsVCursor satisfies the Vindex interface.
-func (vind *XXHash) NeedsVCursor() bool {
-	return false
-}
-
 // Map can map ids to key.Destination objects.
 func (vind *XXHash) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) {
 	out := make([]key.Destination, len(ids))
diff --git a/go/vt/vttablet/tabletserver/vstreamer/local_vschema.go b/go/vt/vttablet/tabletserver/vstreamer/local_vschema.go
index 57343bd654..e6e8c61eaa 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/local_vschema.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/local_vschema.go
@@ -31,12 +31,16 @@ type localVSchema struct {
 	vschema  *vindexes.VSchema
 }
 
-func (lvs *localVSchema) FindColVindex(tablename string) (*vindexes.ColumnVindex, error) {
-	table, err := lvs.findTable(tablename)
-	if err != nil {
-		return nil, err
+func (lvs *localVSchema) FindTable(tablename string) (*vindexes.Table, error) {
+	ks, ok := lvs.vschema.Keyspaces[lvs.keyspace]
+	if !ok {
+		return nil, fmt.Errorf("keyspace %s not found in vschema", lvs.keyspace)
 	}
-	return identifyColVindex(table)
+	table := ks.Tables[tablename]
+	if table == nil {
+		return nil, fmt.Errorf("table %s not found", tablename)
+	}
+	return table, nil
 }
 
 func (lvs *localVSchema) FindOrCreateVindex(qualifiedName string) (vindexes.Vindex, error) {
@@ -62,37 +66,3 @@ func (lvs *localVSchema) FindOrCreateVindex(qualifiedName string) (vindexes.Vind
 	}
 	return vindexes.CreateVindex(name, name, map[string]string{})
 }
-
-func (lvs *localVSchema) findTable(tablename string) (*vindexes.Table, error) {
-	ks, ok := lvs.vschema.Keyspaces[lvs.keyspace]
-	if !ok {
-		return nil, fmt.Errorf("keyspace %s not found in vschema", lvs.keyspace)
-	}
-	table := ks.Tables[tablename]
-	if table == nil {
-		return nil, fmt.Errorf("table %s not found", tablename)
-	}
-	return table, nil
-}
-
-func identifyColVindex(table *vindexes.Table) (*vindexes.ColumnVindex, error) {
-	if len(table.ColumnVindexes) == 0 {
-		return nil, fmt.Errorf("table %s has no vindex", table.Name.String())
-	}
-	var result *vindexes.ColumnVindex
-	for _, cv := range table.ColumnVindexes {
-		if cv.Vindex.NeedsVCursor() {
-			continue
-		}
-		if !cv.Vindex.IsUnique() {
-			continue
-		}
-		if result == nil || result.Vindex.Cost() > cv.Vindex.Cost() {
-			result = cv
-		}
-	}
-	if result == nil {
-		return nil, fmt.Errorf("could not find a vindex to compute keyspace id for table %v", table.Name.String())
-	}
-	return result, nil
-}
diff --git a/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go b/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go
index 3422463add..dd5a58be79 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go
@@ -230,12 +230,16 @@ func buildREPlan(ti *Table, vschema *localVSchema, filter string) (*Plan, error)
 
 	// We need to additionally set VindexColumn, Vindex and KeyRange
 	// based on the Primary Vindex of the table.
-	cv, err := vschema.FindColVindex(ti.Name)
+	table, err := vschema.FindTable(ti.Name)
 	if err != nil {
 		return nil, err
 	}
-	plan.Vindex = cv.Vindex
-	plan.VindexColumns, err = buildVindexColumns(plan.Table, cv.Columns)
+	// Get Primary Vindex.
+	if len(table.ColumnVindexes) == 0 {
+		return nil, fmt.Errorf("table %s has no primary vindex", ti.Name)
+	}
+	plan.Vindex = table.ColumnVindexes[0].Vindex
+	plan.VindexColumns, err = buildVindexColumns(plan.Table, table.ColumnVindexes[0].Columns)
 	if err != nil {
 		return nil, err
 	}
@@ -361,16 +365,20 @@ func (plan *Plan) analyzeExpr(vschema *localVSchema, selExpr sqlparser.SelectExp
 		if len(inner.Exprs) != 0 {
 			return ColExpr{}, fmt.Errorf("unexpected: %v", sqlparser.String(inner))
 		}
-		cv, err := vschema.FindColVindex(plan.Table.Name)
+		table, err := vschema.FindTable(plan.Table.Name)
 		if err != nil {
 			return ColExpr{}, err
 		}
-		vindexColumns, err := buildVindexColumns(plan.Table, cv.Columns)
+		// Get Primary Vindex.
+		if len(table.ColumnVindexes) == 0 {
+			return ColExpr{}, fmt.Errorf("table %s has no primary vindex", plan.Table.Name)
+		}
+		vindexColumns, err := buildVindexColumns(plan.Table, table.ColumnVindexes[0].Columns)
 		if err != nil {
 			return ColExpr{}, err
 		}
 		return ColExpr{
-			Vindex:        cv.Vindex,
+			Vindex:        table.ColumnVindexes[0].Vindex,
 			VindexColumns: vindexColumns,
 			Alias:         sqlparser.NewColIdent("keyspace_id"),
 			Type:          sqltypes.VarBinary,
@@ -385,12 +393,16 @@ func (plan *Plan) analyzeInKeyRange(vschema *localVSchema, exprs sqlparser.Selec
 	var krExpr sqlparser.SelectExpr
 	switch {
 	case len(exprs) == 1:
-		cv, err := vschema.FindColVindex(plan.Table.Name)
+		table, err := vschema.FindTable(plan.Table.Name)
 		if err != nil {
 			return err
 		}
-		colnames = cv.Columns
-		plan.Vindex = cv.Vindex
+		// Get Primary Vindex.
+		if len(table.ColumnVindexes) == 0 {
+			return fmt.Errorf("table %s has no primary vindex", plan.Table.Name)
+		}
+		colnames = table.ColumnVindexes[0].Columns
+		plan.Vindex = table.ColumnVindexes[0].Vindex
 		krExpr = exprs[0]
 	case len(exprs) >= 3:
 		for _, expr := range exprs[:len(exprs)-2] {
diff --git a/tools/make-release-packages.sh b/tools/make-release-packages.sh
index 703997e0b9..6ec36c5e85 100755
--- a/tools/make-release-packages.sh
+++ b/tools/make-release-packages.sh
@@ -7,7 +7,7 @@
 set -euo pipefail
 
 # sudo gem install --no-ri --no-rdoc fpm
-# shellcheck disable=SC1091
+
 source build.env
 
 SHORT_REV="$(git rev-parse --short HEAD)"
@@ -43,8 +43,6 @@ done;
 # But resolving symlinks
 cp -rpfL {config,vthook,web,examples} "${RELEASE_DIR}/"
 
-echo "Follow the binary installation instructions at: https://vitess.io/docs/get-started/local/" > "${RELEASE_DIR}"/README.md
-
 cd "${RELEASE_DIR}/.."
 tar -czf "${TAR_FILE}" "${RELEASE_ID}"
 


Test patch:
diff --git a/go/test/endtoend/cellalias/cell_alias_test.go b/go/test/endtoend/cellalias/cell_alias_test.go
index 19c199a696..c9d816271a 100644
--- a/go/test/endtoend/cellalias/cell_alias_test.go
+++ b/go/test/endtoend/cellalias/cell_alias_test.go
@@ -289,11 +289,11 @@ func TestAlias(t *testing.T) {
 
 func waitTillAllTabletsAreHealthyInVtgate(t *testing.T, vtgateInstance cluster.VtgateProcess, shards ...string) {
 	for _, shard := range shards {
-		err := vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", keyspaceName, shard))
+		err := vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", keyspaceName, shard), 1)
 		assert.Nil(t, err)
-		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", keyspaceName, shard))
+		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", keyspaceName, shard), 1)
 		assert.Nil(t, err)
-		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard))
+		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard), 1)
 		assert.Nil(t, err)
 	}
 }
diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go
index 441a31dc5e..df1f13cc1b 100644
--- a/go/test/endtoend/cluster/cluster_process.go
+++ b/go/test/endtoend/cluster/cluster_process.go
@@ -423,10 +423,10 @@ func (cluster *LocalProcessCluster) WaitForTabletsToHealthyInVtgate() (err error
 	for _, keyspace := range cluster.Keyspaces {
 		for _, shard := range keyspace.Shards {
 			isRdOnlyPresent = false
-			if err = cluster.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", keyspace.Name, shard.Name)); err != nil {
+			if err = cluster.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", keyspace.Name, shard.Name), 1); err != nil {
 				return err
 			}
-			if err = cluster.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", keyspace.Name, shard.Name)); err != nil {
+			if err = cluster.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", keyspace.Name, shard.Name), 1); err != nil {
 				return err
 			}
 			for _, tablet := range shard.Vttablets {
@@ -435,7 +435,7 @@ func (cluster *LocalProcessCluster) WaitForTabletsToHealthyInVtgate() (err error
 				}
 			}
 			if isRdOnlyPresent {
-				err = cluster.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspace.Name, shard.Name))
+				err = cluster.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspace.Name, shard.Name), 1)
 			}
 			if err != nil {
 				return err
diff --git a/go/test/endtoend/cluster/vtgate_process.go b/go/test/endtoend/cluster/vtgate_process.go
index a185fbb32b..e8b1615f67 100644
--- a/go/test/endtoend/cluster/vtgate_process.go
+++ b/go/test/endtoend/cluster/vtgate_process.go
@@ -25,6 +25,7 @@ import (
 	"os/exec"
 	"path"
 	"reflect"
+	"strconv"
 	"strings"
 	"syscall"
 	"time"
@@ -131,7 +132,8 @@ func (vtgate *VtgateProcess) WaitForStatus() bool {
 }
 
 // GetStatusForTabletOfShard function gets status for a specific tablet of a shard in keyspace
-func (vtgate *VtgateProcess) GetStatusForTabletOfShard(name string) bool {
+// endPointsCount : number of endpoints
+func (vtgate *VtgateProcess) GetStatusForTabletOfShard(name string, endPointsCount int) bool {
 	resp, err := http.Get(vtgate.VerifyURL)
 	if err != nil {
 		return false
@@ -149,9 +151,9 @@ func (vtgate *VtgateProcess) GetStatusForTabletOfShard(name string) bool {
 			for _, key := range object.MapKeys() {
 				if key.String() == name {
 					value := fmt.Sprintf("%v", object.MapIndex(key))
-					return value == "1"
+					countStr := strconv.Itoa(endPointsCount)
+					return value == countStr
 				}
-
 			}
 		}
 		return masterConnectionExist
@@ -160,10 +162,11 @@ func (vtgate *VtgateProcess) GetStatusForTabletOfShard(name string) bool {
 }
 
 // WaitForStatusOfTabletInShard function waits till status of a tablet in shard is 1
-func (vtgate *VtgateProcess) WaitForStatusOfTabletInShard(name string) error {
+// endPointsCount: how many endpoints to wait for
+func (vtgate *VtgateProcess) WaitForStatusOfTabletInShard(name string, endPointsCount int) error {
 	timeout := time.Now().Add(10 * time.Second)
 	for time.Now().Before(timeout) {
-		if vtgate.GetStatusForTabletOfShard(name) {
+		if vtgate.GetStatusForTabletOfShard(name, endPointsCount) {
 			return nil
 		}
 		select {
@@ -226,3 +229,22 @@ func VtgateProcessInstance(port int, grpcPort int, mySQLServerPort int, cell str
 
 	return vtgate
 }
+
+// GetVars returns map of vars
+func (vtgate *VtgateProcess) GetVars() (map[string]interface{}, error) {
+	resultMap := make(map[string]interface{})
+	resp, err := http.Get(vtgate.VerifyURL)
+	if err != nil {
+		return nil, fmt.Errorf("error getting response from %s", vtgate.VerifyURL)
+	}
+	if resp.StatusCode == 200 {
+		respByte, _ := ioutil.ReadAll(resp.Body)
+		err := json.Unmarshal(respByte, &resultMap)
+		if err != nil {
+			return nil, fmt.Errorf("not able to parse response body")
+		}
+		return resultMap, nil
+	} else {
+		return nil, fmt.Errorf("unsuccessful response")
+	}
+}
diff --git a/go/test/endtoend/mysqlctl/mysqlctl_test.go b/go/test/endtoend/mysqlctl/mysqlctl_test.go
index 269e9535ee..b5f70954eb 100644
--- a/go/test/endtoend/mysqlctl/mysqlctl_test.go
+++ b/go/test/endtoend/mysqlctl/mysqlctl_test.go
@@ -118,6 +118,7 @@ func initCluster(shardNames []string, totalTabletsRequired int) {
 				clusterInstance.VtTabletExtraArgs,
 				clusterInstance.EnableSemiSync)
 			tablet.Alias = tablet.VttabletProcess.TabletPath
+
 			shard.Vttablets = append(shard.Vttablets, tablet)
 		}
 		for _, proc := range mysqlCtlProcessList {
diff --git a/go/test/endtoend/sharded/sharded_keyspace_test.go b/go/test/endtoend/sharded/sharded_keyspace_test.go
index d72ffd16a7..85b122330a 100644
--- a/go/test/endtoend/sharded/sharded_keyspace_test.go
+++ b/go/test/endtoend/sharded/sharded_keyspace_test.go
@@ -233,6 +233,7 @@ func initCluster(shardNames []string, totalTabletsRequired int) {
 				clusterInstance.VtTabletExtraArgs,
 				clusterInstance.EnableSemiSync)
 			tablet.Alias = tablet.VttabletProcess.TabletPath
+
 			shard.Vttablets = append(shard.Vttablets, tablet)
 		}
 		for _, proc := range mysqlCtlProcessList {
diff --git a/go/test/endtoend/sharding/base_sharding.go b/go/test/endtoend/sharding/base_sharding.go
index 583095f3d2..f7c8b4f280 100644
--- a/go/test/endtoend/sharding/base_sharding.go
+++ b/go/test/endtoend/sharding/base_sharding.go
@@ -239,18 +239,23 @@ func checkStreamHealthEqualsBinlogPlayerVars(t *testing.T, vttablet cluster.Vtta
 }
 
 // CheckBinlogServerVars checks the binlog server variables are correctly exported.
-func CheckBinlogServerVars(t *testing.T, vttablet cluster.Vttablet, minStatement int, minTxn int) {
+func CheckBinlogServerVars(t *testing.T, vttablet cluster.Vttablet, minStatement int, minTxn int, isVerticalSplit bool) {
 	resultMap := vttablet.VttabletProcess.GetVars()
-	assert.Contains(t, resultMap, "UpdateStreamKeyRangeStatements")
-	assert.Contains(t, resultMap, "UpdateStreamKeyRangeTransactions")
+	skey := "UpdateStreamKeyRangeStatements"
+	tkey := "UpdateStreamKeyRangeTransactions"
+	if isVerticalSplit {
+		skey = "UpdateStreamTablesStatements"
+		tkey = "UpdateStreamTablesTransactions"
+	}
+	assert.Contains(t, resultMap, skey)
+	assert.Contains(t, resultMap, tkey)
 	if minStatement > 0 {
-		value := fmt.Sprintf("%v", reflect.ValueOf(resultMap["UpdateStreamKeyRangeStatements"]))
+		value := fmt.Sprintf("%v", reflect.ValueOf(resultMap[skey]))
 		iValue, _ := strconv.Atoi(value)
 		assert.True(t, iValue >= minStatement, fmt.Sprintf("only got %d < %d statements", iValue, minStatement))
 	}
-
 	if minTxn > 0 {
-		value := fmt.Sprintf("%v", reflect.ValueOf(resultMap["UpdateStreamKeyRangeStatements"]))
+		value := fmt.Sprintf("%v", reflect.ValueOf(resultMap[tkey]))
 		iValue, _ := strconv.Atoi(value)
 		assert.True(t, iValue >= minTxn, fmt.Sprintf("only got %d < %d transactions", iValue, minTxn))
 	}
diff --git a/go/test/endtoend/sharding/initialsharding/sharding_util.go b/go/test/endtoend/sharding/initialsharding/sharding_util.go
index a2f2c36647..6e0cc1f514 100644
--- a/go/test/endtoend/sharding/initialsharding/sharding_util.go
+++ b/go/test/endtoend/sharding/initialsharding/sharding_util.go
@@ -341,7 +341,7 @@ func TestInitialSharding(t *testing.T, keyspace *cluster.Keyspace, keyType query
 	assert.Nil(t, err)
 
 	for _, tabletType := range []string{"master", "replica", "rdonly"} {
-		if err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.%s", keyspaceName, shard1.Name, tabletType)); err != nil {
+		if err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.%s", keyspaceName, shard1.Name, tabletType), 1); err != nil {
 			assert.Fail(t, err.Error())
 		}
 	}
@@ -400,12 +400,11 @@ func TestInitialSharding(t *testing.T, keyspace *cluster.Keyspace, keyType query
 
 	// Wait for the endpoints, either local or remote.
 	for _, shard := range []cluster.Shard{shard1, shard21, shard22} {
-
-		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", keyspaceName, shard.Name))
+		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", keyspaceName, shard.Name), 1)
 		assert.Nil(t, err)
-		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", keyspaceName, shard.Name))
+		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", keyspaceName, shard.Name), 1)
 		assert.Nil(t, err)
-		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard.Name))
+		err = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard.Name), 1)
 		assert.Nil(t, err)
 	}
 
@@ -493,7 +492,7 @@ func TestInitialSharding(t *testing.T, keyspace *cluster.Keyspace, keyType query
 	sharding.CheckDestinationMaster(t, *shard22.MasterTablet(), []string{shard1Ks}, *ClusterInstance)
 
 	//  check that binlog server exported the stats vars
-	sharding.CheckBinlogServerVars(t, *shard1.Replica(), 0, 0)
+	sharding.CheckBinlogServerVars(t, *shard1.Replica(), 0, 0, false)
 
 	for _, tablet := range []cluster.Vttablet{*shard21.Rdonly(), *shard22.Rdonly()} {
 		err = ClusterInstance.VtctlclientProcess.ExecuteCommand("RunHealthCheck", tablet.Alias)
@@ -510,7 +509,7 @@ func TestInitialSharding(t *testing.T, keyspace *cluster.Keyspace, keyType query
 
 	sharding.CheckDestinationMaster(t, *shard21.MasterTablet(), []string{shard1Ks}, *ClusterInstance)
 	sharding.CheckDestinationMaster(t, *shard22.MasterTablet(), []string{shard1Ks}, *ClusterInstance)
-	sharding.CheckBinlogServerVars(t, *shard1.Replica(), 1000, 1000)
+	sharding.CheckBinlogServerVars(t, *shard1.Replica(), 1000, 1000, false)
 
 	err = ClusterInstance.VtctlclientProcess.ExecuteCommand("RunHealthCheck", shard21.Rdonly().Alias)
 	assert.Nil(t, err)
@@ -558,8 +557,8 @@ func TestInitialSharding(t *testing.T, keyspace *cluster.Keyspace, keyType query
 	_ = shard21.Rdonly().VttabletProcess.WaitForTabletType("SERVING")
 	_ = shard22.Rdonly().VttabletProcess.WaitForTabletType("SERVING")
 
-	_ = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard21.Name))
-	_ = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard22.Name))
+	_ = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard21.Name), 1)
+	_ = vtgateInstance.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", keyspaceName, shard22.Name), 1)
 
 	//then serve replica from the split shards
 
diff --git a/go/test/endtoend/sharding/resharding/resharding_base.go b/go/test/endtoend/sharding/resharding/resharding_base.go
index 4c2e9e0c14..5064f67e2b 100644
--- a/go/test/endtoend/sharding/resharding/resharding_base.go
+++ b/go/test/endtoend/sharding/resharding/resharding_base.go
@@ -529,7 +529,7 @@ func TestResharding(t *testing.T, useVarbinaryShardingKeyType bool) {
 	assert.Nil(t, err)
 
 	// check that binlog server exported the stats vars
-	sharding.CheckBinlogServerVars(t, *shard1Replica1, 0, 0)
+	sharding.CheckBinlogServerVars(t, *shard1Replica1, 0, 0, false)
 
 	// Check that the throttler was enabled.
 	// The stream id is hard-coded as 1, which is the first id generated through auto-inc.
@@ -554,7 +554,8 @@ func TestResharding(t *testing.T, useVarbinaryShardingKeyType bool) {
 	checkMultiShardValues(t, keyspaceName, shardingKeyType)
 	sharding.CheckBinlogPlayerVars(t, *shard2Master, []string{shard1Ks}, 30)
 	sharding.CheckBinlogPlayerVars(t, *shard3Master, []string{shard1Ks}, 30)
-	sharding.CheckBinlogServerVars(t, *shard1Replica1, 100, 100)
+
+	sharding.CheckBinlogServerVars(t, *shard1Replica1, 100, 100, false)
 
 	// use vtworker to compare the data (after health-checking the destination
 	// rdonly tablets so discovery works)
@@ -613,7 +614,8 @@ func TestResharding(t *testing.T, useVarbinaryShardingKeyType bool) {
 	insertLots(100, 100, *shard1Master, tableName, fixedParentID, keyspaceName)
 	log.Debug("Checking 100 percent of data was sent quickly")
 	assert.True(t, checkLotsTimeout(t, 100, 100, tableName, keyspaceName, shardingKeyType))
-	sharding.CheckBinlogServerVars(t, *shard1Replica2, 80, 80)
+
+	sharding.CheckBinlogServerVars(t, *shard1Replica2, 80, 80, false)
 
 	// check we can't migrate the master just yet
 	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedTypes", shard1Ks, "master")
diff --git a/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go b/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go
new file mode 100644
index 0000000000..731c9a44ee
--- /dev/null
+++ b/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go
@@ -0,0 +1,736 @@
+/*
+Copyright 2019 The Vitess Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package verticalsplit
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"os/exec"
+	"path"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+
+	"vitess.io/vitess/go/json2"
+	"vitess.io/vitess/go/vt/vtgate/vtgateconn"
+
+	"github.com/stretchr/testify/assert"
+	"vitess.io/vitess/go/mysql"
+	"vitess.io/vitess/go/sqltypes"
+	"vitess.io/vitess/go/test/endtoend/cluster"
+	"vitess.io/vitess/go/test/endtoend/sharding"
+	"vitess.io/vitess/go/vt/proto/topodata"
+	_ "vitess.io/vitess/go/vt/vtgate/grpcvtgateconn"
+)
+
+var (
+	clusterInstance      *cluster.LocalProcessCluster
+	sourceKeyspace       = "source_keyspace"
+	destinationKeyspace  = "destination_keyspace"
+	hostname             = "localhost"
+	cellj                = "test_nj"
+	shardName            = "0"
+	createTabletTemplate = `
+		create table %s(
+			id bigint not null,
+			msg varchar(64),
+			primary key (id),
+			index by_msg (msg)
+		) Engine=InnoDB;`
+	createViewTemplate     = "create view %s(id, msg) as select id, msg from %s;"
+	createMoving3NoPkTable = `
+		create table moving3_no_pk (
+			id bigint not null,
+			msg varchar(64)
+		) Engine=InnoDB;`
+	tableArr         = []string{"moving1", "moving2", "staying1", "staying2"}
+	insertIndex      = 0
+	moving1First     int
+	moving2First     int
+	staying1First    int
+	staying2First    int
+	moving3NoPkFirst int
+)
+
+func TestVerticalSplit(t *testing.T) {
+	flag.Parse()
+	code, err := initializeCluster()
+	if err != nil {
+		t.Errorf("setup failed with status code %d", code)
+	}
+	defer teardownCluster()
+
+	// Adding another cell in the same cluster
+	err = clusterInstance.TopoProcess.ManageTopoDir("mkdir", "/vitess/"+"test_ca")
+	assert.Nil(t, err)
+	err = clusterInstance.VtctlProcess.AddCellInfo("test_ca")
+	assert.Nil(t, err)
+	err = clusterInstance.TopoProcess.ManageTopoDir("mkdir", "/vitess/"+"test_ny")
+	assert.Nil(t, err)
+	err = clusterInstance.VtctlProcess.AddCellInfo("test_ny")
+	assert.Nil(t, err)
+
+	assert.Nil(t, err, "error should be Nil")
+
+	// source keyspace, with 4 tables
+	sourceShard := clusterInstance.Keyspaces[0].Shards[0]
+	sourceMasterTablet := *sourceShard.Vttablets[0]
+	sourceReplicaTablet := *sourceShard.Vttablets[1]
+	sourceRdOnlyTablet1 := *sourceShard.Vttablets[2]
+	sourceRdOnlyTablet2 := *sourceShard.Vttablets[3]
+	sourceKs := fmt.Sprintf("%s/%s", sourceKeyspace, shardName)
+
+	// source tablets init
+	for _, tablet := range []cluster.Vttablet{sourceMasterTablet, sourceReplicaTablet, sourceRdOnlyTablet1, sourceRdOnlyTablet2} {
+		err = clusterInstance.VtctlclientProcess.InitTablet(&tablet, cellj, sourceKeyspace, hostname, sourceShard.Name)
+		assert.Nil(t, err)
+		err = tablet.VttabletProcess.CreateDB(sourceKeyspace)
+		assert.Nil(t, err)
+	}
+
+	// destination keyspace, with just two tables
+	destinationShard := clusterInstance.Keyspaces[1].Shards[0]
+	destinationMasterTablet := *destinationShard.Vttablets[0]
+	destinationReplicaTablet := *destinationShard.Vttablets[1]
+	destinationRdOnlyTablet1 := *destinationShard.Vttablets[2]
+	destinationRdOnlyTablet2 := *destinationShard.Vttablets[3]
+
+	// destination tablets init
+	for _, tablet := range []cluster.Vttablet{destinationMasterTablet, destinationReplicaTablet, destinationRdOnlyTablet1, destinationRdOnlyTablet2} {
+		err = clusterInstance.VtctlclientProcess.InitTablet(&tablet, cellj, destinationKeyspace, hostname, destinationShard.Name)
+		assert.Nil(t, err)
+		err = tablet.VttabletProcess.CreateDB(destinationKeyspace)
+		assert.Nil(t, err)
+	}
+
+	// RebuildKeyspaceGraph source keyspace
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", sourceKeyspace)
+	assert.Nil(t, err)
+
+	// RebuildKeyspaceGraph destination keyspace
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", destinationKeyspace)
+	assert.Nil(t, err)
+
+	// source schema
+	for _, tablet := range []cluster.Vttablet{sourceMasterTablet, sourceReplicaTablet, sourceRdOnlyTablet1, sourceRdOnlyTablet2} {
+		for _, tableName := range tableArr {
+			_, err := tablet.VttabletProcess.QueryTablet(fmt.Sprintf(createTabletTemplate, tableName), sourceKeyspace, true)
+			assert.Nil(t, err)
+		}
+		_, err := tablet.VttabletProcess.QueryTablet(fmt.Sprintf(createViewTemplate, "view1", "moving1"), sourceKeyspace, true)
+		assert.Nil(t, err)
+
+		// RBR (default behaviour) only because Vitess requires the primary key for query rewrites if
+		// it is running with statement based replication.
+		_, err = tablet.VttabletProcess.QueryTablet(createMoving3NoPkTable, sourceKeyspace, true)
+		assert.Nil(t, err)
+	}
+
+	// destination schema
+	// Insert data directly because vtgate would redirect us.
+	for _, tablet := range []cluster.Vttablet{destinationMasterTablet, destinationReplicaTablet, destinationRdOnlyTablet1, destinationRdOnlyTablet2} {
+		_, err = tablet.VttabletProcess.QueryTablet(fmt.Sprintf(createTabletTemplate, "extra1"), destinationKeyspace, true)
+		assert.Nil(t, err)
+	}
+
+	// source and destination master and replica tablets will be started
+	for _, tablet := range []cluster.Vttablet{sourceMasterTablet, sourceReplicaTablet, destinationMasterTablet, destinationReplicaTablet} {
+		_ = tablet.VttabletProcess.Setup()
+	}
+
+	// rdonly tablets will be started
+	for _, tablet := range []cluster.Vttablet{sourceRdOnlyTablet1, sourceRdOnlyTablet2, destinationRdOnlyTablet1, destinationRdOnlyTablet2} {
+		_ = tablet.VttabletProcess.Setup()
+	}
+
+	// check SrvKeyspace
+	ksServedFrom := "ServedFrom(master): source_keyspace\nServedFrom(rdonly): source_keyspace\nServedFrom(replica): source_keyspace\n"
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, ksServedFrom, *clusterInstance)
+
+	// reparent to make the tablets work (we use health check, fix their types)
+	err = clusterInstance.VtctlclientProcess.InitShardMaster(sourceKeyspace, shardName, cellj, sourceMasterTablet.TabletUID)
+	assert.Nil(t, err)
+	err = clusterInstance.VtctlclientProcess.InitShardMaster(destinationKeyspace, shardName, cellj, destinationMasterTablet.TabletUID)
+	assert.Nil(t, err)
+
+	sourceMasterTablet.Type = "master"
+	destinationMasterTablet.Type = "master"
+
+	for _, tablet := range []cluster.Vttablet{sourceReplicaTablet, destinationReplicaTablet} {
+		_ = tablet.VttabletProcess.WaitForTabletType("SERVING")
+		assert.Nil(t, err)
+	}
+	for _, tablet := range []cluster.Vttablet{sourceRdOnlyTablet1, sourceRdOnlyTablet2, destinationRdOnlyTablet1, destinationRdOnlyTablet2} {
+		_ = tablet.VttabletProcess.WaitForTabletType("SERVING")
+		assert.Nil(t, err)
+	}
+
+	for _, tablet := range []cluster.Vttablet{sourceMasterTablet, destinationMasterTablet, sourceReplicaTablet, destinationReplicaTablet, sourceRdOnlyTablet1, sourceRdOnlyTablet2, destinationRdOnlyTablet1, destinationRdOnlyTablet2} {
+		assert.Equal(t, tablet.VttabletProcess.GetTabletStatus(), "SERVING")
+	}
+
+	err = clusterInstance.StartVtgate()
+	assert.Nil(t, err)
+
+	vtParams := mysql.ConnParams{
+		Host: clusterInstance.Hostname,
+		Port: clusterInstance.VtgateMySQLPort,
+	}
+
+	ctx := context.Background()
+	conn, err := mysql.Connect(ctx, &vtParams)
+	assert.Nil(t, err)
+	defer conn.Close()
+
+	err = clusterInstance.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", sourceKeyspace, shardName), 1)
+	assert.Nil(t, err)
+	err = clusterInstance.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", sourceKeyspace, shardName), 1)
+	assert.Nil(t, err)
+	err = clusterInstance.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", sourceKeyspace, shardName), 2)
+	assert.Nil(t, err)
+	err = clusterInstance.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", destinationKeyspace, shardName), 1)
+	assert.Nil(t, err)
+	err = clusterInstance.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", destinationKeyspace, shardName), 1)
+	assert.Nil(t, err)
+	err = clusterInstance.VtgateProcess.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.rdonly", destinationKeyspace, shardName), 2)
+	assert.Nil(t, err)
+
+	// create the schema on the source keyspace, add some values
+	insertInitialValues(t, conn, sourceMasterTablet, destinationMasterTablet)
+
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("CopySchemaShard", "--tables", "/moving/,view1", sourceRdOnlyTablet1.Alias, "destination_keyspace/0")
+	assert.Nil(t, err, "CopySchemaShard failed")
+
+	// starting vtworker
+	httpPort := clusterInstance.GetAndReservePort()
+	grpcPort := clusterInstance.GetAndReservePort()
+	clusterInstance.VtworkerProcess = *cluster.VtworkerProcessInstance(
+		httpPort,
+		grpcPort,
+		clusterInstance.TopoPort,
+		clusterInstance.Hostname,
+		clusterInstance.TmpDirectory)
+
+	err = clusterInstance.VtworkerProcess.ExecuteVtworkerCommand(httpPort, grpcPort,
+		"--cell", cellj,
+		"--command_display_interval", "10ms",
+		"--use_v3_resharding_mode=true",
+		"VerticalSplitClone",
+		"--tables", "/moving/,view1",
+		"--chunk_count", "10",
+		"--min_rows_per_chunk", "1",
+		"--min_healthy_tablets", "1", "destination_keyspace/0")
+	assert.Nil(t, err)
+
+	// test Cancel first
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("CancelResharding", "destination_keyspace/0")
+	assert.Nil(t, err)
+	err = destinationMasterTablet.VttabletProcess.WaitForBinLogPlayerCount(0)
+	assert.Nil(t, err)
+	// master should be in serving state after cancel
+	sharding.CheckTabletQueryServices(t, []cluster.Vttablet{destinationMasterTablet}, "SERVING", false, *clusterInstance)
+
+	// redo VerticalSplitClone
+	err = clusterInstance.VtworkerProcess.ExecuteVtworkerCommand(clusterInstance.GetAndReservePort(), clusterInstance.GetAndReservePort(),
+		"--cell", cellj,
+		"--command_display_interval", "10ms",
+		"--use_v3_resharding_mode=true",
+		"VerticalSplitClone",
+		"--tables", "/moving/,view1",
+		"--chunk_count", "10",
+		"--min_rows_per_chunk", "1",
+		"--min_healthy_tablets", "1", "destination_keyspace/0")
+	assert.Nil(t, err)
+
+	// check values are present
+	checkValues(t, &destinationMasterTablet, destinationKeyspace, "vt_destination_keyspace", "moving1", moving1First, 100)
+	checkValues(t, &destinationMasterTablet, destinationKeyspace, "vt_destination_keyspace", "moving2", moving2First, 100)
+	checkValues(t, &destinationMasterTablet, destinationKeyspace, "vt_destination_keyspace", "view1", moving1First, 100)
+	checkValues(t, &destinationMasterTablet, destinationKeyspace, "vt_destination_keyspace", "moving3_no_pk", moving3NoPkFirst, 100)
+
+	// Verify vreplication table entries
+	dbParams := mysql.ConnParams{
+		Uname:      "vt_dba",
+		UnixSocket: path.Join(destinationMasterTablet.VttabletProcess.Directory, "mysql.sock"),
+	}
+	dbParams.DbName = "_vt"
+	dbConn, err := mysql.Connect(ctx, &dbParams)
+	assert.Nil(t, err)
+	qr, err := dbConn.ExecuteFetch("select * from vreplication", 1000, true)
+	assert.Nil(t, err, "error should be Nil")
+	assert.Equal(t, 1, len(qr.Rows))
+	assert.Contains(t, fmt.Sprintf("%v", qr.Rows), "SplitClone")
+	assert.Contains(t, fmt.Sprintf("%v", qr.Rows), `keyspace:\"source_keyspace\" shard:\"0\" tables:\"/moving/\" tables:\"view1\`)
+	dbConn.Close()
+
+	// check the binlog player is running and exporting vars
+	sharding.CheckDestinationMaster(t, destinationMasterTablet, []string{sourceKs}, *clusterInstance)
+
+	// check that binlog server exported the stats vars
+	sharding.CheckBinlogServerVars(t, sourceReplicaTablet, 0, 0, true)
+
+	// add values to source, make sure they're replicated
+	moving1FirstAdd1 := insertValues(t, conn, sourceKeyspace, "moving1", 100)
+	_ = insertValues(t, conn, sourceKeyspace, "staying1", 100)
+	moving2FirstAdd1 := insertValues(t, conn, sourceKeyspace, "moving2", 100)
+	checkValuesTimeout(t, destinationMasterTablet, "moving1", moving1FirstAdd1, 100, 30)
+	checkValuesTimeout(t, destinationMasterTablet, "moving2", moving2FirstAdd1, 100, 30)
+	sharding.CheckBinlogPlayerVars(t, destinationMasterTablet, []string{sourceKs}, 30)
+	sharding.CheckBinlogServerVars(t, sourceReplicaTablet, 100, 100, true)
+
+	// use vtworker to compare the data
+	t.Log("Running vtworker VerticalSplitDiff")
+	err = clusterInstance.VtworkerProcess.ExecuteVtworkerCommand(clusterInstance.GetAndReservePort(),
+		clusterInstance.GetAndReservePort(),
+		"--use_v3_resharding_mode=true",
+		"--cell", "test_nj",
+		"VerticalSplitDiff",
+		"--min_healthy_rdonly_tablets", "1",
+		"destination_keyspace/0")
+	assert.Nil(t, err)
+
+	// get status for destination master tablet, make sure we have it all
+	sharding.CheckRunningBinlogPlayer(t, destinationMasterTablet, 700, 300)
+
+	// check query service is off on destination master, as filtered
+	// replication is enabled. Even health check should not interfere.
+	destinationMasterTabletVars := destinationMasterTablet.VttabletProcess.GetVars()
+	assert.NotNil(t, destinationMasterTabletVars)
+	assert.Contains(t, reflect.ValueOf(destinationMasterTabletVars["TabletStateName"]).String(), "NOT_SERVING")
+
+	// check we can't migrate the master just yet
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "destination_keyspace/0", "master")
+	assert.NotNil(t, err)
+
+	// migrate rdonly only in test_ny cell, make sure nothing is migrated
+	// in test_nj
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "--cells=test_ny", "destination_keyspace/0", "rdonly")
+	assert.Nil(t, err)
+
+	// check SrvKeyspace
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, ksServedFrom, *clusterInstance)
+	checkBlacklistedTables(t, sourceMasterTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceReplicaTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceRdOnlyTablet1, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceRdOnlyTablet2, sourceKeyspace, nil)
+
+	// migrate test_nj only, using command line manual fix command,
+	// and restore it back.
+	keyspaceJSON, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("GetKeyspace", "destination_keyspace")
+	assert.Nil(t, err)
+
+	validateKeyspaceJSON(t, keyspaceJSON, []string{"test_ca", "test_nj"})
+
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetKeyspaceServedFrom", "-source=source_keyspace", "-remove", "-cells=test_nj,test_ca", "destination_keyspace", "rdonly")
+	assert.Nil(t, err)
+
+	// again validating keyspaceJSON
+	keyspaceJSON, err = clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("GetKeyspace", "destination_keyspace")
+	assert.Nil(t, err)
+
+	validateKeyspaceJSON(t, keyspaceJSON, nil)
+
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetKeyspaceServedFrom", "-source=source_keyspace", "destination_keyspace", "rdonly")
+	assert.Nil(t, err)
+
+	keyspaceJSON, err = clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("GetKeyspace", "destination_keyspace")
+	assert.Nil(t, err)
+
+	validateKeyspaceJSON(t, keyspaceJSON, []string{})
+
+	// now serve rdonly from the destination shards
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "destination_keyspace/0", "rdonly")
+	assert.Nil(t, err)
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, "ServedFrom(master): source_keyspace\nServedFrom(replica): source_keyspace\n", *clusterInstance)
+	checkBlacklistedTables(t, sourceMasterTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceReplicaTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceRdOnlyTablet1, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet2, sourceKeyspace, []string{"/moving/", "view1"})
+
+	grpcAddress := fmt.Sprintf("%s:%d", "localhost", clusterInstance.VtgateProcess.GrpcPort)
+	gconn, err := vtgateconn.Dial(ctx, grpcAddress)
+	assert.Nil(t, err)
+	defer gconn.Close()
+
+	checkClientConnRedirectionExecuteKeyrange(ctx, t, gconn, destinationKeyspace, []topodata.TabletType{topodata.TabletType_MASTER, topodata.TabletType_REPLICA}, []string{"moving1", "moving2"})
+
+	// then serve replica from the destination shards
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "destination_keyspace/0", "replica")
+	assert.Nil(t, err)
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, "ServedFrom(master): source_keyspace\n", *clusterInstance)
+	checkBlacklistedTables(t, sourceMasterTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceReplicaTablet, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet1, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet2, sourceKeyspace, []string{"/moving/", "view1"})
+	checkClientConnRedirectionExecuteKeyrange(ctx, t, gconn, destinationKeyspace, []topodata.TabletType{topodata.TabletType_MASTER}, []string{"moving1", "moving2"})
+
+	// move replica back and forth
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "-reverse", "destination_keyspace/0", "replica")
+	assert.Nil(t, err)
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, "ServedFrom(master): source_keyspace\nServedFrom(replica): source_keyspace\n", *clusterInstance)
+	checkBlacklistedTables(t, sourceMasterTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceReplicaTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceRdOnlyTablet1, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet2, sourceKeyspace, []string{"/moving/", "view1"})
+
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "destination_keyspace/0", "replica")
+	assert.Nil(t, err)
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, "ServedFrom(master): source_keyspace\n", *clusterInstance)
+	checkBlacklistedTables(t, sourceMasterTablet, sourceKeyspace, nil)
+	checkBlacklistedTables(t, sourceReplicaTablet, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet1, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet2, sourceKeyspace, []string{"/moving/", "view1"})
+	checkClientConnRedirectionExecuteKeyrange(ctx, t, gconn, destinationKeyspace, []topodata.TabletType{topodata.TabletType_MASTER}, []string{"moving1", "moving2"})
+
+	// Cancel should fail now
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("CancelResharding", "destination_keyspace/0")
+	assert.NotNil(t, err)
+
+	// then serve master from the destination shards
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("MigrateServedFrom", "destination_keyspace/0", "master")
+	checkSrvKeyspaceServedFrom(t, cellj, destinationKeyspace, "", *clusterInstance)
+	checkBlacklistedTables(t, sourceMasterTablet, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceReplicaTablet, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet1, sourceKeyspace, []string{"/moving/", "view1"})
+	checkBlacklistedTables(t, sourceRdOnlyTablet2, sourceKeyspace, []string{"/moving/", "view1"})
+
+	// check the binlog player is gone now
+	_ = destinationMasterTablet.VttabletProcess.WaitForBinLogPlayerCount(0)
+
+	// check the stats are correct
+	checkStats(t)
+
+	// now remove the tables on the source shard. The blacklisted tables
+	// in the source shard won't match any table, make sure that works.
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("ApplySchema", "-sql=drop view view1", "source_keyspace")
+	assert.Nil(t, err)
+
+	for _, table := range []string{"moving1", "moving2"} {
+		err = clusterInstance.VtctlclientProcess.ExecuteCommand("ApplySchema", "--sql=drop table "+table, "source_keyspace")
+		assert.Nil(t, err)
+	}
+	for _, tablet := range []cluster.Vttablet{sourceMasterTablet, sourceReplicaTablet, sourceRdOnlyTablet1, sourceRdOnlyTablet2} {
+		err = clusterInstance.VtctlclientProcess.ExecuteCommand("ReloadSchema", tablet.Alias)
+		assert.Nil(t, err)
+	}
+	qr, _ = sourceMasterTablet.VttabletProcess.QueryTablet("select count(1) from staying1", sourceKeyspace, true)
+	assert.Equal(t, 1, len(qr.Rows), fmt.Sprintf("cannot read staying1: got %d", len(qr.Rows)))
+
+	// test SetShardTabletControl
+	verifyVtctlSetShardTabletControl(t)
+
+}
+
+func verifyVtctlSetShardTabletControl(t *testing.T) {
+	// clear the rdonly entry:
+	err := clusterInstance.VtctlclientProcess.ExecuteCommand("SetShardTabletControl", "--remove", "source_keyspace/0", "rdonly")
+	assert.Nil(t, err)
+	assertTabletControls(t, clusterInstance, []topodata.TabletType{topodata.TabletType_MASTER, topodata.TabletType_REPLICA})
+
+	// re-add rdonly:
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetShardTabletControl", "--blacklisted_tables=/moving/,view1", "source_keyspace/0", "rdonly")
+	assert.Nil(t, err)
+	assertTabletControls(t, clusterInstance, []topodata.TabletType{topodata.TabletType_MASTER, topodata.TabletType_REPLICA, topodata.TabletType_RDONLY})
+
+	//and then clear all entries:
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetShardTabletControl", "--remove", "source_keyspace/0", "rdonly")
+	assert.Nil(t, err)
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetShardTabletControl", "--remove", "source_keyspace/0", "replica")
+	assert.Nil(t, err)
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SetShardTabletControl", "--remove", "source_keyspace/0", "master")
+	assert.Nil(t, err)
+
+	shardJSON, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("GetShard", "source_keyspace/0")
+	var shardJSONData topodata.Shard
+	err = json2.Unmarshal([]byte(shardJSON), &shardJSONData)
+	assert.Empty(t, shardJSONData.TabletControls)
+
+}
+
+func assertTabletControls(t *testing.T, clusterInstance *cluster.LocalProcessCluster, aliases []topodata.TabletType) {
+	shardJSON, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("GetShard", "source_keyspace/0")
+	assert.Nil(t, err)
+	var shardJSONData topodata.Shard
+	err = json2.Unmarshal([]byte(shardJSON), &shardJSONData)
+	assert.Nil(t, err)
+	assert.Equal(t, len(shardJSONData.TabletControls), len(aliases))
+	for _, tc := range shardJSONData.TabletControls {
+		assert.Contains(t, aliases, tc.TabletType)
+		assert.Equal(t, []string{"/moving/", "view1"}, tc.BlacklistedTables)
+	}
+}
+
+func checkStats(t *testing.T) {
+
+	resultMap, err := clusterInstance.VtgateProcess.GetVars()
+	assert.Nil(t, err)
+	resultVtTabletCall := resultMap["VttabletCall"]
+	resultVtTabletCallMap := resultVtTabletCall.(map[string]interface{})
+	resultHistograms := resultVtTabletCallMap["Histograms"]
+	resultHistogramsMap := resultHistograms.(map[string]interface{})
+	resultTablet := resultHistogramsMap["Execute.source_keyspace.0.replica"]
+	resultTableMap := resultTablet.(map[string]interface{})
+	resultCountStr := fmt.Sprintf("%v", reflect.ValueOf(resultTableMap["Count"]))
+	assert.Equal(t, "2", resultCountStr, fmt.Sprintf("unexpected value for VttabletCall(Execute.source_keyspace.0.replica) inside %s", resultCountStr))
+
+	// Verify master reads done by self._check_client_conn_redirection().
+	resultVtgateAPI := resultMap["VtgateApi"]
+	resultVtgateAPIMap := resultVtgateAPI.(map[string]interface{})
+	resultAPIHistograms := resultVtgateAPIMap["Histograms"]
+	resultAPIHistogramsMap := resultAPIHistograms.(map[string]interface{})
+	resultTabletDestination := resultAPIHistogramsMap["ExecuteKeyRanges.destination_keyspace.master"]
+	resultTabletDestinationMap := resultTabletDestination.(map[string]interface{})
+	resultCountStrDestination := fmt.Sprintf("%v", reflect.ValueOf(resultTabletDestinationMap["Count"]))
+	assert.Equal(t, "6", resultCountStrDestination, fmt.Sprintf("unexpected value for VtgateApi(ExecuteKeyRanges.destination_keyspace.master) inside %s)", resultCountStrDestination))
+
+	assert.Empty(t, resultMap["VtgateApiErrorCounts"])
+
+}
+
+func insertInitialValues(t *testing.T, conn *mysql.Conn, sourceMasterTablet cluster.Vttablet, destinationMasterTablet cluster.Vttablet) {
+	moving1First = insertValues(t, conn, sourceKeyspace, "moving1", 100)
+	moving2First = insertValues(t, conn, sourceKeyspace, "moving2", 100)
+	staying1First = insertValues(t, conn, sourceKeyspace, "staying1", 100)
+	staying2First = insertValues(t, conn, sourceKeyspace, "staying2", 100)
+	checkValues(t, &sourceMasterTablet, sourceKeyspace, "vt_source_keyspace", "moving1", moving1First, 100)
+	checkValues(t, &sourceMasterTablet, sourceKeyspace, "vt_source_keyspace", "moving2", moving2First, 100)
+	checkValues(t, &sourceMasterTablet, sourceKeyspace, "vt_source_keyspace", "staying1", staying1First, 100)
+	checkValues(t, &sourceMasterTablet, sourceKeyspace, "vt_source_keyspace", "staying2", staying2First, 100)
+	checkValues(t, &sourceMasterTablet, sourceKeyspace, "vt_source_keyspace", "view1", moving1First, 100)
+
+	moving3NoPkFirst = insertValues(t, conn, sourceKeyspace, "moving3_no_pk", 100)
+	checkValues(t, &sourceMasterTablet, sourceKeyspace, "vt_source_keyspace", "moving3_no_pk", moving3NoPkFirst, 100)
+
+	// Insert data directly because vtgate would redirect us.
+	_, err := destinationMasterTablet.VttabletProcess.QueryTablet(fmt.Sprintf("insert into %s (id, msg) values(%d, 'value %d')", "extra1", 1, 1), destinationKeyspace, true)
+	assert.Nil(t, err)
+	checkValues(t, &destinationMasterTablet, destinationKeyspace, "vt_destination_keyspace", "extra1", 1, 1)
+}
+
+func checkClientConnRedirectionExecuteKeyrange(ctx context.Context, t *testing.T, conn *vtgateconn.VTGateConn, keyspace string, servedFromDbTypes []topodata.TabletType, movedTables []string) {
+	var testKeyRange = &topodata.KeyRange{
+		Start: []byte{},
+		End:   []byte{},
+	}
+	keyRanges := []*topodata.KeyRange{testKeyRange}
+	// check that the ServedFrom indirection worked correctly.
+	for _, tableType := range servedFromDbTypes {
+		for _, table := range movedTables {
+			_, err := conn.ExecuteKeyRanges(ctx, fmt.Sprintf("select * from %s", table), keyspace, keyRanges, nil, tableType, nil)
+			assert.Nil(t, err)
+		}
+	}
+}
+
+func checkValues(t *testing.T, tablet *cluster.Vttablet, keyspace string, dbname string, table string, first int, count int) {
+	t.Logf("Checking %d values from %s/%s starting at %d", count, dbname, table, first)
+	qr, _ := tablet.VttabletProcess.QueryTablet(fmt.Sprintf("select id, msg from %s where id>=%d order by id limit %d", table, first, count), keyspace, true)
+	assert.Equal(t, count, len(qr.Rows), fmt.Sprintf("got wrong number of rows: %d != %d", len(qr.Rows), count))
+	i := 0
+	for i < count {
+		result, _ := sqltypes.ToInt64(qr.Rows[i][0])
+		assert.Equal(t, int64(first+i), result, fmt.Sprintf("got wrong number of rows: %d != %d", len(qr.Rows), first+i))
+		assert.Contains(t, qr.Rows[i][1].String(), fmt.Sprintf("value %d", first+i), fmt.Sprintf("invalid msg[%d]: 'value %d' != '%s'", i, first+i, qr.Rows[i][1].String()))
+		i++
+	}
+}
+
+func checkValuesTimeout(t *testing.T, tablet cluster.Vttablet, table string, first int, count int, timeoutInSec int) bool {
+	for i := 0; i < timeoutInSec; i-- {
+		qr, err := tablet.VttabletProcess.QueryTablet(fmt.Sprintf("select id, msg from %s where id>=%d order by id limit %d", table, first, count), destinationKeyspace, true)
+		if err != nil {
+			assert.Nil(t, err, "select failed on master tablet")
+		}
+		if len(qr.Rows) == count {
+			return true
+		}
+		time.Sleep(1 * time.Second)
+	}
+	return true
+}
+
+func checkBlacklistedTables(t *testing.T, tablet cluster.Vttablet, keyspace string, expected []string) {
+	tabletStatus := tablet.VttabletProcess.GetStatus()
+	if expected != nil {
+		assert.Contains(t, tabletStatus, fmt.Sprintf("BlacklistedTables: %s", strings.Join(expected, " ")))
+	} else {
+		assert.NotContains(t, tabletStatus, "BlacklistedTables")
+	}
+
+	// check we can or cannot access the tables
+	for _, table := range []string{"moving1", "moving2"} {
+		if expected != nil && strings.Contains(strings.Join(expected, " "), "moving") {
+			// table is blacklisted, should get error
+			err := clusterInstance.VtctlclientProcess.ExecuteCommand("VtTabletExecute", "-json", tablet.Alias, fmt.Sprintf("select count(1) from %s", table))
+			assert.NotNil(t, err, "disallowed due to rule: enforce blacklisted tables")
+		} else {
+			// table is not blacklisted, should just work
+			_, err := tablet.VttabletProcess.QueryTablet(fmt.Sprintf("select count(1) from %s", table), keyspace, true)
+			assert.Nil(t, err)
+		}
+	}
+}
+
+func insertValues(t *testing.T, conn *mysql.Conn, keyspace string, table string, count int) int {
+	result := insertIndex
+	i := 0
+	for i < count {
+		execQuery(t, conn, "begin")
+		execQuery(t, conn, "use `"+keyspace+":0`")
+		execQuery(t, conn, fmt.Sprintf("insert into %s (id, msg) values(%d, 'value %d')", table, insertIndex, insertIndex))
+		execQuery(t, conn, "commit")
+		insertIndex++
+		i++
+	}
+	return result
+}
+
+func teardownCluster() {
+	clusterInstance.Teardown()
+}
+
+func execQuery(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
+	t.Helper()
+	qr, err := conn.ExecuteFetch(query, 1000, true)
+	assert.Nil(t, err)
+	return qr
+}
+
+// CheckSrvKeyspaceServedFrom verifies the servedFrom with expected
+func checkSrvKeyspaceServedFrom(t *testing.T, cell string, ksname string, expected string, ci cluster.LocalProcessCluster) {
+	srvKeyspace := sharding.GetSrvKeyspace(t, cell, ksname, ci)
+	tabletTypeKeyspaceMap := make(map[string]string)
+	result := ""
+	if srvKeyspace.GetServedFrom() != nil {
+		for _, servedFrom := range srvKeyspace.GetServedFrom() {
+			tabletTy := strings.ToLower(servedFrom.GetTabletType().String())
+			tabletTypeKeyspaceMap[tabletTy] = servedFrom.GetKeyspace()
+		}
+	}
+	if tabletTypeKeyspaceMap["master"] != "" {
+		result = result + fmt.Sprintf("ServedFrom(%s): %s\n", "master", tabletTypeKeyspaceMap["master"])
+	}
+	if tabletTypeKeyspaceMap["rdonly"] != "" {
+		result = result + fmt.Sprintf("ServedFrom(%s): %s\n", "rdonly", tabletTypeKeyspaceMap["rdonly"])
+	}
+	if tabletTypeKeyspaceMap["replica"] != "" {
+		result = result + fmt.Sprintf("ServedFrom(%s): %s\n", "replica", tabletTypeKeyspaceMap["replica"])
+	}
+	assert.Equal(t, expected, result, fmt.Sprintf("Mismatch in srv keyspace for cell %s keyspace %s, expected:\n %s\ngot:\n%s", cell, ksname, expected, result))
+	assert.Equal(t, "", srvKeyspace.GetShardingColumnName(), fmt.Sprintf("Got a sharding_column_name in SrvKeyspace: %s", srvKeyspace.GetShardingColumnName()))
+	assert.Equal(t, "UNSET", srvKeyspace.GetShardingColumnType().String(), fmt.Sprintf("Got a sharding_column_type in SrvKeyspace: %s", srvKeyspace.GetShardingColumnType().String()))
+}
+
+func initializeCluster() (int, error) {
+	var mysqlProcesses []*exec.Cmd
+	clusterInstance = &cluster.LocalProcessCluster{Cell: cellj, Hostname: hostname}
+
+	// Start topo server
+	if err := clusterInstance.StartTopo(); err != nil {
+		return 1, err
+	}
+
+	for _, keyspaceStr := range []string{sourceKeyspace, destinationKeyspace} {
+		KeyspacePtr := &cluster.Keyspace{Name: keyspaceStr}
+		keyspace := *KeyspacePtr
+		if keyspaceStr == sourceKeyspace {
+			if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspace.Name); err != nil {
+				return 1, err
+			}
+		} else {
+			if err := clusterInstance.VtctlclientProcess.ExecuteCommand("CreateKeyspace", "--served_from", "master:source_keyspace,replica:source_keyspace,rdonly:source_keyspace", "destination_keyspace"); err != nil {
+				return 1, err
+			}
+		}
+		shard := &cluster.Shard{
+			Name: shardName,
+		}
+		for i := 0; i < 4; i++ {
+			// instantiate vttablet object with reserved ports
+			tabletUID := clusterInstance.GetAndReserveTabletUID()
+			var tablet *cluster.Vttablet = nil
+			if i == 0 {
+				tablet = clusterInstance.GetVttabletInstance("replica", tabletUID, cellj)
+			} else if i == 1 {
+				tablet = clusterInstance.GetVttabletInstance("replica", tabletUID, cellj)
+			} else {
+				tablet = clusterInstance.GetVttabletInstance("rdonly", tabletUID, cellj)
+			}
+			// Start Mysqlctl process
+			tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory)
+			if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil {
+				return 1, err
+			} else {
+				mysqlProcesses = append(mysqlProcesses, proc)
+			}
+			// start vttablet process
+			tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort,
+				tablet.GrpcPort,
+				tablet.TabletUID,
+				clusterInstance.Cell,
+				shardName,
+				keyspace.Name,
+				clusterInstance.VtctldProcess.Port,
+				tablet.Type,
+				clusterInstance.TopoProcess.Port,
+				clusterInstance.Hostname,
+				clusterInstance.TmpDirectory,
+				clusterInstance.VtTabletExtraArgs,
+				clusterInstance.EnableSemiSync)
+			tablet.Alias = tablet.VttabletProcess.TabletPath
+
+			shard.Vttablets = append(shard.Vttablets, tablet)
+		}
+		keyspace.Shards = append(keyspace.Shards, *shard)
+		clusterInstance.Keyspaces = append(clusterInstance.Keyspaces, keyspace)
+	}
+	for _, proc := range mysqlProcesses {
+		err := proc.Wait()
+		if err != nil {
+			return 1, err
+		}
+	}
+	return 0, nil
+}
+
+func validateKeyspaceJSON(t *testing.T, keyspaceJSON string, cellsArr []string) {
+	var keyspace topodata.Keyspace
+	err := json2.Unmarshal([]byte(keyspaceJSON), &keyspace)
+	assert.Nil(t, err)
+	found := false
+	for _, servedFrom := range keyspace.GetServedFroms() {
+		if strings.ToLower(servedFrom.GetTabletType().String()) == "rdonly" {
+			found = true
+			if cellsArr != nil {
+				if len(cellsArr) > 0 {
+					for _, eachCell := range cellsArr {
+						assert.Contains(t, strings.Join(servedFrom.GetCells(), " "), eachCell)
+					}
+				} else {
+					assert.Equal(t, []string{}, servedFrom.GetCells())
+				}
+			}
+		}
+	}
+	if cellsArr != nil {
+		assert.Equal(t, true, found)
+	} else {
+		assert.Equal(t, false, found)
+	}
+}
diff --git a/go/test/endtoend/tabletmanager/tablet_health_test.go b/go/test/endtoend/tabletmanager/tablet_health_test.go
index 1c012e88d0..3c00956704 100644
--- a/go/test/endtoend/tabletmanager/tablet_health_test.go
+++ b/go/test/endtoend/tabletmanager/tablet_health_test.go
@@ -54,6 +54,7 @@ func TestTabletReshuffle(t *testing.T) {
 
 	//Create new tablet
 	rTablet := clusterInstance.GetVttabletInstance("replica", 0, "")
+
 	//Init Tablets
 	err = clusterInstance.VtctlclientProcess.InitTablet(rTablet, cell, keyspaceName, hostname, shardName)
 	require.NoError(t, err)
diff --git a/go/test/endtoend/vtgate/buffer/buffer_test.go b/go/test/endtoend/vtgate/buffer/buffer_test.go
index 02c8514f29..ff796dc7b9 100644
--- a/go/test/endtoend/vtgate/buffer/buffer_test.go
+++ b/go/test/endtoend/vtgate/buffer/buffer_test.go
@@ -356,6 +356,7 @@ func externalReparenting(ctx context.Context, t *testing.T, clusterInstance *clu
 
 	// Wait for replica to catch up to master.
 	waitForReplicationPos(ctx, t, master, replica, 60.0)
+
 	duration := time.Since(start)
 	minUnavailabilityInS := 1.0
 	if duration.Seconds() < minUnavailabilityInS {
@@ -372,7 +373,9 @@ func externalReparenting(ctx context.Context, t *testing.T, clusterInstance *clu
 	}
 
 	// Configure old master to replicate from new master.
+
 	_, gtID := cluster.GetMasterPosition(t, *newMaster, hostname)
+
 	// Use 'localhost' as hostname because Travis CI worker hostnames
 	// are too long for MySQL replication.
 	changeMasterCommands := fmt.Sprintf("RESET SLAVE;SET GLOBAL gtid_slave_pos = '%s';CHANGE MASTER TO MASTER_HOST='%s', MASTER_PORT=%d ,MASTER_USER='vt_repl', MASTER_USE_GTID = slave_pos;START SLAVE;", gtID, "localhost", newMaster.MySQLPort)
diff --git a/go/vt/vtgate/engine/vindex_func_test.go b/go/vt/vtgate/engine/vindex_func_test.go
index ff22fe4e60..338ca9f7dd 100644
--- a/go/vt/vtgate/engine/vindex_func_test.go
+++ b/go/vt/vtgate/engine/vindex_func_test.go
@@ -30,10 +30,9 @@ import (
 // uvindex is Unique.
 type uvindex struct{ matchid, matchkr bool }
 
-func (*uvindex) String() string     { return "uvindex" }
-func (*uvindex) Cost() int          { return 1 }
-func (*uvindex) IsUnique() bool     { return true }
-func (*uvindex) NeedsVCursor() bool { return false }
+func (*uvindex) String() string { return "uvindex" }
+func (*uvindex) Cost() int      { return 1 }
+func (*uvindex) IsUnique() bool { return true }
 func (*uvindex) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	panic("unimplemented")
 }
@@ -60,10 +59,9 @@ func (v *uvindex) Map(cursor vindexes.VCursor, ids []sqltypes.Value) ([]key.Dest
 // nvindex is NonUnique.
 type nvindex struct{ matchid, matchkr bool }
 
-func (*nvindex) String() string     { return "nvindex" }
-func (*nvindex) Cost() int          { return 1 }
-func (*nvindex) IsUnique() bool     { return false }
-func (*nvindex) NeedsVCursor() bool { return false }
+func (*nvindex) String() string { return "nvindex" }
+func (*nvindex) Cost() int      { return 1 }
+func (*nvindex) IsUnique() bool { return false }
 func (*nvindex) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	panic("unimplemented")
 }
diff --git a/go/vt/vtgate/executor_framework_test.go b/go/vt/vtgate/executor_framework_test.go
index 632de9c0bc..1478144e5b 100644
--- a/go/vt/vtgate/executor_framework_test.go
+++ b/go/vt/vtgate/executor_framework_test.go
@@ -282,10 +282,9 @@ func (dp DestinationAnyShardPickerFirstShard) PickShard(shardCount int) int {
 type keyRangeLookuper struct {
 }
 
-func (v *keyRangeLookuper) String() string   { return "keyrange_lookuper" }
-func (*keyRangeLookuper) Cost() int          { return 0 }
-func (*keyRangeLookuper) IsUnique() bool     { return false }
-func (*keyRangeLookuper) NeedsVCursor() bool { return false }
+func (v *keyRangeLookuper) String() string { return "keyrange_lookuper" }
+func (*keyRangeLookuper) Cost() int        { return 0 }
+func (*keyRangeLookuper) IsUnique() bool   { return false }
 func (*keyRangeLookuper) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	return []bool{}, nil
 }
@@ -307,10 +306,9 @@ func newKeyRangeLookuper(name string, params map[string]string) (vindexes.Vindex
 type keyRangeLookuperUnique struct {
 }
 
-func (v *keyRangeLookuperUnique) String() string   { return "keyrange_lookuper" }
-func (*keyRangeLookuperUnique) Cost() int          { return 0 }
-func (*keyRangeLookuperUnique) IsUnique() bool     { return true }
-func (*keyRangeLookuperUnique) NeedsVCursor() bool { return false }
+func (v *keyRangeLookuperUnique) String() string { return "keyrange_lookuper" }
+func (*keyRangeLookuperUnique) Cost() int        { return 0 }
+func (*keyRangeLookuperUnique) IsUnique() bool   { return true }
 func (*keyRangeLookuperUnique) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	return []bool{}, nil
 }
diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go
index 885499d87a..9e0e72ed30 100644
--- a/go/vt/vtgate/planbuilder/plan_test.go
+++ b/go/vt/vtgate/planbuilder/plan_test.go
@@ -39,10 +39,9 @@ import (
 // hashIndex is a functional, unique Vindex.
 type hashIndex struct{ name string }
 
-func (v *hashIndex) String() string   { return v.name }
-func (*hashIndex) Cost() int          { return 1 }
-func (*hashIndex) IsUnique() bool     { return true }
-func (*hashIndex) NeedsVCursor() bool { return false }
+func (v *hashIndex) String() string { return v.name }
+func (*hashIndex) Cost() int        { return 1 }
+func (*hashIndex) IsUnique() bool   { return true }
 func (*hashIndex) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	return []bool{}, nil
 }
@@ -57,10 +56,9 @@ func newHashIndex(name string, _ map[string]string) (vindexes.Vindex, error) {
 // lookupIndex is a unique Vindex, and satisfies Lookup.
 type lookupIndex struct{ name string }
 
-func (v *lookupIndex) String() string   { return v.name }
-func (*lookupIndex) Cost() int          { return 2 }
-func (*lookupIndex) IsUnique() bool     { return true }
-func (*lookupIndex) NeedsVCursor() bool { return false }
+func (v *lookupIndex) String() string { return v.name }
+func (*lookupIndex) Cost() int        { return 2 }
+func (*lookupIndex) IsUnique() bool   { return true }
 func (*lookupIndex) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	return []bool{}, nil
 }
@@ -82,10 +80,9 @@ var _ vindexes.Lookup = (*lookupIndex)(nil)
 // multiIndex satisfies Lookup, NonUnique.
 type multiIndex struct{ name string }
 
-func (v *multiIndex) String() string   { return v.name }
-func (*multiIndex) Cost() int          { return 3 }
-func (*multiIndex) IsUnique() bool     { return false }
-func (*multiIndex) NeedsVCursor() bool { return false }
+func (v *multiIndex) String() string { return v.name }
+func (*multiIndex) Cost() int        { return 3 }
+func (*multiIndex) IsUnique() bool   { return false }
 func (*multiIndex) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	return []bool{}, nil
 }
@@ -108,10 +105,9 @@ var _ vindexes.Lookup = (*multiIndex)(nil)
 // costlyIndex satisfies Lookup, NonUnique.
 type costlyIndex struct{ name string }
 
-func (v *costlyIndex) String() string   { return v.name }
-func (*costlyIndex) Cost() int          { return 10 }
-func (*costlyIndex) IsUnique() bool     { return false }
-func (*costlyIndex) NeedsVCursor() bool { return false }
+func (v *costlyIndex) String() string { return v.name }
+func (*costlyIndex) Cost() int        { return 10 }
+func (*costlyIndex) IsUnique() bool   { return false }
 func (*costlyIndex) Verify(vindexes.VCursor, []sqltypes.Value, [][]byte) ([]bool, error) {
 	return []bool{}, nil
 }
diff --git a/go/vt/vtgate/vindexes/binary_test.go b/go/vt/vtgate/vindexes/binary_test.go
index a9c4554e12..ac9d566609 100644
--- a/go/vt/vtgate/vindexes/binary_test.go
+++ b/go/vt/vtgate/vindexes/binary_test.go
@@ -19,9 +19,9 @@ package vindexes
 import (
 	"bytes"
 	"reflect"
+	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -33,11 +33,16 @@ func init() {
 	binOnlyVindex = vindex.(SingleColumn)
 }
 
-func TestBinaryInfo(t *testing.T) {
-	assert.Equal(t, 1, binOnlyVindex.Cost())
-	assert.Equal(t, "binary_varchar", binOnlyVindex.String())
-	assert.True(t, binOnlyVindex.IsUnique())
-	assert.False(t, binOnlyVindex.NeedsVCursor())
+func TestBinaryCost(t *testing.T) {
+	if binOnlyVindex.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", binOnlyVindex.Cost())
+	}
+}
+
+func TestBinaryString(t *testing.T) {
+	if strings.Compare("binary_varchar", binOnlyVindex.String()) != 0 {
+		t.Errorf("String(): %s, want binary_varchar", binOnlyVindex.String())
+	}
 }
 
 func TestBinaryMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/binarymd5_test.go b/go/vt/vtgate/vindexes/binarymd5_test.go
index 51d557003a..f959fb4cd1 100644
--- a/go/vt/vtgate/vindexes/binarymd5_test.go
+++ b/go/vt/vtgate/vindexes/binarymd5_test.go
@@ -20,7 +20,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
+	"strings"
+
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -32,11 +33,16 @@ func init() {
 	binVindex = vindex.(SingleColumn)
 }
 
-func TestBinaryMD5Info(t *testing.T) {
-	assert.Equal(t, 1, binVindex.Cost())
-	assert.Equal(t, "binary_md5_varchar", binVindex.String())
-	assert.True(t, binVindex.IsUnique())
-	assert.False(t, binVindex.NeedsVCursor())
+func TestBinaryMD5Cost(t *testing.T) {
+	if binVindex.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", binVindex.Cost())
+	}
+}
+
+func TestBinaryMD5String(t *testing.T) {
+	if strings.Compare("binary_md5_varchar", binVindex.String()) != 0 {
+		t.Errorf("String(): %s, want binary_md5_varchar", binVindex.String())
+	}
 }
 
 func TestBinaryMD5Map(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/consistent_lookup_test.go b/go/vt/vtgate/vindexes/consistent_lookup_test.go
index b9cd9b4004..bb25c20427 100644
--- a/go/vt/vtgate/vindexes/consistent_lookup_test.go
+++ b/go/vt/vtgate/vindexes/consistent_lookup_test.go
@@ -25,7 +25,6 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 	querypb "vitess.io/vitess/go/vt/proto/query"
@@ -47,18 +46,28 @@ func TestConsistentLookupInit(t *testing.T) {
 
 func TestConsistentLookupInfo(t *testing.T) {
 	lookup := createConsistentLookup(t, "consistent_lookup")
-	assert.Equal(t, 20, lookup.Cost())
-	assert.Equal(t, "consistent_lookup", lookup.String())
-	assert.False(t, lookup.IsUnique())
-	assert.True(t, lookup.NeedsVCursor())
+	if lookup.Cost() != 20 {
+		t.Errorf("Cost(): %d, want 20", lookup.Cost())
+	}
+	if strings.Compare("consistent_lookup", lookup.String()) != 0 {
+		t.Errorf("String(): %s, want consistent_lookup", lookup.String())
+	}
+	if lookup.IsUnique() {
+		t.Errorf("IsUnique(): %v, want false", lookup.IsUnique())
+	}
 }
 
 func TestConsistentLookupUniqueInfo(t *testing.T) {
 	lookup := createConsistentLookup(t, "consistent_lookup_unique")
-	assert.Equal(t, 10, lookup.Cost())
-	assert.Equal(t, "consistent_lookup_unique", lookup.String())
-	assert.True(t, lookup.IsUnique())
-	assert.True(t, lookup.NeedsVCursor())
+	if lookup.Cost() != 10 {
+		t.Errorf("Cost(): %d, want 10", lookup.Cost())
+	}
+	if strings.Compare("consistent_lookup_unique", lookup.String()) != 0 {
+		t.Errorf("String(): %s, want consistent_lookup_unique", lookup.String())
+	}
+	if !lookup.IsUnique() {
+		t.Errorf("IsUnique(): %v, want true", lookup.IsUnique())
+	}
 }
 
 func TestConsistentLookupMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/hash_test.go b/go/vt/vtgate/vindexes/hash_test.go
index 9550ce9535..847cf1968f 100644
--- a/go/vt/vtgate/vindexes/hash_test.go
+++ b/go/vt/vtgate/vindexes/hash_test.go
@@ -18,9 +18,9 @@ package vindexes
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -35,11 +35,16 @@ func init() {
 	hash = hv.(SingleColumn)
 }
 
-func TestHashInfo(t *testing.T) {
-	assert.Equal(t, 1, hash.Cost())
-	assert.Equal(t, "nn", hash.String())
-	assert.True(t, hash.IsUnique())
-	assert.False(t, hash.NeedsVCursor())
+func TestHashCost(t *testing.T) {
+	if hash.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", hash.Cost())
+	}
+}
+
+func TestHashString(t *testing.T) {
+	if strings.Compare("nn", hash.String()) != 0 {
+		t.Errorf("String(): %s, want hash", hash.String())
+	}
 }
 
 func TestHashMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/lookup_hash_test.go b/go/vt/vtgate/vindexes/lookup_hash_test.go
index 076b17d49e..414c86ca93 100644
--- a/go/vt/vtgate/vindexes/lookup_hash_test.go
+++ b/go/vt/vtgate/vindexes/lookup_hash_test.go
@@ -18,9 +18,9 @@ package vindexes
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
@@ -49,18 +49,28 @@ func TestLookupHashNew(t *testing.T) {
 	}
 }
 
-func TestLookupHashInfo(t *testing.T) {
+func TestLookupHashCost(t *testing.T) {
 	lookuphash := createLookup(t, "lookup_hash", false)
-	assert.Equal(t, 20, lookuphash.Cost())
-	assert.Equal(t, "lookup_hash", lookuphash.String())
-	assert.False(t, lookuphash.IsUnique())
-	assert.True(t, lookuphash.NeedsVCursor())
+	lookuphashunique := createLookup(t, "lookup_hash_unique", false)
+
+	if lookuphash.Cost() != 20 {
+		t.Errorf("Cost(): %d, want 20", lookuphash.Cost())
+	}
+	if lookuphashunique.Cost() != 10 {
+		t.Errorf("Cost(): %d, want 10", lookuphashunique.Cost())
+	}
+}
 
+func TestLookupHashString(t *testing.T) {
+	lookuphash := createLookup(t, "lookup_hash", false)
 	lookuphashunique := createLookup(t, "lookup_hash_unique", false)
-	assert.Equal(t, 10, lookuphashunique.Cost())
-	assert.Equal(t, "lookup_hash_unique", lookuphashunique.String())
-	assert.True(t, lookuphashunique.IsUnique())
-	assert.True(t, lookuphashunique.NeedsVCursor())
+
+	if strings.Compare("lookup_hash", lookuphash.String()) != 0 {
+		t.Errorf("String(): %s, want lookup_hash", lookuphash.String())
+	}
+	if strings.Compare("lookup_hash_unique", lookuphashunique.String()) != 0 {
+		t.Errorf("String(): %s, want lookup_hash_unique", lookuphashunique.String())
+	}
 }
 
 func TestLookupHashMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/lookup_hash_unique_test.go b/go/vt/vtgate/vindexes/lookup_hash_unique_test.go
index 445f12fde7..27ea2cb4e2 100644
--- a/go/vt/vtgate/vindexes/lookup_hash_unique_test.go
+++ b/go/vt/vtgate/vindexes/lookup_hash_unique_test.go
@@ -20,7 +20,6 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
@@ -55,12 +54,11 @@ func TestLookupHashUniqueNew(t *testing.T) {
 	}
 }
 
-func TestLookupHashUniqueInfo(t *testing.T) {
+func TestLookupHashUniqueCost(t *testing.T) {
 	lhu := createLookup(t, "lookup_hash_unique", false)
-	assert.Equal(t, 10, lhu.Cost())
-	assert.Equal(t, "lookup_hash_unique", lhu.String())
-	assert.True(t, lhu.IsUnique())
-	assert.True(t, lhu.NeedsVCursor())
+	if lhu.Cost() != 10 {
+		t.Errorf("Cost(): %d, want 10", lhu.Cost())
+	}
 }
 
 func TestLookupHashUniqueMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/lookup_test.go b/go/vt/vtgate/vindexes/lookup_test.go
index 5393af3758..12865b8fb7 100644
--- a/go/vt/vtgate/vindexes/lookup_test.go
+++ b/go/vt/vtgate/vindexes/lookup_test.go
@@ -23,7 +23,6 @@ import (
 
 	"strings"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 
 	"vitess.io/vitess/go/vt/key"
@@ -114,12 +113,18 @@ func TestLookupNonUniqueNew(t *testing.T) {
 	}
 }
 
-func TestLookupNonUniqueInfo(t *testing.T) {
+func TestLookupNonUniqueCost(t *testing.T) {
 	lookupNonUnique := createLookup(t, "lookup", false)
-	assert.Equal(t, 20, lookupNonUnique.Cost())
-	assert.Equal(t, "lookup", lookupNonUnique.String())
-	assert.False(t, lookupNonUnique.IsUnique())
-	assert.True(t, lookupNonUnique.NeedsVCursor())
+	if lookupNonUnique.Cost() != 20 {
+		t.Errorf("Cost(): %d, want 20", lookupNonUnique.Cost())
+	}
+}
+
+func TestLookupNonUniqueString(t *testing.T) {
+	lookupNonUnique := createLookup(t, "lookup", false)
+	if strings.Compare("lookup", lookupNonUnique.String()) != 0 {
+		t.Errorf("String(): %s, want lookup", lookupNonUnique.String())
+	}
 }
 
 func TestLookupNilVCursor(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/lookup_unique_test.go b/go/vt/vtgate/vindexes/lookup_unique_test.go
index 9165bab6c7..cb9ab2bed8 100644
--- a/go/vt/vtgate/vindexes/lookup_unique_test.go
+++ b/go/vt/vtgate/vindexes/lookup_unique_test.go
@@ -18,9 +18,9 @@ package vindexes
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 	querypb "vitess.io/vitess/go/vt/proto/query"
@@ -56,11 +56,18 @@ func TestLookupUniqueNew(t *testing.T) {
 	}
 }
 
-func TestLookupUniqueInfo(t *testing.T) {
+func TestLookupUniqueCost(t *testing.T) {
 	lookupUnique := createLookup(t, "lookup_unique", false)
-	assert.Equal(t, 10, lookupUnique.Cost())
-	assert.Equal(t, "lookup_unique", lookupUnique.String())
-	assert.True(t, lookupUnique.IsUnique())
+	if lookupUnique.Cost() != 10 {
+		t.Errorf("Cost(): %d, want 10", lookupUnique.Cost())
+	}
+}
+
+func TestLookupUniqueString(t *testing.T) {
+	lookupUnique := createLookup(t, "lookup_unique", false)
+	if strings.Compare("lookup_unique", lookupUnique.String()) != 0 {
+		t.Errorf("String(): %s, want lookup_unique", lookupUnique.String())
+	}
 }
 
 func TestLookupUniqueMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/null_test.go b/go/vt/vtgate/vindexes/null_test.go
index 8210c3ae80..11568f9eb5 100644
--- a/go/vt/vtgate/vindexes/null_test.go
+++ b/go/vt/vtgate/vindexes/null_test.go
@@ -18,9 +18,9 @@ package vindexes
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -35,11 +35,16 @@ func init() {
 	null = hv.(SingleColumn)
 }
 
-func TestNullInfo(t *testing.T) {
-	assert.Equal(t, 100, null.Cost())
-	assert.Equal(t, "nn", null.String())
-	assert.True(t, null.IsUnique())
-	assert.False(t, null.NeedsVCursor())
+func TestNullCost(t *testing.T) {
+	if null.Cost() != 0 {
+		t.Errorf("Cost(): %d, want 0", null.Cost())
+	}
+}
+
+func TestNullString(t *testing.T) {
+	if strings.Compare("nn", null.String()) != 0 {
+		t.Errorf("String(): %s, want null", null.String())
+	}
 }
 
 func TestNullMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/numeric_static_map_test.go b/go/vt/vtgate/vindexes/numeric_static_map_test.go
index bd54cef1c6..94035320f0 100644
--- a/go/vt/vtgate/vindexes/numeric_static_map_test.go
+++ b/go/vt/vtgate/vindexes/numeric_static_map_test.go
@@ -20,8 +20,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
+	"strings"
+
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -38,13 +38,24 @@ func createVindex() (SingleColumn, error) {
 	return vindex.(SingleColumn), nil
 }
 
-func TestNumericStaticMapInfo(t *testing.T) {
+func TestNumericStaticMapCost(t *testing.T) {
+	numericStaticMap, err := createVindex()
+	if err != nil {
+		t.Fatalf("failed to create vindex: %v", err)
+	}
+	if numericStaticMap.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", numericStaticMap.Cost())
+	}
+}
+
+func TestNumericStaticMapString(t *testing.T) {
 	numericStaticMap, err := createVindex()
-	require.NoError(t, err)
-	assert.Equal(t, 1, numericStaticMap.Cost())
-	assert.Equal(t, "numericStaticMap", numericStaticMap.String())
-	assert.True(t, numericStaticMap.IsUnique())
-	assert.False(t, numericStaticMap.NeedsVCursor())
+	if err != nil {
+		t.Fatalf("failed to create vindex: %v", err)
+	}
+	if strings.Compare("numericStaticMap", numericStaticMap.String()) != 0 {
+		t.Errorf("String(): %s, want num", numericStaticMap.String())
+	}
 }
 
 func TestNumericStaticMapMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/numeric_test.go b/go/vt/vtgate/vindexes/numeric_test.go
index 326d23dcf1..3d0d053241 100644
--- a/go/vt/vtgate/vindexes/numeric_test.go
+++ b/go/vt/vtgate/vindexes/numeric_test.go
@@ -20,7 +20,8 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
+	"strings"
+
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -32,11 +33,16 @@ func init() {
 	numeric = vindex.(SingleColumn)
 }
 
-func TestNumericInfo(t *testing.T) {
-	assert.Equal(t, 0, numeric.Cost())
-	assert.Equal(t, "num", numeric.String())
-	assert.True(t, numeric.IsUnique())
-	assert.False(t, numeric.NeedsVCursor())
+func TestNumericCost(t *testing.T) {
+	if numeric.Cost() != 0 {
+		t.Errorf("Cost(): %d, want 0", numeric.Cost())
+	}
+}
+
+func TestNumericString(t *testing.T) {
+	if strings.Compare("num", numeric.String()) != 0 {
+		t.Errorf("String(): %s, want num", numeric.String())
+	}
 }
 
 func TestNumericMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/region_experimental_test.go b/go/vt/vtgate/vindexes/region_experimental_test.go
index c0b0b761ef..f1162f4361 100644
--- a/go/vt/vtgate/vindexes/region_experimental_test.go
+++ b/go/vt/vtgate/vindexes/region_experimental_test.go
@@ -21,18 +21,16 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
 
 func TestRegionExperimentalMisc(t *testing.T) {
 	ge, err := createRegionVindex(t, "region_experimental", "f1,f2", 1)
-	require.NoError(t, err)
+	assert.NoError(t, err)
 	assert.Equal(t, 1, ge.Cost())
 	assert.Equal(t, "region_experimental", ge.String())
 	assert.True(t, ge.IsUnique())
-	assert.False(t, ge.NeedsVCursor())
 }
 
 func TestRegionExperimentalMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/reverse_bits_test.go b/go/vt/vtgate/vindexes/reverse_bits_test.go
index 4cc12cbb96..a135b8ca56 100644
--- a/go/vt/vtgate/vindexes/reverse_bits_test.go
+++ b/go/vt/vtgate/vindexes/reverse_bits_test.go
@@ -18,9 +18,9 @@ package vindexes
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -35,11 +35,16 @@ func init() {
 	reverseBits = hv.(SingleColumn)
 }
 
-func TestReverseBitsInfo(t *testing.T) {
-	assert.Equal(t, 1, reverseBits.Cost())
-	assert.Equal(t, "rr", reverseBits.String())
-	assert.True(t, reverseBits.IsUnique())
-	assert.False(t, reverseBits.NeedsVCursor())
+func TestReverseBitsCost(t *testing.T) {
+	if reverseBits.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", reverseBits.Cost())
+	}
+}
+
+func TestReverseBitsString(t *testing.T) {
+	if strings.Compare("rr", reverseBits.String()) != 0 {
+		t.Errorf("String(): %s, want hash", reverseBits.String())
+	}
 }
 
 func TestReverseBitsMap(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/unicodeloosemd5_test.go b/go/vt/vtgate/vindexes/unicodeloosemd5_test.go
index 04695d2e34..89bcc19fbb 100644
--- a/go/vt/vtgate/vindexes/unicodeloosemd5_test.go
+++ b/go/vt/vtgate/vindexes/unicodeloosemd5_test.go
@@ -22,7 +22,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
 )
@@ -34,11 +33,16 @@ func init() {
 	charVindex = vindex.(SingleColumn)
 }
 
-func TestUnicodeLooseMD5Info(t *testing.T) {
-	assert.Equal(t, 1, charVindex.Cost())
-	assert.Equal(t, "utf8ch", charVindex.String())
-	assert.True(t, charVindex.IsUnique())
-	assert.False(t, charVindex.NeedsVCursor())
+func TestUnicodeLooseMD5Cost(t *testing.T) {
+	if charVindex.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", charVindex.Cost())
+	}
+}
+
+func TestUnicodeLooseMD5String(t *testing.T) {
+	if strings.Compare("utf8ch", charVindex.String()) != 0 {
+		t.Errorf("String(): %s, want utf8ch", charVindex.String())
+	}
 }
 
 func TestUnicodeLooseMD5Map(t *testing.T) {
diff --git a/go/vt/vtgate/vindexes/vschema_test.go b/go/vt/vtgate/vindexes/vschema_test.go
index 3c18234f86..5ed01c5285 100644
--- a/go/vt/vtgate/vindexes/vschema_test.go
+++ b/go/vt/vtgate/vindexes/vschema_test.go
@@ -45,7 +45,6 @@ type stFU struct {
 func (v *stFU) String() string                                                    { return v.name }
 func (*stFU) Cost() int                                                           { return 1 }
 func (*stFU) IsUnique() bool                                                      { return true }
-func (*stFU) NeedsVCursor() bool                                                  { return false }
 func (*stFU) Verify(VCursor, []sqltypes.Value, [][]byte) ([]bool, error)          { return []bool{}, nil }
 func (*stFU) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { return nil, nil }
 
@@ -64,7 +63,6 @@ type stLN struct {
 func (v *stLN) String() string                                                    { return v.name }
 func (*stLN) Cost() int                                                           { return 0 }
 func (*stLN) IsUnique() bool                                                      { return false }
-func (*stLN) NeedsVCursor() bool                                                  { return false }
 func (*stLN) Verify(VCursor, []sqltypes.Value, [][]byte) ([]bool, error)          { return []bool{}, nil }
 func (*stLN) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { return nil, nil }
 func (*stLN) Create(VCursor, [][]sqltypes.Value, [][]byte, bool) error            { return nil }
@@ -87,7 +85,6 @@ type stLU struct {
 func (v *stLU) String() string                                                    { return v.name }
 func (*stLU) Cost() int                                                           { return 2 }
 func (*stLU) IsUnique() bool                                                      { return true }
-func (*stLU) NeedsVCursor() bool                                                  { return false }
 func (*stLU) Verify(VCursor, []sqltypes.Value, [][]byte) ([]bool, error)          { return []bool{}, nil }
 func (*stLU) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { return nil, nil }
 func (*stLU) Create(VCursor, [][]sqltypes.Value, [][]byte, bool) error            { return nil }
@@ -113,7 +110,6 @@ type stLO struct {
 func (v *stLO) String() string                                                    { return v.name }
 func (*stLO) Cost() int                                                           { return 2 }
 func (*stLO) IsUnique() bool                                                      { return true }
-func (*stLO) NeedsVCursor() bool                                                  { return false }
 func (*stLO) Verify(VCursor, []sqltypes.Value, [][]byte) ([]bool, error)          { return []bool{}, nil }
 func (*stLO) Map(cursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { return nil, nil }
 func (*stLO) Create(VCursor, [][]sqltypes.Value, [][]byte, bool) error            { return nil }
diff --git a/go/vt/vtgate/vindexes/xxhash_test.go b/go/vt/vtgate/vindexes/xxhash_test.go
index dc66aa3d7b..187682f972 100644
--- a/go/vt/vtgate/vindexes/xxhash_test.go
+++ b/go/vt/vtgate/vindexes/xxhash_test.go
@@ -20,10 +20,10 @@ import (
 	"bytes"
 	"fmt"
 	"reflect"
+	"strings"
 	"testing"
 
 	"github.com/cespare/xxhash/v2"
-	"github.com/stretchr/testify/assert"
 
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/key"
@@ -39,11 +39,16 @@ func init() {
 	xxHash = hv.(SingleColumn)
 }
 
-func TestXXHashInfo(t *testing.T) {
-	assert.Equal(t, 1, xxHash.Cost())
-	assert.Equal(t, "xxhash_name", xxHash.String())
-	assert.True(t, xxHash.IsUnique())
-	assert.False(t, xxHash.NeedsVCursor())
+func TestXXHashCost(t *testing.T) {
+	if xxHash.Cost() != 1 {
+		t.Errorf("Cost(): %d, want 1", xxHash.Cost())
+	}
+}
+
+func TestXXHashString(t *testing.T) {
+	if strings.Compare("xxhash_name", xxHash.String()) != 0 {
+		t.Errorf("String(): %s, want xxhash_name", xxHash.String())
+	}
 }
 
 func TestXXHashMap(t *testing.T) {
diff --git a/go/vt/vttablet/tabletserver/vstreamer/local_vschema_test.go b/go/vt/vttablet/tabletserver/vstreamer/local_vschema_test.go
index 37ea34dfe4..0ac313eb77 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/local_vschema_test.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/local_vschema_test.go
@@ -27,151 +27,78 @@ import (
 	"vitess.io/vitess/go/vt/vtgate/vindexes"
 )
 
-func TestFindColVindex(t *testing.T) {
-	testSrvVSchema := &vschemapb.SrvVSchema{
-		Keyspaces: map[string]*vschemapb.Keyspace{
-			"ks1": {
-				Sharded: true,
-				Vindexes: map[string]*vschemapb.Vindex{
-					"hash": {
-						Type: "hash",
-					},
-					"lookup_unique": {
-						Type: "lookup_unique",
-						Params: map[string]string{
-							"table": "t",
-							"from":  "fromc",
-							"to":    "toc",
-						},
-					},
-					"lookup": {
-						Type: "lookup",
-						Params: map[string]string{
-							"table": "t",
-							"from":  "fromc",
-							"to":    "toc",
-						},
-					},
-					"numeric": {
-						Type: "numeric",
-					},
+var testSrvVSchema = &vschemapb.SrvVSchema{
+	Keyspaces: map[string]*vschemapb.Keyspace{
+		"ks1": {
+			Sharded: true,
+			Vindexes: map[string]*vschemapb.Vindex{
+				"duphash": {
+					Type: "hash",
 				},
-				Tables: map[string]*vschemapb.Table{
-					"t1": {
-						ColumnVindexes: []*vschemapb.ColumnVindex{{
-							Name:    "hash",
-							Columns: []string{"id"},
-						}},
-					},
-					"nogoodvindex1": {
-						ColumnVindexes: []*vschemapb.ColumnVindex{{
-							Name:    "lookup_unique",
-							Columns: []string{"id"},
-						}},
-					},
-					"nogoodvindex2": {
-						ColumnVindexes: []*vschemapb.ColumnVindex{{
-							Name:    "lookup_unique",
-							Columns: []string{"id"},
-						}, {
-							Name:    "lookup",
-							Columns: []string{"id"},
-						}},
-					},
-					"cheapest": {
-						ColumnVindexes: []*vschemapb.ColumnVindex{{
-							Name:    "hash",
-							Columns: []string{"id"},
-						}, {
-							Name:    "numeric",
-							Columns: []string{"id"},
-						}},
-					},
+			},
+			Tables: map[string]*vschemapb.Table{
+				"t1": {
+					ColumnVindexes: []*vschemapb.ColumnVindex{{
+						Name:    "duphash",
+						Columns: []string{"id"},
+					}},
 				},
 			},
-			"unsharded": {
-				Tables: map[string]*vschemapb.Table{
-					"t1": {},
+		},
+		"ks2": {
+			Sharded: true,
+			Vindexes: map[string]*vschemapb.Vindex{
+				"duphash": {
+					Type: "hash",
+				},
+				"otherhash": {
+					Type: "hash",
 				},
 			},
 		},
-	}
+	},
+}
+
+func TestFindTable(t *testing.T) {
 	vschema, err := vindexes.BuildVSchema(testSrvVSchema)
 	require.NoError(t, err)
 
 	testcases := []struct {
-		keyspace   string
-		tablename  string
-		vindexname string
-		err        string
+		keyspace  string
+		tablename string
+		err       string
 	}{{
-		keyspace:   "ks1",
-		tablename:  "t1",
-		vindexname: "hash",
-	}, {
 		keyspace:  "ks1",
-		tablename: "nogoodvindex1",
-		err:       "could not find a vindex to compute keyspace id for table nogoodvindex1",
+		tablename: "t1",
+		err:       "",
 	}, {
 		keyspace:  "ks1",
-		tablename: "nogoodvindex2",
-		err:       "could not find a vindex to compute keyspace id for table nogoodvindex2",
-	}, {
-		keyspace:   "ks1",
-		tablename:  "cheapest",
-		vindexname: "numeric",
+		tablename: "t2",
+		err:       "table t2 not found",
 	}, {
-		keyspace:  "unsharded",
-		tablename: "t1",
-		err:       "table t1 has no vindex",
+		keyspace:  "noks",
+		tablename: "t2",
+		err:       "keyspace noks not found in vschema",
 	}}
 	for _, tcase := range testcases {
 		lvs := &localVSchema{
 			keyspace: tcase.keyspace,
 			vschema:  vschema,
 		}
-		cv, err := lvs.FindColVindex(tcase.tablename)
+		table, err := lvs.FindTable(tcase.tablename)
 		if err != nil {
-			assert.EqualError(t, err, tcase.err, tcase.tablename)
+			assert.EqualError(t, err, tcase.err, tcase.keyspace, tcase.tablename)
 			continue
 		}
-		assert.NoError(t, err, tcase.tablename)
-		assert.Equal(t, cv.Name, tcase.vindexname, tcase.tablename)
+		assert.NoError(t, err, tcase.keyspace, tcase.tablename)
+		assert.Equal(t, table.Name.String(), tcase.tablename, tcase.keyspace, tcase.tablename)
 	}
 }
 
 func TestFindOrCreateVindex(t *testing.T) {
-	testSrvVSchema := &vschemapb.SrvVSchema{
-		Keyspaces: map[string]*vschemapb.Keyspace{
-			"ks1": {
-				Sharded: true,
-				Vindexes: map[string]*vschemapb.Vindex{
-					"duphash": {
-						Type: "hash",
-					},
-				},
-			},
-			"ks2": {
-				Sharded: true,
-				Vindexes: map[string]*vschemapb.Vindex{
-					"duphash": {
-						Type: "hash",
-					},
-					"otherhash": {
-						Type: "hash",
-					},
-				},
-			},
-		},
-	}
 	vschema, err := vindexes.BuildVSchema(testSrvVSchema)
 	require.NoError(t, err)
 
-	lvs := &localVSchema{
-		keyspace: "ks1",
-		vschema:  vschema,
-	}
-
 	testcases := []struct {
 		name string
 		err  string
@@ -198,6 +125,10 @@ func TestFindOrCreateVindex(t *testing.T) {
 		err:  `vindexType "none" not found`,
 	}}
 	for _, tcase := range testcases {
+		lvs := &localVSchema{
+			keyspace: "ks1",
+			vschema:  vschema,
+		}
 		vindex, err := lvs.FindOrCreateVindex(tcase.name)
 		if err != nil {
 			assert.EqualError(t, err, tcase.err, tcase.name)
@@ -209,48 +140,3 @@ func TestFindOrCreateVindex(t *testing.T) {
 		assert.Equal(t, vindex.String(), want, tcase.name)
 	}
 }
-
-func TestFindTable(t *testing.T) {
-	testSrvVSchema := &vschemapb.SrvVSchema{
-		Keyspaces: map[string]*vschemapb.Keyspace{
-			"ks1": {
-				Tables: map[string]*vschemapb.Table{
-					"t1": {},
-				},
-			},
-		},
-	}
-	vschema, err := vindexes.BuildVSchema(testSrvVSchema)
-	require.NoError(t, err)
-
-	testcases := []struct {
-		keyspace  string
-		tablename string
-		err       string
-	}{{
-		keyspace:  "ks1",
-		tablename: "t1",
-		err:       "",
-	}, {
-		keyspace:  "ks1",
-		tablename: "t2",
-		err:       "table t2 not found",
-	}, {
-		keyspace:  "noks",
-		tablename: "t2",
-		err:       "keyspace noks not found in vschema",
-	}}
-	for _, tcase := range testcases {
-		lvs := &localVSchema{
-			keyspace: tcase.keyspace,
-			vschema:  vschema,
-		}
-		table, err := lvs.findTable(tcase.tablename)
-		if err != nil {
-			assert.EqualError(t, err, tcase.err, tcase.keyspace, tcase.tablename)
-			continue
-		}
-		assert.NoError(t, err, tcase.keyspace, tcase.tablename)
-		assert.Equal(t, table.Name.String(), tcase.tablename, tcase.keyspace, tcase.tablename)
-	}
-}
diff --git a/test/config.json b/test/config.json
index cf8c510dab..529a7429e2 100644
--- a/test/config.json
+++ b/test/config.json
@@ -481,7 +481,7 @@
 			"Args": [],
 			"Command": [],
 			"Manual": false,
-			"Shard": 4,
+			"Shard": 5,
 			"RetryMax": 0,
 			"Tags": [
 				"worker_test"
@@ -492,7 +492,7 @@
 			"Args": [],
 			"Command": [],
 			"Manual": false,
-			"Shard": 4,
+			"Shard": 5,
 			"RetryMax": 0,
 			"Tags": [
 				"worker_test"