vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletmanager/vreplication/external_connector_test.go (about) 1 /* 2 Copyright 2020 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 "fmt" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 25 "vitess.io/vitess/go/vt/binlog/binlogplayer" 26 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 27 qh "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication/queryhistory" 28 ) 29 30 func TestExternalConnectorCopy(t *testing.T) { 31 execStatements(t, []string{ 32 "create table tab1(id int, val varbinary(128), primary key(id))", 33 fmt.Sprintf("create table %s.tab1(id int, val varbinary(128), primary key(id))", vrepldb), 34 "insert into tab1 values(1, 'a'), (2, 'b')", 35 36 "create table tab2(id int, val varbinary(128), primary key(id))", 37 fmt.Sprintf("create table %s.tab2(id int, val varbinary(128), primary key(id))", vrepldb), 38 "insert into tab2 values(1, 'a'), (2, 'b')", 39 40 "create table tab3(id int, val varbinary(128), primary key(id))", 41 fmt.Sprintf("create table %s.tab3(id int, val varbinary(128), primary key(id))", vrepldb), 42 "insert into tab3 values(1, 'a'), (2, 'b')", 43 }) 44 defer execStatements(t, []string{ 45 "drop table tab1", 46 fmt.Sprintf("drop table %s.tab1", vrepldb), 47 "drop table tab2", 48 fmt.Sprintf("drop table %s.tab2", vrepldb), 49 "drop table tab3", 50 fmt.Sprintf("drop table %s.tab3", vrepldb), 51 }) 52 53 filter1 := &binlogdatapb.Filter{ 54 Rules: []*binlogdatapb.Rule{{ 55 Match: "tab1", 56 Filter: "", 57 }}, 58 } 59 bls1 := &binlogdatapb.BinlogSource{ 60 ExternalMysql: "exta", 61 Filter: filter1, 62 } 63 cancel1 := startExternalVReplication(t, bls1, "") 64 65 expectDBClientAndVreplicationQueries(t, []string{ 66 "begin", 67 "insert into tab1(id,val) values (1,'a'), (2,'b')", 68 "/insert into _vt.copy_state", 69 "commit", 70 "/delete cs, pca from _vt.copy_state as cs left join _vt.post_copy_action as pca on cs.vrepl_id=pca.vrepl_id and cs.table_name=pca.table_name", 71 "/update _vt.vreplication set state='Running'", 72 }, "") 73 execStatements(t, []string{"insert into tab1 values(3, 'c')"}) 74 expectDBClientQueries(t, qh.Expect( 75 "begin", 76 "insert into tab1(id,val) values (3,'c')", 77 "/update _vt.vreplication set pos=", 78 "commit", 79 )) 80 // Cancel immediately so we don't deal with spurious updates. 81 cancel1() 82 83 // Check that only one connector was created. 84 assert.Equal(t, 1, len(playerEngine.ec.connectors)) 85 filter2 := &binlogdatapb.Filter{ 86 Rules: []*binlogdatapb.Rule{{ 87 Match: "tab2", 88 Filter: "", 89 }}, 90 } 91 bls2 := &binlogdatapb.BinlogSource{ 92 ExternalMysql: "exta", 93 Filter: filter2, 94 } 95 cancel2 := startExternalVReplication(t, bls2, "") 96 97 expectDBClientAndVreplicationQueries(t, []string{ 98 "begin", 99 "insert into tab2(id,val) values (1,'a'), (2,'b')", 100 "/insert into _vt.copy_state", 101 "commit", 102 "/delete cs, pca from _vt.copy_state as cs left join _vt.post_copy_action as pca on cs.vrepl_id=pca.vrepl_id and cs.table_name=pca.table_name", 103 "/update _vt.vreplication set state='Running'", 104 }, "") 105 cancel2() 106 107 // Check that only one connector was created. 108 assert.Equal(t, 1, len(playerEngine.ec.connectors)) 109 110 filter3 := &binlogdatapb.Filter{ 111 Rules: []*binlogdatapb.Rule{{ 112 Match: "tab3", 113 Filter: "", 114 }}, 115 } 116 bls3 := &binlogdatapb.BinlogSource{ 117 ExternalMysql: "extb", 118 Filter: filter3, 119 } 120 cancel3 := startExternalVReplication(t, bls3, "") 121 122 expectDBClientAndVreplicationQueries(t, []string{ 123 "begin", 124 "insert into tab3(id,val) values (1,'a'), (2,'b')", 125 "/insert into _vt.copy_state", 126 "commit", 127 "/delete cs, pca from _vt.copy_state as cs left join _vt.post_copy_action as pca on cs.vrepl_id=pca.vrepl_id and cs.table_name=pca.table_name", 128 "/update _vt.vreplication set state='Running'", 129 }, "") 130 cancel3() 131 132 // Check that there now two connectors. 133 assert.Equal(t, 2, len(playerEngine.ec.connectors)) 134 } 135 136 func TestExternalConnectorPlay(t *testing.T) { 137 execStatements(t, []string{ 138 "create table tab1(id int, val varbinary(128), primary key(id))", 139 fmt.Sprintf("create table %s.tab1(id int, val varbinary(128), primary key(id))", vrepldb), 140 }) 141 defer execStatements(t, []string{ 142 "drop table tab1", 143 fmt.Sprintf("drop table %s.tab1", vrepldb), 144 }) 145 146 filter1 := &binlogdatapb.Filter{ 147 Rules: []*binlogdatapb.Rule{{ 148 Match: "tab1", 149 Filter: "", 150 }}, 151 } 152 bls1 := &binlogdatapb.BinlogSource{ 153 ExternalMysql: "exta", 154 Filter: filter1, 155 } 156 pos := primaryPosition(t) 157 cancel1 := startExternalVReplication(t, bls1, pos) 158 defer cancel1() 159 160 execStatements(t, []string{ 161 "insert into tab1 values(1, 'a'), (2, 'b')", 162 }) 163 164 expectDBClientAndVreplicationQueries(t, []string{ 165 "begin", 166 "insert into tab1(id,val) values (1,'a')", 167 "insert into tab1(id,val) values (2,'b')", 168 "/update _vt.vreplication set pos=", 169 "commit", 170 }, pos) 171 } 172 173 func expectDBClientAndVreplicationQueries(t *testing.T, queries []string, pos string) { 174 t.Helper() 175 vrepQueries := getExpectedVreplicationQueries(t, pos) 176 expectedQueries := append(vrepQueries, queries...) 177 expectDBClientQueries(t, qh.Expect(expectedQueries[0], expectedQueries[1:]...)) 178 } 179 180 func getExpectedVreplicationQueries(t *testing.T, pos string) []string { 181 if pos == "" { 182 return []string{ 183 "/insert into _vt.vreplication", 184 "begin", 185 "/insert into _vt.copy_state", 186 "/update _vt.vreplication set state='Copying'", 187 "commit", 188 "/update _vt.vreplication set pos=", 189 } 190 } 191 return []string{ 192 "/insert into _vt.vreplication", 193 "/update _vt.vreplication set state='Running'", 194 } 195 } 196 197 func startExternalVReplication(t *testing.T, bls *binlogdatapb.BinlogSource, pos string) (cancelr func()) { 198 query := binlogplayer.CreateVReplication("test", bls, pos, 9223372036854775807, 9223372036854775807, 0, vrepldb, 0, 0, false) 199 qr, err := playerEngine.Exec(query) 200 if err != nil { 201 t.Fatal(err) 202 } 203 return func() { 204 t.Helper() 205 query := fmt.Sprintf("delete from _vt.vreplication where id = %d", qr.InsertID) 206 if _, err := playerEngine.Exec(query); err != nil { 207 t.Fatal(err) 208 } 209 expectDeleteQueries(t) 210 } 211 }