vitess.io/vitess@v0.16.2/go/vt/wrangler/resharder_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package wrangler
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"context"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  
    30  	"vitess.io/vitess/go/sqltypes"
    31  	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
    32  	tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
    33  	vschemapb "vitess.io/vitess/go/vt/proto/vschema"
    34  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    35  )
    36  
    37  const rsSelectFrozenQuery = "select 1 from _vt.vreplication where db_name='vt_ks' and message='FROZEN' and workflow_sub_type != 1"
    38  const insertPrefix = `/insert into _vt.vreplication\(workflow, source, pos, max_tps, max_replication_lag, cell, tablet_types, time_updated, transaction_timestamp, state, db_name, workflow_type, workflow_sub_type, defer_secondary_keys\) values `
    39  const eol = "$"
    40  
    41  func TestResharderOneToMany(t *testing.T) {
    42  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
    43  	defer env.close()
    44  
    45  	schm := &tabletmanagerdatapb.SchemaDefinition{
    46  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
    47  			Name:              "t1",
    48  			Columns:           []string{"c1", "c2"},
    49  			PrimaryKeyColumns: []string{"c1"},
    50  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
    51  		}},
    52  	}
    53  	env.tmc.schema = schm
    54  
    55  	env.expectValidation()
    56  	env.expectNoRefStream()
    57  
    58  	type testCase struct {
    59  		cells       string
    60  		tabletTypes string
    61  	}
    62  	var newTestCase = func(cells, tabletTypes string) *testCase {
    63  		return &testCase{
    64  			cells:       cells,
    65  			tabletTypes: tabletTypes,
    66  		}
    67  	}
    68  	var testCases []*testCase
    69  
    70  	testCases = append(testCases, newTestCase("", ""))
    71  	testCases = append(testCases, newTestCase("cell", "primary"))
    72  	testCases = append(testCases, newTestCase("cell", "primary,replica"))
    73  	testCases = append(testCases, newTestCase("", "replica,rdonly"))
    74  
    75  	for _, tc := range testCases {
    76  		env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
    77  
    78  		schm := &tabletmanagerdatapb.SchemaDefinition{
    79  			TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
    80  				Name:              "t1",
    81  				Columns:           []string{"c1", "c2"},
    82  				PrimaryKeyColumns: []string{"c1"},
    83  				Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
    84  			}},
    85  		}
    86  		env.tmc.schema = schm
    87  
    88  		env.expectValidation()
    89  		env.expectNoRefStream()
    90  		name := tc.cells + "/" + tc.tabletTypes
    91  		t.Run(name, func(t *testing.T) {
    92  			env.tmc.expectVRQuery(
    93  				200,
    94  				insertPrefix+
    95  					`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '`+
    96  					tc.cells+`', '`+tc.tabletTypes+`', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+eol,
    97  				&sqltypes.Result{},
    98  			)
    99  			env.tmc.expectVRQuery(
   100  				210,
   101  				insertPrefix+
   102  					`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '`+
   103  					tc.cells+`', '`+tc.tabletTypes+`', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+eol,
   104  				&sqltypes.Result{},
   105  			)
   106  			env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   107  			env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   108  
   109  			err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, tc.cells, tc.tabletTypes, defaultOnDDL, true, false, false)
   110  			require.NoError(t, err)
   111  			env.tmc.verifyQueries(t)
   112  		})
   113  		env.close()
   114  	}
   115  }
   116  
   117  func TestResharderManyToOne(t *testing.T) {
   118  	env := newTestResharderEnv(t, []string{"-80", "80-"}, []string{"0"})
   119  	defer env.close()
   120  
   121  	schm := &tabletmanagerdatapb.SchemaDefinition{
   122  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   123  			Name:              "t1",
   124  			Columns:           []string{"c1", "c2"},
   125  			PrimaryKeyColumns: []string{"c1"},
   126  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   127  		}},
   128  	}
   129  	env.tmc.schema = schm
   130  
   131  	env.expectValidation()
   132  	env.expectNoRefStream()
   133  
   134  	env.tmc.expectVRQuery(
   135  		200,
   136  		insertPrefix+
   137  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"-80\\" filter:{rules:{match:\\"/.*\\" filter:\\"-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+
   138  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"80-\\" filter:{rules:{match:\\"/.*\\" filter:\\"-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   139  			eol,
   140  		&sqltypes.Result{},
   141  	)
   142  
   143  	env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   144  
   145  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   146  	assert.NoError(t, err)
   147  	env.tmc.verifyQueries(t)
   148  }
   149  
   150  func TestResharderManyToMany(t *testing.T) {
   151  	env := newTestResharderEnv(t, []string{"-40", "40-"}, []string{"-80", "80-"})
   152  	defer env.close()
   153  
   154  	schm := &tabletmanagerdatapb.SchemaDefinition{
   155  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   156  			Name:              "t1",
   157  			Columns:           []string{"c1", "c2"},
   158  			PrimaryKeyColumns: []string{"c1"},
   159  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   160  		}},
   161  	}
   162  	env.tmc.schema = schm
   163  
   164  	env.expectValidation()
   165  	env.expectNoRefStream()
   166  
   167  	env.tmc.expectVRQuery(
   168  		200,
   169  		insertPrefix+
   170  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"-40\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+
   171  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"40-\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   172  			eol,
   173  		&sqltypes.Result{},
   174  	)
   175  	env.tmc.expectVRQuery(
   176  		210,
   177  		insertPrefix+
   178  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"40-\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   179  			eol,
   180  		&sqltypes.Result{},
   181  	)
   182  
   183  	env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   184  	env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   185  
   186  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   187  	assert.NoError(t, err)
   188  	env.tmc.verifyQueries(t)
   189  }
   190  
   191  // TestResharderOneRefTable tests the case where there's one ref table, but no stream for it.
   192  // This means that the table is being updated manually.
   193  func TestResharderOneRefTable(t *testing.T) {
   194  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   195  	defer env.close()
   196  
   197  	schm := &tabletmanagerdatapb.SchemaDefinition{
   198  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   199  			Name:              "t1",
   200  			Columns:           []string{"c1", "c2"},
   201  			PrimaryKeyColumns: []string{"c1"},
   202  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   203  		}},
   204  	}
   205  	env.tmc.schema = schm
   206  
   207  	vs := &vschemapb.Keyspace{
   208  		Tables: map[string]*vschemapb.Table{
   209  			"t1": {
   210  				Type: vindexes.TypeReference,
   211  			},
   212  		},
   213  	}
   214  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   215  		t.Fatal(err)
   216  	}
   217  
   218  	env.expectValidation()
   219  	env.expectNoRefStream()
   220  
   221  	env.tmc.expectVRQuery(
   222  		200,
   223  		insertPrefix+
   224  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   225  			eol,
   226  		&sqltypes.Result{},
   227  	)
   228  	env.tmc.expectVRQuery(
   229  		210,
   230  		insertPrefix+
   231  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   232  			eol,
   233  		&sqltypes.Result{},
   234  	)
   235  
   236  	env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   237  	env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   238  
   239  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   240  	assert.NoError(t, err)
   241  	env.tmc.verifyQueries(t)
   242  }
   243  
   244  // TestReshardStopFlags tests the flags -stop_started and -stop_after_copy
   245  func TestReshardStopFlags(t *testing.T) {
   246  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   247  	defer env.close()
   248  
   249  	schm := &tabletmanagerdatapb.SchemaDefinition{
   250  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   251  			Name:              "t1",
   252  			Columns:           []string{"c1", "c2"},
   253  			PrimaryKeyColumns: []string{"c1"},
   254  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   255  		}},
   256  	}
   257  	env.tmc.schema = schm
   258  
   259  	vs := &vschemapb.Keyspace{
   260  		Tables: map[string]*vschemapb.Table{
   261  			"t1": {
   262  				Type: vindexes.TypeReference,
   263  			},
   264  		},
   265  	}
   266  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	env.expectValidation()
   271  	env.expectNoRefStream()
   272  	// inserts into the two shards expects flag stop_after_copy to be true
   273  
   274  	env.tmc.expectVRQuery(
   275  		200,
   276  		insertPrefix+
   277  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"-80\\"}} stop_after_copy:true', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   278  			eol,
   279  		&sqltypes.Result{},
   280  	)
   281  	env.tmc.expectVRQuery(
   282  		210,
   283  		insertPrefix+
   284  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"80-\\"}} stop_after_copy:true', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   285  			eol,
   286  		&sqltypes.Result{},
   287  	)
   288  	// -auto_start=false is tested by NOT expecting the update query which sets state to RUNNING
   289  
   290  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, false, true, false)
   291  	assert.NoError(t, err)
   292  	env.tmc.verifyQueries(t)
   293  }
   294  
   295  // TestResharderOneRefStream tests the case where there's one ref table and an associated stream.
   296  func TestResharderOneRefStream(t *testing.T) {
   297  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   298  	defer env.close()
   299  
   300  	schm := &tabletmanagerdatapb.SchemaDefinition{
   301  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   302  			Name:              "t1",
   303  			Columns:           []string{"c1", "c2"},
   304  			PrimaryKeyColumns: []string{"c1"},
   305  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   306  		}},
   307  	}
   308  	env.tmc.schema = schm
   309  
   310  	vs := &vschemapb.Keyspace{
   311  		Tables: map[string]*vschemapb.Table{
   312  			"t1": {
   313  				Type: vindexes.TypeReference,
   314  			},
   315  		},
   316  	}
   317  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   318  		t.Fatal(err)
   319  	}
   320  
   321  	env.expectValidation()
   322  
   323  	bls := &binlogdatapb.BinlogSource{
   324  		Keyspace: "ks1",
   325  		Shard:    "0",
   326  		Filter: &binlogdatapb.Filter{
   327  			Rules: []*binlogdatapb.Rule{{
   328  				Match: "t1",
   329  			}},
   330  		},
   331  	}
   332  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   333  		"workflow|source|cell|tablet_types",
   334  		"varchar|varchar|varchar|varchar"),
   335  		fmt.Sprintf("t1|%v|cell1|primary,replica", bls),
   336  	)
   337  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result)
   338  
   339  	refRow := `\('t1', 'keyspace:\\"ks1\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\"}}', '', [0-9]*, [0-9]*, 'cell1', 'primary,replica', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`
   340  	env.tmc.expectVRQuery(
   341  		200,
   342  		insertPrefix+
   343  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+
   344  			refRow+eol,
   345  		&sqltypes.Result{},
   346  	)
   347  	env.tmc.expectVRQuery(
   348  		210,
   349  		insertPrefix+
   350  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"t1\\" filter:\\"exclude\\"} rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\).*`+
   351  			refRow+eol,
   352  		&sqltypes.Result{},
   353  	)
   354  
   355  	env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   356  	env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   357  
   358  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   359  	assert.NoError(t, err)
   360  	env.tmc.verifyQueries(t)
   361  }
   362  
   363  // TestResharderNoRefStream tests the case where there's a stream, but it's not a reference.
   364  func TestResharderNoRefStream(t *testing.T) {
   365  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   366  	defer env.close()
   367  
   368  	schm := &tabletmanagerdatapb.SchemaDefinition{
   369  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   370  			Name:              "t1",
   371  			Columns:           []string{"c1", "c2"},
   372  			PrimaryKeyColumns: []string{"c1"},
   373  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   374  		}},
   375  	}
   376  	env.tmc.schema = schm
   377  
   378  	vs := &vschemapb.Keyspace{
   379  		Sharded: true,
   380  		Vindexes: map[string]*vschemapb.Vindex{
   381  			"hash": {
   382  				Type: "hash",
   383  			},
   384  		},
   385  		Tables: map[string]*vschemapb.Table{
   386  			"t1": {
   387  				ColumnVindexes: []*vschemapb.ColumnVindex{{
   388  					Column: "c1",
   389  					Name:   "hash",
   390  				}},
   391  			},
   392  		},
   393  	}
   394  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   395  		t.Fatal(err)
   396  	}
   397  
   398  	env.expectValidation()
   399  
   400  	bls := &binlogdatapb.BinlogSource{
   401  		Keyspace: "ks1",
   402  		Shard:    "0",
   403  		Filter: &binlogdatapb.Filter{
   404  			Rules: []*binlogdatapb.Rule{{
   405  				Match:  "t1",
   406  				Filter: "select * from t2",
   407  			}},
   408  		},
   409  	}
   410  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   411  		"workflow|source|cell|tablet_types",
   412  		"varchar|varchar|varchar|varchar"),
   413  		fmt.Sprintf("t1|%v|cell1|primary,replica", bls),
   414  	)
   415  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result)
   416  
   417  	env.tmc.expectVRQuery(
   418  		200,
   419  		insertPrefix+
   420  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   421  			eol,
   422  		&sqltypes.Result{},
   423  	)
   424  	env.tmc.expectVRQuery(
   425  		210,
   426  		insertPrefix+
   427  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   428  			eol,
   429  		&sqltypes.Result{},
   430  	)
   431  
   432  	env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   433  	env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   434  
   435  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   436  	assert.NoError(t, err)
   437  	env.tmc.verifyQueries(t)
   438  }
   439  
   440  func TestResharderCopySchema(t *testing.T) {
   441  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   442  	defer env.close()
   443  
   444  	schm := &tabletmanagerdatapb.SchemaDefinition{
   445  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   446  			Name:              "t1",
   447  			Columns:           []string{"c1", "c2"},
   448  			PrimaryKeyColumns: []string{"c1"},
   449  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   450  		}},
   451  	}
   452  	env.tmc.schema = schm
   453  
   454  	env.expectValidation()
   455  	env.expectNoRefStream()
   456  
   457  	env.tmc.expectVRQuery(
   458  		200,
   459  		insertPrefix+
   460  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"-80\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   461  			eol,
   462  		&sqltypes.Result{},
   463  	)
   464  	env.tmc.expectVRQuery(
   465  		210,
   466  		insertPrefix+
   467  			`\('resharderTest', 'keyspace:\\"ks\\" shard:\\"0\\" filter:{rules:{match:\\"/.*\\" filter:\\"80-\\"}}', '', [0-9]*, [0-9]*, '', '', [0-9]*, 0, 'Stopped', 'vt_ks', 4, 0, false\)`+
   468  			eol,
   469  		&sqltypes.Result{},
   470  	)
   471  
   472  	env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   473  	env.tmc.expectVRQuery(210, "update _vt.vreplication set state='Running' where db_name='vt_ks'", &sqltypes.Result{})
   474  
   475  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, false, "", "", defaultOnDDL, true, false, false)
   476  	assert.NoError(t, err)
   477  	env.tmc.verifyQueries(t)
   478  }
   479  
   480  func TestResharderDupWorkflow(t *testing.T) {
   481  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   482  	defer env.close()
   483  
   484  	schm := &tabletmanagerdatapb.SchemaDefinition{
   485  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   486  			Name:              "t1",
   487  			Columns:           []string{"c1", "c2"},
   488  			PrimaryKeyColumns: []string{"c1"},
   489  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   490  		}},
   491  	}
   492  	env.tmc.schema = schm
   493  
   494  	env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   495  	env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   496  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   497  		"1",
   498  		"int64"),
   499  		"1",
   500  	)
   501  	env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), result)
   502  
   503  	env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{})
   504  	env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{})
   505  
   506  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   507  	assert.EqualError(t, err, "validateWorkflowName.VReplicationExec: workflow resharderTest already exists in keyspace ks on tablet 210")
   508  	env.tmc.verifyQueries(t)
   509  }
   510  
   511  func TestResharderServingState(t *testing.T) {
   512  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   513  	defer env.close()
   514  
   515  	schm := &tabletmanagerdatapb.SchemaDefinition{
   516  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   517  			Name:              "t1",
   518  			Columns:           []string{"c1", "c2"},
   519  			PrimaryKeyColumns: []string{"c1"},
   520  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   521  		}},
   522  	}
   523  	env.tmc.schema = schm
   524  
   525  	env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   526  	env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   527  	env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   528  	env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{})
   529  	env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{})
   530  	env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{})
   531  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, []string{"-80"}, nil, true, "", "", defaultOnDDL, true, false, false)
   532  	assert.EqualError(t, err, "buildResharder: source shard -80 is not in serving state")
   533  
   534  	env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   535  	env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   536  	env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   537  	env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{})
   538  	env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{})
   539  	env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{})
   540  	err = env.wr.Reshard(context.Background(), env.keyspace, env.workflow, []string{"0"}, []string{"0"}, true, "", "", defaultOnDDL, true, false, false)
   541  	assert.EqualError(t, err, "buildResharder: target shard 0 is in serving state")
   542  
   543  	env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   544  	env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   545  	env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   546  	env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{})
   547  	env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{})
   548  	env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{})
   549  	err = env.wr.Reshard(context.Background(), env.keyspace, env.workflow, []string{"0"}, []string{"-80"}, true, "", "", defaultOnDDL, true, false, false)
   550  	assert.EqualError(t, err, "buildResharder: ValidateForReshard: source and target keyranges don't match: - vs -80")
   551  }
   552  
   553  func TestResharderTargetAlreadyResharding(t *testing.T) {
   554  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   555  	defer env.close()
   556  
   557  	schm := &tabletmanagerdatapb.SchemaDefinition{
   558  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   559  			Name:              "t1",
   560  			Columns:           []string{"c1", "c2"},
   561  			PrimaryKeyColumns: []string{"c1"},
   562  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   563  		}},
   564  	}
   565  	env.tmc.schema = schm
   566  
   567  	env.tmc.expectVRQuery(100, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   568  	env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   569  	env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s' and workflow='%s'", env.keyspace, env.workflow), &sqltypes.Result{})
   570  
   571  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   572  		"1",
   573  		"int64"),
   574  		"1",
   575  	)
   576  	env.tmc.expectVRQuery(200, rsSelectFrozenQuery, &sqltypes.Result{})
   577  	env.tmc.expectVRQuery(210, rsSelectFrozenQuery, &sqltypes.Result{})
   578  	env.tmc.expectVRQuery(200, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s'", env.keyspace), result)
   579  	env.tmc.expectVRQuery(210, fmt.Sprintf("select 1 from _vt.vreplication where db_name='vt_%s'", env.keyspace), &sqltypes.Result{})
   580  	env.tmc.expectVRQuery(100, rsSelectFrozenQuery, &sqltypes.Result{})
   581  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   582  	assert.EqualError(t, err, "buildResharder: validateTargets: some streams already exist in the target shards, please clean them up and retry the command")
   583  	env.tmc.verifyQueries(t)
   584  }
   585  
   586  func TestResharderUnnamedStream(t *testing.T) {
   587  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   588  	defer env.close()
   589  
   590  	schm := &tabletmanagerdatapb.SchemaDefinition{
   591  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   592  			Name:              "t1",
   593  			Columns:           []string{"c1", "c2"},
   594  			PrimaryKeyColumns: []string{"c1"},
   595  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   596  		}},
   597  	}
   598  	env.tmc.schema = schm
   599  
   600  	vs := &vschemapb.Keyspace{
   601  		Tables: map[string]*vschemapb.Table{
   602  			"t1": {
   603  				Type: vindexes.TypeReference,
   604  			},
   605  		},
   606  	}
   607  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   608  		t.Fatal(err)
   609  	}
   610  
   611  	env.expectValidation()
   612  
   613  	bls := &binlogdatapb.BinlogSource{
   614  		Keyspace: "ks1",
   615  		Shard:    "0",
   616  		Filter: &binlogdatapb.Filter{
   617  			Rules: []*binlogdatapb.Rule{{
   618  				Match: "t1",
   619  			}},
   620  		},
   621  	}
   622  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   623  		"workflow|source|cell|tablet_types",
   624  		"varchar|varchar|varchar|varchar"),
   625  		fmt.Sprintf("|%v|cell1|primary,replica", bls),
   626  	)
   627  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result)
   628  
   629  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   630  	assert.EqualError(t, err, "buildResharder: readRefStreams: VReplication streams must have named workflows for migration: shard: ks:0")
   631  	env.tmc.verifyQueries(t)
   632  }
   633  
   634  func TestResharderMismatchedRefStreams(t *testing.T) {
   635  	env := newTestResharderEnv(t, []string{"-80", "80-"}, []string{"0"})
   636  	defer env.close()
   637  
   638  	schm := &tabletmanagerdatapb.SchemaDefinition{
   639  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   640  			Name:              "t1",
   641  			Columns:           []string{"c1", "c2"},
   642  			PrimaryKeyColumns: []string{"c1"},
   643  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   644  		}},
   645  	}
   646  	env.tmc.schema = schm
   647  
   648  	vs := &vschemapb.Keyspace{
   649  		Tables: map[string]*vschemapb.Table{
   650  			"t1": {
   651  				Type: vindexes.TypeReference,
   652  			},
   653  		},
   654  	}
   655  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   656  		t.Fatal(err)
   657  	}
   658  
   659  	env.expectValidation()
   660  
   661  	bls1 := &binlogdatapb.BinlogSource{
   662  		Keyspace: "ks1",
   663  		Shard:    "0",
   664  		Filter: &binlogdatapb.Filter{
   665  			Rules: []*binlogdatapb.Rule{{
   666  				Match: "t1",
   667  			}},
   668  		},
   669  	}
   670  	result1 := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   671  		"workflow|source|cell|tablet_types",
   672  		"varchar|varchar|varchar|varchar"),
   673  		fmt.Sprintf("t1|%v|cell1|primary,replica", bls1),
   674  	)
   675  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result1)
   676  	bls2 := &binlogdatapb.BinlogSource{
   677  		Keyspace: "ks2",
   678  		Shard:    "0",
   679  		Filter: &binlogdatapb.Filter{
   680  			Rules: []*binlogdatapb.Rule{{
   681  				Match: "t1",
   682  			}},
   683  		},
   684  	}
   685  	result2 := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   686  		"workflow|source|cell|tablet_types",
   687  		"varchar|varchar|varchar|varchar"),
   688  		fmt.Sprintf("t1|%v|cell1|primary,replica", bls1),
   689  		fmt.Sprintf("t1|%v|cell1|primary,replica", bls2),
   690  	)
   691  	env.tmc.expectVRQuery(110, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result2)
   692  
   693  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   694  	want := "buildResharder: readRefStreams: streams are mismatched across source shards"
   695  	if err == nil || !strings.HasPrefix(err.Error(), want) {
   696  		t.Errorf("Reshard err: %v, want %v", err, want)
   697  	}
   698  	env.tmc.verifyQueries(t)
   699  }
   700  
   701  func TestResharderTableNotInVSchema(t *testing.T) {
   702  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   703  	defer env.close()
   704  
   705  	schm := &tabletmanagerdatapb.SchemaDefinition{
   706  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   707  			Name:              "t1",
   708  			Columns:           []string{"c1", "c2"},
   709  			PrimaryKeyColumns: []string{"c1"},
   710  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   711  		}},
   712  	}
   713  	env.tmc.schema = schm
   714  
   715  	env.expectValidation()
   716  
   717  	bls := &binlogdatapb.BinlogSource{
   718  		Keyspace: "ks1",
   719  		Shard:    "0",
   720  		Filter: &binlogdatapb.Filter{
   721  			Rules: []*binlogdatapb.Rule{{
   722  				Match: "t1",
   723  			}},
   724  		},
   725  	}
   726  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   727  		"workflow|source|cell|tablet_types",
   728  		"varchar|varchar|varchar|varchar"),
   729  		fmt.Sprintf("t1|%v|cell1|primary,replica", bls),
   730  	)
   731  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result)
   732  
   733  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   734  	assert.EqualError(t, err, "buildResharder: readRefStreams: blsIsReference: table t1 not found in vschema")
   735  	env.tmc.verifyQueries(t)
   736  }
   737  
   738  func TestResharderMixedTablesOrder1(t *testing.T) {
   739  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   740  	defer env.close()
   741  
   742  	schm := &tabletmanagerdatapb.SchemaDefinition{
   743  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   744  			Name:              "t1",
   745  			Columns:           []string{"c1", "c2"},
   746  			PrimaryKeyColumns: []string{"c1"},
   747  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   748  		}},
   749  	}
   750  	env.tmc.schema = schm
   751  
   752  	vs := &vschemapb.Keyspace{
   753  		Sharded: true,
   754  		Vindexes: map[string]*vschemapb.Vindex{
   755  			"hash": {
   756  				Type: "hash",
   757  			},
   758  		},
   759  		Tables: map[string]*vschemapb.Table{
   760  			"t1": {
   761  				ColumnVindexes: []*vschemapb.ColumnVindex{{
   762  					Column: "c1",
   763  					Name:   "hash",
   764  				}},
   765  			},
   766  			"t2": {
   767  				Type: vindexes.TypeReference,
   768  			},
   769  		},
   770  	}
   771  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   772  		t.Fatal(err)
   773  	}
   774  
   775  	env.expectValidation()
   776  
   777  	bls := &binlogdatapb.BinlogSource{
   778  		Keyspace: "ks1",
   779  		Shard:    "0",
   780  		Filter: &binlogdatapb.Filter{
   781  			Rules: []*binlogdatapb.Rule{{
   782  				Match:  "t1",
   783  				Filter: "select * from t2",
   784  			}, {
   785  				Match:  "t2",
   786  				Filter: "select * from t2",
   787  			}},
   788  		},
   789  	}
   790  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   791  		"workflow|source|cell|tablet_types",
   792  		"varchar|varchar|varchar|varchar"),
   793  		fmt.Sprintf("t1t2|%v|cell1|primary,replica", bls),
   794  	)
   795  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result)
   796  
   797  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   798  	want := "buildResharder: readRefStreams: blsIsReference: cannot reshard streams with a mix of reference and sharded tables"
   799  	if err == nil || !strings.HasPrefix(err.Error(), want) {
   800  		t.Errorf("Reshard err: %v, want %v", err.Error(), want)
   801  	}
   802  	env.tmc.verifyQueries(t)
   803  }
   804  
   805  func TestResharderMixedTablesOrder2(t *testing.T) {
   806  	env := newTestResharderEnv(t, []string{"0"}, []string{"-80", "80-"})
   807  	defer env.close()
   808  
   809  	schm := &tabletmanagerdatapb.SchemaDefinition{
   810  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{
   811  			Name:              "t1",
   812  			Columns:           []string{"c1", "c2"},
   813  			PrimaryKeyColumns: []string{"c1"},
   814  			Fields:            sqltypes.MakeTestFields("c1|c2", "int64|int64"),
   815  		}},
   816  	}
   817  	env.tmc.schema = schm
   818  
   819  	vs := &vschemapb.Keyspace{
   820  		Sharded: true,
   821  		Vindexes: map[string]*vschemapb.Vindex{
   822  			"hash": {
   823  				Type: "hash",
   824  			},
   825  		},
   826  		Tables: map[string]*vschemapb.Table{
   827  			"t1": {
   828  				ColumnVindexes: []*vschemapb.ColumnVindex{{
   829  					Column: "c1",
   830  					Name:   "hash",
   831  				}},
   832  			},
   833  			"t2": {
   834  				Type: vindexes.TypeReference,
   835  			},
   836  		},
   837  	}
   838  	if err := env.wr.ts.SaveVSchema(context.Background(), env.keyspace, vs); err != nil {
   839  		t.Fatal(err)
   840  	}
   841  
   842  	env.expectValidation()
   843  
   844  	bls := &binlogdatapb.BinlogSource{
   845  		Keyspace: "ks1",
   846  		Shard:    "0",
   847  		Filter: &binlogdatapb.Filter{
   848  			Rules: []*binlogdatapb.Rule{{
   849  				Match:  "t2",
   850  				Filter: "select * from t2",
   851  			}, {
   852  				Match:  "t1",
   853  				Filter: "select * from t2",
   854  			}},
   855  		},
   856  	}
   857  	result := sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   858  		"workflow|source|cell|tablet_types",
   859  		"varchar|varchar|varchar|varchar"),
   860  		fmt.Sprintf("t1t2|%v|cell1|primary,replica", bls),
   861  	)
   862  	env.tmc.expectVRQuery(100, fmt.Sprintf("select workflow, source, cell, tablet_types from _vt.vreplication where db_name='vt_%s' and message != 'FROZEN'", env.keyspace), result)
   863  
   864  	err := env.wr.Reshard(context.Background(), env.keyspace, env.workflow, env.sources, env.targets, true, "", "", defaultOnDDL, true, false, false)
   865  	want := "buildResharder: readRefStreams: blsIsReference: cannot reshard streams with a mix of reference and sharded tables"
   866  	if err == nil || !strings.HasPrefix(err.Error(), want) {
   867  		t.Errorf("Reshard err: %v, want %v", err.Error(), want)
   868  	}
   869  	env.tmc.verifyQueries(t)
   870  }