vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletmanager/vreplication/engine_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 vreplication
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  
    31  	"vitess.io/vitess/go/sqltypes"
    32  	"vitess.io/vitess/go/sync2"
    33  	"vitess.io/vitess/go/vt/binlog/binlogplayer"
    34  	"vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon"
    35  )
    36  
    37  func TestEngineOpen(t *testing.T) {
    38  	defer func() { globalStats = &vrStats{} }()
    39  
    40  	defer deleteTablet(addTablet(100))
    41  	resetBinlogClient()
    42  	dbClient := binlogplayer.NewMockDBClient(t)
    43  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
    44  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
    45  
    46  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
    47  	require.False(t, vre.IsOpen())
    48  
    49  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", sqltypes.MakeTestResult(
    50  		sqltypes.MakeTestFields(
    51  			"id|state|source|tablet_types",
    52  			"int64|varchar|varchar|varbinary",
    53  		),
    54  		fmt.Sprintf(`1|Running|keyspace:"%s" shard:"0" key_range:{end:"\x80"}|PRIMARY,REPLICA`, env.KeyspaceName),
    55  	), nil)
    56  	dbClient.ExpectRequestRE("update _vt.vreplication set message='Picked source tablet.*", testDMLResponse, nil)
    57  	dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil)
    58  	dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag, state, workflow_type, workflow, workflow_sub_type, defer_secondary_keys from _vt.vreplication where id=1", testSettingsResponse, nil)
    59  	dbClient.ExpectRequest("begin", nil, nil)
    60  	dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil)
    61  	dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil)
    62  	dbClient.ExpectRequest("commit", nil, nil)
    63  	vre.Open(context.Background())
    64  	defer vre.Close()
    65  	assert.True(t, vre.IsOpen())
    66  
    67  	// Verify stats
    68  	assert.Equal(t, globalStats.controllers, vre.controllers)
    69  
    70  	ct := vre.controllers[1]
    71  	assert.True(t, ct != nil && ct.id == 1)
    72  }
    73  
    74  func TestEngineOpenRetry(t *testing.T) {
    75  	defer func() { globalStats = &vrStats{} }()
    76  
    77  	defer func(saved time.Duration) { openRetryInterval.Set(saved) }(openRetryInterval.Get())
    78  	openRetryInterval.Set(10 * time.Millisecond)
    79  
    80  	defer deleteTablet(addTablet(100))
    81  	resetBinlogClient()
    82  	dbClient := binlogplayer.NewMockDBClient(t)
    83  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
    84  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
    85  
    86  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
    87  
    88  	// Fail twice to ensure the retry retries at least once.
    89  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", nil, errors.New("err"))
    90  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", nil, errors.New("err"))
    91  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", sqltypes.MakeTestResult(
    92  		sqltypes.MakeTestFields(
    93  			"id|state|source",
    94  			"int64|varchar|varchar",
    95  		),
    96  	), nil)
    97  
    98  	isRetrying := func() bool {
    99  		vre.mu.Lock()
   100  		defer vre.mu.Unlock()
   101  		return vre.cancelRetry != nil
   102  	}
   103  
   104  	vre.Open(context.Background())
   105  
   106  	assert.True(t, isRetrying())
   107  	func() {
   108  		for i := 0; i < 10; i++ {
   109  			time.Sleep(10 * time.Millisecond)
   110  			if !isRetrying() {
   111  				return
   112  			}
   113  		}
   114  		t.Error("retrying did not become false")
   115  	}()
   116  
   117  	// Open is idempotent.
   118  	assert.True(t, vre.IsOpen())
   119  	vre.Open(context.Background())
   120  
   121  	vre.Close()
   122  	assert.False(t, vre.IsOpen())
   123  
   124  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", nil, errors.New("err"))
   125  	vre.Open(context.Background())
   126  
   127  	// A second Open should cancel the existing retry and start a new one.
   128  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", nil, errors.New("err"))
   129  	vre.Open(context.Background())
   130  
   131  	start := time.Now()
   132  	// Close should cause the retry to exit.
   133  	vre.Close()
   134  	elapsed := time.Since(start)
   135  	assert.Greater(t, int64(openRetryInterval.Get()), int64(elapsed))
   136  }
   137  
   138  func TestEngineExec(t *testing.T) {
   139  	defer func() { globalStats = &vrStats{} }()
   140  
   141  	defer deleteTablet(addTablet(100))
   142  	resetBinlogClient()
   143  	dbClient := binlogplayer.NewMockDBClient(t)
   144  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
   145  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   146  
   147  	// Test Insert
   148  
   149  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
   150  
   151  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", &sqltypes.Result{}, nil)
   152  	vre.Open(context.Background())
   153  	defer vre.Close()
   154  
   155  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   156  	dbClient.ExpectRequest("insert into _vt.vreplication values(null)", &sqltypes.Result{InsertID: 1}, nil)
   157  	dbClient.ExpectRequest("select * from _vt.vreplication where id = 1", sqltypes.MakeTestResult(
   158  		sqltypes.MakeTestFields(
   159  			"id|state|source|tablet_types",
   160  			"int64|varchar|varchar|varbinary",
   161  		),
   162  		fmt.Sprintf(`1|Running|keyspace:"%s" shard:"0" key_range:{end:"\x80"}|PRIMARY,REPLICA`, env.KeyspaceName),
   163  	), nil)
   164  	dbClient.ExpectRequestRE("update _vt.vreplication set message='Picked source tablet.*", testDMLResponse, nil)
   165  	dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil)
   166  	dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag, state, workflow_type, workflow, workflow_sub_type, defer_secondary_keys from _vt.vreplication where id=1", testSettingsResponse, nil)
   167  	dbClient.ExpectRequest("begin", nil, nil)
   168  	dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil)
   169  	dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil)
   170  	dbClient.ExpectRequest("commit", nil, nil)
   171  
   172  	qr, err := vre.Exec("insert into _vt.vreplication values(null)")
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	wantqr := &sqltypes.Result{InsertID: 1}
   177  	if !qr.Equal(wantqr) {
   178  		t.Errorf("Exec: %v, want %v", qr, wantqr)
   179  	}
   180  	dbClient.Wait()
   181  
   182  	ct := vre.controllers[1]
   183  	if ct == nil || ct.id != 1 {
   184  		t.Errorf("ct: %v, id should be 1", ct)
   185  	}
   186  
   187  	// Verify stats
   188  	if !reflect.DeepEqual(globalStats.controllers, vre.controllers) {
   189  		t.Errorf("stats are mismatched: %v, want %v", globalStats.controllers, vre.controllers)
   190  	}
   191  
   192  	// Test Update
   193  
   194  	savedBlp := ct.blpStats
   195  
   196  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   197  	dbClient.ExpectRequest("select id from _vt.vreplication where id = 1", testSelectorResponse1, nil)
   198  	dbClient.ExpectRequest("update _vt.vreplication set pos = 'MariaDB/0-1-1084', state = 'Running' where id in (1)", testDMLResponse, nil)
   199  	dbClient.ExpectRequest("select * from _vt.vreplication where id = 1", sqltypes.MakeTestResult(
   200  		sqltypes.MakeTestFields(
   201  			"id|state|source",
   202  			"int64|varchar|varchar",
   203  		),
   204  		fmt.Sprintf(`1|Running|keyspace:"%s" shard:"0" key_range:{end:"\x80"}`, env.KeyspaceName),
   205  	), nil)
   206  	dbClient.ExpectRequestRE("update _vt.vreplication set message='Picked source tablet.*", testDMLResponse, nil)
   207  	dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil)
   208  	dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag, state, workflow_type, workflow, workflow_sub_type, defer_secondary_keys from _vt.vreplication where id=1", testSettingsResponse, nil)
   209  	dbClient.ExpectRequest("begin", nil, nil)
   210  	dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil)
   211  	dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil)
   212  	dbClient.ExpectRequest("commit", nil, nil)
   213  
   214  	qr, err = vre.Exec("update _vt.vreplication set pos = 'MariaDB/0-1-1084', state = 'Running' where id = 1")
   215  	if err != nil {
   216  		t.Fatal(err)
   217  	}
   218  	wantqr = &sqltypes.Result{RowsAffected: 1}
   219  	if !qr.Equal(wantqr) {
   220  		t.Errorf("Exec: %v, want %v", qr, wantqr)
   221  	}
   222  	dbClient.Wait()
   223  
   224  	ct = vre.controllers[1]
   225  
   226  	// Verify that the new controller has reused the previous blpStats.
   227  	if ct.blpStats != savedBlp {
   228  		t.Errorf("BlpStats: %v and %v, must be same", ct.blpStats, savedBlp)
   229  	}
   230  
   231  	// Verify stats
   232  	if !reflect.DeepEqual(globalStats.controllers, vre.controllers) {
   233  		t.Errorf("stats are mismatched: %v, want %v", globalStats.controllers, vre.controllers)
   234  	}
   235  
   236  	// Test no update
   237  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   238  	dbClient.ExpectRequest("select id from _vt.vreplication where id = 2", &sqltypes.Result{}, nil)
   239  	_, err = vre.Exec("update _vt.vreplication set pos = 'MariaDB/0-1-1084', state = 'Running' where id = 2")
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	dbClient.Wait()
   244  
   245  	// Test Delete
   246  
   247  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   248  	dbClient.ExpectRequest("select id from _vt.vreplication where id = 1", testSelectorResponse1, nil)
   249  	dbClient.ExpectRequest("begin", nil, nil)
   250  	dbClient.ExpectRequest("delete from _vt.vreplication where id in (1)", testDMLResponse, nil)
   251  	dbClient.ExpectRequest("delete from _vt.copy_state where vrepl_id in (1)", nil, nil)
   252  	dbClient.ExpectRequest("delete from _vt.post_copy_action where vrepl_id in (1)", nil, nil)
   253  	dbClient.ExpectRequest("commit", nil, nil)
   254  
   255  	qr, err = vre.Exec("delete from _vt.vreplication where id = 1")
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	wantqr = &sqltypes.Result{RowsAffected: 1}
   260  	if !qr.Equal(wantqr) {
   261  		t.Errorf("Exec: %v, want %v", qr, wantqr)
   262  	}
   263  	dbClient.Wait()
   264  
   265  	ct = vre.controllers[1]
   266  	if ct != nil {
   267  		t.Errorf("ct: %v, want nil", ct)
   268  	}
   269  
   270  	// Verify stats
   271  	if !reflect.DeepEqual(globalStats.controllers, vre.controllers) {
   272  		t.Errorf("stats are mismatched: %v, want %v", globalStats.controllers, vre.controllers)
   273  	}
   274  
   275  	// Test Delete of multiple rows
   276  
   277  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   278  	dbClient.ExpectRequest("select id from _vt.vreplication where id > 1", testSelectorResponse2, nil)
   279  	dbClient.ExpectRequest("begin", nil, nil)
   280  	dbClient.ExpectRequest("delete from _vt.vreplication where id in (1, 2)", testDMLResponse, nil)
   281  	dbClient.ExpectRequest("delete from _vt.copy_state where vrepl_id in (1, 2)", nil, nil)
   282  	dbClient.ExpectRequest("delete from _vt.post_copy_action where vrepl_id in (1, 2)", nil, nil)
   283  	dbClient.ExpectRequest("commit", nil, nil)
   284  
   285  	_, err = vre.Exec("delete from _vt.vreplication where id > 1")
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  	dbClient.Wait()
   290  
   291  	// Test no delete
   292  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   293  	dbClient.ExpectRequest("select id from _vt.vreplication where id = 3", &sqltypes.Result{}, nil)
   294  	_, err = vre.Exec("delete from _vt.vreplication where id = 3")
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  	dbClient.Wait()
   299  }
   300  
   301  func TestEngineBadInsert(t *testing.T) {
   302  	defer func() { globalStats = &vrStats{} }()
   303  
   304  	defer deleteTablet(addTablet(100))
   305  	resetBinlogClient()
   306  
   307  	dbClient := binlogplayer.NewMockDBClient(t)
   308  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
   309  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   310  
   311  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
   312  
   313  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", &sqltypes.Result{}, nil)
   314  	vre.Open(context.Background())
   315  	defer vre.Close()
   316  
   317  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   318  	dbClient.ExpectRequest("insert into _vt.vreplication values(null)", &sqltypes.Result{}, nil)
   319  	_, err := vre.Exec("insert into _vt.vreplication values(null)")
   320  	want := "insert failed to generate an id"
   321  	if err == nil || err.Error() != want {
   322  		t.Errorf("vre.Exec err: %v, want %v", err, want)
   323  	}
   324  
   325  	// Verify stats
   326  	if !reflect.DeepEqual(globalStats.controllers, vre.controllers) {
   327  		t.Errorf("stats are mismatched: %v, want %v", globalStats.controllers, vre.controllers)
   328  	}
   329  }
   330  
   331  func TestEngineSelect(t *testing.T) {
   332  	defer deleteTablet(addTablet(100))
   333  	resetBinlogClient()
   334  	dbClient := binlogplayer.NewMockDBClient(t)
   335  
   336  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
   337  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   338  
   339  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
   340  
   341  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", &sqltypes.Result{}, nil)
   342  	vre.Open(context.Background())
   343  	defer vre.Close()
   344  
   345  	dbClient.ExpectRequest("use _vt", &sqltypes.Result{}, nil)
   346  	wantQuery := "select * from _vt.vreplication where workflow = 'x'"
   347  	wantResult := sqltypes.MakeTestResult(
   348  		sqltypes.MakeTestFields(
   349  			"id|state|source|pos",
   350  			"int64|varchar|varchar|varchar",
   351  		),
   352  		fmt.Sprintf(`1|Running|keyspace:"%s" shard:"0" key_range:{end:"\x80"}|MariaDB/0-1-1083`, env.KeyspaceName),
   353  	)
   354  	dbClient.ExpectRequest(wantQuery, wantResult, nil)
   355  	qr, err := vre.Exec(wantQuery)
   356  	if err != nil {
   357  		t.Fatal(err)
   358  	}
   359  	if !qr.Equal(wantResult) {
   360  		t.Errorf("Exec: %v, want %v", qr, wantResult)
   361  	}
   362  }
   363  
   364  func TestWaitForPos(t *testing.T) {
   365  	savedRetryTime := waitRetryTime
   366  	defer func() { waitRetryTime = savedRetryTime }()
   367  	waitRetryTime = 10 * time.Millisecond
   368  
   369  	dbClient := binlogplayer.NewMockDBClient(t)
   370  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   371  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
   372  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
   373  
   374  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", &sqltypes.Result{}, nil)
   375  	vre.Open(context.Background())
   376  
   377  	dbClient.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{
   378  		sqltypes.NewVarBinary("MariaDB/0-1-1083"),
   379  		sqltypes.NewVarBinary("Running"),
   380  		sqltypes.NewVarBinary(""),
   381  	}}}, nil)
   382  	dbClient.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{
   383  		sqltypes.NewVarBinary("MariaDB/0-1-1084"),
   384  		sqltypes.NewVarBinary("Running"),
   385  		sqltypes.NewVarBinary(""),
   386  	}}}, nil)
   387  	start := time.Now()
   388  	if err := vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084"); err != nil {
   389  		t.Fatal(err)
   390  	}
   391  	if duration := time.Since(start); duration < 10*time.Microsecond {
   392  		t.Errorf("duration: %v, want < 10ms", duration)
   393  	}
   394  }
   395  
   396  func TestWaitForPosError(t *testing.T) {
   397  	dbClient := binlogplayer.NewMockDBClient(t)
   398  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   399  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
   400  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
   401  
   402  	err := vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084")
   403  	want := `vreplication engine is closed`
   404  	if err == nil || err.Error() != want {
   405  		t.Errorf("WaitForPos: %v, want %v", err, want)
   406  	}
   407  
   408  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", &sqltypes.Result{}, nil)
   409  	vre.Open(context.Background())
   410  
   411  	err = vre.WaitForPos(context.Background(), 1, "BadFlavor/0-1-1084")
   412  	want = `parse error: unknown GTIDSet flavor "BadFlavor"`
   413  	if err == nil || err.Error() != want {
   414  		t.Errorf("WaitForPos: %v, want %v", err, want)
   415  	}
   416  
   417  	dbClient.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{}}}, nil)
   418  	err = vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084")
   419  	want = "unexpected result: &{[] 0 0 [[]]  0 }"
   420  	assert.EqualError(t, err, want, "WaitForPos:")
   421  
   422  	dbClient.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{
   423  		sqltypes.NewVarBinary("MariaDB/0-1-1083"),
   424  	}, {
   425  		sqltypes.NewVarBinary("MariaDB/0-1-1083"),
   426  	}}}, nil)
   427  	err = vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084")
   428  	want = `unexpected result: &{[] 0 0 [[VARBINARY("MariaDB/0-1-1083")] [VARBINARY("MariaDB/0-1-1083")]]  0 }`
   429  	assert.EqualError(t, err, want, "WaitForPos:")
   430  }
   431  
   432  func TestWaitForPosCancel(t *testing.T) {
   433  	dbClient := binlogplayer.NewMockDBClient(t)
   434  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   435  	dbClientFactory := func() binlogplayer.DBClient { return dbClient }
   436  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactory, dbClientFactory, dbClient.DBName(), nil)
   437  
   438  	dbClient.ExpectRequest("select * from _vt.vreplication where db_name='db'", &sqltypes.Result{}, nil)
   439  	vre.Open(context.Background())
   440  
   441  	dbClient.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{
   442  		sqltypes.NewVarBinary("MariaDB/0-1-1083"),
   443  		sqltypes.NewVarBinary("Running"),
   444  		sqltypes.NewVarBinary(""),
   445  	}}}, nil)
   446  	ctx, cancel := context.WithCancel(context.Background())
   447  	cancel()
   448  	err := vre.WaitForPos(ctx, 1, "MariaDB/0-1-1084")
   449  	want := "error waiting for pos: MariaDB/0-1-1084, last pos: MariaDB/0-1-1083: context canceled"
   450  	if err == nil || !strings.Contains(err.Error(), want) {
   451  		t.Errorf("WaitForPos: %v, must contain %v", err, want)
   452  	}
   453  	dbClient.Wait()
   454  
   455  	go func() {
   456  		time.Sleep(5 * time.Millisecond)
   457  		vre.Close()
   458  	}()
   459  	dbClient.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{
   460  		sqltypes.NewVarBinary("MariaDB/0-1-1083"),
   461  		sqltypes.NewVarBinary("Running"),
   462  		sqltypes.NewVarBinary(""),
   463  	}}}, nil)
   464  	err = vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084")
   465  	want = "vreplication is closing: context canceled"
   466  	if err == nil || err.Error() != want {
   467  		t.Errorf("WaitForPos: %v, want %v", err, want)
   468  	}
   469  }
   470  
   471  func TestGetDBClient(t *testing.T) {
   472  	dbClientDba := binlogplayer.NewMockDbaClient(t)
   473  	dbClientFiltered := binlogplayer.NewMockDBClient(t)
   474  	dbClientFactoryDba := func() binlogplayer.DBClient { return dbClientDba }
   475  	dbClientFactoryFiltered := func() binlogplayer.DBClient { return dbClientFiltered }
   476  
   477  	mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: sync2.NewAtomicInt32(3306)}
   478  	vre := NewTestEngine(env.TopoServ, env.Cells[0], mysqld, dbClientFactoryFiltered, dbClientFactoryDba, dbClientDba.DBName(), nil)
   479  
   480  	shouldBeDbaClient := vre.getDBClient(true /*runAsAdmin*/)
   481  	assert.Equal(t, shouldBeDbaClient, dbClientDba)
   482  
   483  	shouldBeFilteredClient := vre.getDBClient(false /*runAsAdmin*/)
   484  	assert.Equal(t, shouldBeFilteredClient, dbClientFiltered)
   485  }