vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletmanager/vreplication/controller_plan_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 "reflect" 21 "testing" 22 23 "github.com/stretchr/testify/require" 24 ) 25 26 type testControllerPlan struct { 27 query string 28 opcode int 29 numInserts int 30 selector string 31 applier string 32 delCopyState string 33 delPostCopyAction string 34 } 35 36 func TestControllerPlan(t *testing.T) { 37 tcases := []struct { 38 in string 39 plan *testControllerPlan 40 err string 41 }{{ 42 // Insert 43 in: "insert into _vt.vreplication values(null)", 44 plan: &testControllerPlan{ 45 query: "insert into _vt.vreplication values(null)", 46 opcode: insertQuery, 47 numInserts: 1, 48 }, 49 }, { 50 in: "insert into _vt.vreplication(id) values(null)", 51 plan: &testControllerPlan{ 52 query: "insert into _vt.vreplication(id) values(null)", 53 opcode: insertQuery, 54 numInserts: 1, 55 }, 56 }, { 57 in: "insert into _vt.vreplication(workflow, id) values('', null)", 58 plan: &testControllerPlan{ 59 query: "insert into _vt.vreplication(workflow, id) values('', null)", 60 opcode: insertQuery, 61 numInserts: 1, 62 }, 63 }, { 64 in: "insert into _vt.vreplication values(null), (null)", 65 plan: &testControllerPlan{ 66 query: "insert into _vt.vreplication values(null), (null)", 67 opcode: insertQuery, 68 numInserts: 2, 69 }, 70 }, { 71 in: "insert into _vt.resharding_journal values (1)", 72 plan: &testControllerPlan{ 73 query: "insert into _vt.resharding_journal values (1)", 74 opcode: reshardingJournalQuery, 75 }, 76 }, { 77 in: "replace into _vt.vreplication values(null)", 78 err: "unsupported construct: replace into _vt.vreplication values (null)", 79 }, { 80 in: "insert ignore into _vt.vreplication values(null)", 81 err: "unsupported construct: insert ignore into _vt.vreplication values (null)", 82 }, { 83 in: "insert into other values(null)", 84 err: "invalid table name: other", 85 }, { 86 in: "insert into _vt.vreplication partition(a) values(null)", 87 err: "unsupported construct: insert into _vt.vreplication partition (a) values (null)", 88 }, { 89 in: "insert into _vt.vreplication values(null) on duplicate key update id=3", 90 err: "unsupported construct: insert into _vt.vreplication values (null) on duplicate key update id = 3", 91 }, { 92 in: "insert into _vt.vreplication select * from a", 93 err: "unsupported construct: insert into _vt.vreplication select * from a", 94 }, { 95 in: "insert into _vt.vreplication(a, b, id) values(null)", 96 err: "malformed statement: insert into _vt.vreplication(a, b, id) values (null)", 97 }, { 98 in: "insert into _vt.vreplication(workflow, id) values('aa', 1)", 99 err: "id should not have a value: insert into _vt.vreplication(workflow, id) values ('aa', 1)", 100 }, { 101 in: "insert into _vt.vreplication values(1)", 102 err: "id should not have a value: insert into _vt.vreplication values (1)", 103 104 // Update 105 }, { 106 in: "update _vt.vreplication set state='Running' where id = 1", 107 plan: &testControllerPlan{ 108 query: "update _vt.vreplication set state='Running' where id = 1", 109 opcode: updateQuery, 110 selector: "select id from _vt.vreplication where id = 1", 111 applier: "update _vt.vreplication set state = 'Running' where id in ::ids", 112 }, 113 }, { 114 in: "update _vt.vreplication set state='Running'", 115 plan: &testControllerPlan{ 116 query: "update _vt.vreplication set state='Running'", 117 opcode: updateQuery, 118 selector: "select id from _vt.vreplication", 119 applier: "update _vt.vreplication set state = 'Running' where id in ::ids", 120 }, 121 }, { 122 in: "update _vt.vreplication set state='Running' where a = 1", 123 plan: &testControllerPlan{ 124 query: "update _vt.vreplication set state='Running' where a = 1", 125 opcode: updateQuery, 126 selector: "select id from _vt.vreplication where a = 1", 127 applier: "update _vt.vreplication set state = 'Running' where id in ::ids", 128 }, 129 }, { 130 in: "update _vt.resharding_journal set col = 1", 131 plan: &testControllerPlan{ 132 query: "update _vt.resharding_journal set col = 1", 133 opcode: reshardingJournalQuery, 134 }, 135 }, { 136 in: "update a set state='Running' where id = 1", 137 err: "invalid table name: a", 138 }, { 139 in: "update _vt.vreplication set state='Running' where id = 1 order by id", 140 err: "unsupported construct: update _vt.vreplication set state = 'Running' where id = 1 order by id asc", 141 }, { 142 in: "update _vt.vreplication set state='Running' where id = 1 limit 1", 143 err: "unsupported construct: update _vt.vreplication set state = 'Running' where id = 1 limit 1", 144 }, { 145 in: "update _vt.vreplication set state='Running', id = 2 where id = 1", 146 err: "id cannot be changed: id = 2", 147 148 // Delete 149 }, { 150 in: "delete from _vt.vreplication where id = 1", 151 plan: &testControllerPlan{ 152 query: "delete from _vt.vreplication where id = 1", 153 opcode: deleteQuery, 154 selector: "select id from _vt.vreplication where id = 1", 155 applier: "delete from _vt.vreplication where id in ::ids", 156 delCopyState: "delete from _vt.copy_state where vrepl_id in ::ids", 157 delPostCopyAction: "delete from _vt.post_copy_action where vrepl_id in ::ids", 158 }, 159 }, { 160 in: "delete from _vt.vreplication", 161 plan: &testControllerPlan{ 162 query: "delete from _vt.vreplication", 163 opcode: deleteQuery, 164 selector: "select id from _vt.vreplication", 165 applier: "delete from _vt.vreplication where id in ::ids", 166 delCopyState: "delete from _vt.copy_state where vrepl_id in ::ids", 167 delPostCopyAction: "delete from _vt.post_copy_action where vrepl_id in ::ids", 168 }, 169 }, { 170 in: "delete from _vt.vreplication where a = 1", 171 plan: &testControllerPlan{ 172 query: "delete from _vt.vreplication where a = 1", 173 opcode: deleteQuery, 174 selector: "select id from _vt.vreplication where a = 1", 175 applier: "delete from _vt.vreplication where id in ::ids", 176 delCopyState: "delete from _vt.copy_state where vrepl_id in ::ids", 177 delPostCopyAction: "delete from _vt.post_copy_action where vrepl_id in ::ids", 178 }, 179 }, { 180 in: "delete from _vt.resharding_journal where id = 1", 181 plan: &testControllerPlan{ 182 query: "delete from _vt.resharding_journal where id = 1", 183 opcode: reshardingJournalQuery, 184 }, 185 }, { 186 in: "delete from a where id = 1", 187 err: "invalid table name: a", 188 }, { 189 in: "delete a, b from _vt.vreplication where id = 1", 190 err: "unsupported construct: delete a, b from _vt.vreplication where id = 1", 191 }, { 192 in: "delete from _vt.vreplication where id = 1 order by id", 193 err: "unsupported construct: delete from _vt.vreplication where id = 1 order by id asc", 194 }, { 195 in: "delete from _vt.vreplication where id = 1 limit 1", 196 err: "unsupported construct: delete from _vt.vreplication where id = 1 limit 1", 197 }, { 198 in: "delete from _vt.vreplication partition (a) where id = 1 limit 1", 199 err: "unsupported construct: delete from _vt.vreplication partition (a) where id = 1 limit 1", 200 201 // Select 202 }, { 203 in: "select * from _vt.vreplication", 204 plan: &testControllerPlan{ 205 opcode: selectQuery, 206 query: "select * from _vt.vreplication", 207 }, 208 }, { 209 in: "select * from _vt.resharding_journal", 210 plan: &testControllerPlan{ 211 opcode: selectQuery, 212 query: "select * from _vt.resharding_journal", 213 }, 214 }, { 215 in: "select * from _vt.copy_state", 216 plan: &testControllerPlan{ 217 opcode: selectQuery, 218 query: "select * from _vt.copy_state", 219 }, 220 }, { 221 in: "select * from a", 222 err: "invalid table name: a", 223 224 // Parser 225 }, { 226 in: "bad query", 227 err: "syntax error at position 4 near 'bad'", 228 }, { 229 in: "set a = 1", 230 err: "unsupported construct: set @@a = 1", 231 }} 232 for _, tcase := range tcases { 233 t.Run(tcase.in, func(t *testing.T) { 234 pl, err := buildControllerPlan(tcase.in) 235 if tcase.err != "" { 236 require.EqualError(t, err, tcase.err) 237 return 238 } 239 require.NoError(t, err) 240 241 gotPlan := &testControllerPlan{ 242 query: pl.query, 243 opcode: pl.opcode, 244 numInserts: pl.numInserts, 245 selector: pl.selector, 246 } 247 if pl.applier != nil { 248 gotPlan.applier = pl.applier.Query 249 } 250 if pl.delCopyState != nil { 251 gotPlan.delCopyState = pl.delCopyState.Query 252 } 253 if pl.delPostCopyAction != nil { 254 gotPlan.delPostCopyAction = pl.delPostCopyAction.Query 255 } 256 if !reflect.DeepEqual(gotPlan, tcase.plan) { 257 t.Errorf("getPlan(%v):\n%+v, want\n%+v", tcase.in, gotPlan, tcase.plan) 258 } 259 }) 260 } 261 }