vitess.io/vitess@v0.16.2/go/mysql/binlog_event_common_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 mysql 18 19 import ( 20 "reflect" 21 "testing" 22 23 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 24 25 "github.com/stretchr/testify/assert" 26 ) 27 28 // sample event data 29 var ( 30 garbageEvent = []byte{92, 93, 211, 208, 16, 71, 139, 255, 83, 199, 198, 59, 148, 214, 109, 154, 122, 226, 39, 41} 31 googleRotateEvent = []byte{0x0, 0x0, 0x0, 0x0, 0x4, 0x88, 0xf3, 0x0, 0x0, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x23, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x76, 0x74, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x32, 0x33, 0x34, 0x34, 0x2d, 0x62, 0x69, 0x6e, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31} 32 googleFormatEvent = []byte{0x52, 0x52, 0xe9, 0x53, 0xf, 0x88, 0xf3, 0x0, 0x0, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x35, 0x2e, 0x31, 0x2e, 0x36, 0x33, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2d, 0x6c, 0x6f, 0x67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x38, 0xd, 0x0, 0x8, 0x0, 0x12, 0x0, 0x4, 0x4, 0x4, 0x4, 0x12, 0x0, 0x0, 0x53, 0x0, 0x4, 0x1a, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x2} 33 googleQueryEvent = []byte{0x53, 0x52, 0xe9, 0x53, 0x2, 0x88, 0xf3, 0x0, 0x0, 0xad, 0x0, 0x0, 0x0, 0x9a, 0x4, 0x0, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x1, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x3, 0x73, 0x74, 0x64, 0x4, 0x8, 0x0, 0x8, 0x0, 0x21, 0x0, 0x76, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, 0x76, 0x74, 0x5f, 0x61, 0x20, 0x28, 0xa, 0x65, 0x69, 0x64, 0x20, 0x62, 0x69, 0x67, 0x69, 0x6e, 0x74, 0x2c, 0xa, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x2c, 0xa, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x28, 0x65, 0x69, 0x64, 0x2c, 0x20, 0x69, 0x64, 0x29, 0xa, 0x29, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x3d, 0x49, 0x6e, 0x6e, 0x6f, 0x44, 0x42} 34 googleXIDEvent = []byte{0x53, 0x52, 0xe9, 0x53, 0x10, 0x88, 0xf3, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0x4e, 0xa, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} 35 googleIntVarEvent1 = []byte{0xea, 0xa8, 0xea, 0x53, 0x5, 0x88, 0xf3, 0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0xb8, 0x6, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} 36 googleIntVarEvent2 = []byte{0xea, 0xa8, 0xea, 0x53, 0x5, 0x88, 0xf3, 0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0xb8, 0x6, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} 37 googleSemiSyncNoAckQueryEvent = []byte{0xef, 0x00, 0x53, 0x52, 0xe9, 0x53, 0x2, 0x88, 0xf3, 0x0, 0x0, 0xad, 0x0, 0x0, 0x0, 0x9a, 0x4, 0x0, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x1a, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x1, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x3, 0x73, 0x74, 0x64, 0x4, 0x8, 0x0, 0x8, 0x0, 0x21, 0x0, 0x76, 0x74, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x0, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, 0x76, 0x74, 0x5f, 0x61, 0x20, 0x28, 0xa, 0x65, 0x69, 0x64, 0x20, 0x62, 0x69, 0x67, 0x69, 0x6e, 0x74, 0x2c, 0xa, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x2c, 0xa, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x28, 0x65, 0x69, 0x64, 0x2c, 0x20, 0x69, 0x64, 0x29, 0xa, 0x29, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x3d, 0x49, 0x6e, 0x6e, 0x6f, 0x44, 0x42} 38 googleSemiSyncAckXIDEvent = []byte{0xef, 0x01, 0x53, 0x52, 0xe9, 0x53, 0x10, 0x88, 0xf3, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0x4e, 0xa, 0x0, 0x0, 0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} 39 ) 40 41 func TestBinlogEventEmptyBuf(t *testing.T) { 42 input := binlogEvent([]byte{}) 43 want := false 44 if got := input.IsValid(); got != want { 45 t.Errorf("%#v.IsValid() = %v, want %v", input, got, want) 46 } 47 } 48 49 func TestBinlogEventGarbage(t *testing.T) { 50 input := binlogEvent(garbageEvent) 51 want := false 52 if got := input.IsValid(); got != want { 53 t.Errorf("%#v.IsValid() = %v, want %v", input, got, want) 54 } 55 } 56 57 func TestBinlogEventIsValid(t *testing.T) { 58 input := binlogEvent(googleRotateEvent) 59 want := true 60 if got := input.IsValid(); got != want { 61 t.Errorf("%#v.IsValid() = %v, want %v", input, got, want) 62 } 63 } 64 65 func TestBinlogEventTruncatedHeader(t *testing.T) { 66 input := binlogEvent(googleRotateEvent[:18]) 67 want := false 68 if got := input.IsValid(); got != want { 69 t.Errorf("%#v.IsValid() = %v, want %v", input, got, want) 70 } 71 } 72 73 func TestBinlogEventTruncatedData(t *testing.T) { 74 input := binlogEvent(googleRotateEvent[:len(googleRotateEvent)-1]) 75 want := false 76 if got := input.IsValid(); got != want { 77 t.Errorf("%#v.IsValid() = %v, want %v", input, got, want) 78 } 79 } 80 81 func TestBinlogEventType(t *testing.T) { 82 input := binlogEvent(googleRotateEvent) 83 want := byte(0x04) 84 if got := input.Type(); got != want { 85 t.Errorf("%#v.Type() = %v, want %v", input, got, want) 86 } 87 } 88 89 func TestBinlogEventFlags(t *testing.T) { 90 input := binlogEvent(googleRotateEvent) 91 want := uint16(0x20) 92 if got := input.Flags(); got != want { 93 t.Errorf("%#v.Flags() = %v, want %v", input, got, want) 94 } 95 } 96 97 func TestBinlogEventTimestamp(t *testing.T) { 98 input := binlogEvent(googleFormatEvent) 99 want := uint32(0x53e95252) 100 if got := input.Timestamp(); got != want { 101 t.Errorf("%#v.Timestamp() = %v, want %v", input, got, want) 102 } 103 } 104 105 func TestBinlogEventServerID(t *testing.T) { 106 input := binlogEvent(googleFormatEvent) 107 want := uint32(62344) 108 if got := input.ServerID(); got != want { 109 t.Errorf("%#v.ServerID() = %v, want %v", input, got, want) 110 } 111 } 112 113 func TestBinlogEventIsFormatDescription(t *testing.T) { 114 input := binlogEvent(googleFormatEvent) 115 want := true 116 if got := input.IsFormatDescription(); got != want { 117 t.Errorf("%#v.IsFormatDescription() = %v, want %v", input, got, want) 118 } 119 } 120 121 func TestBinlogEventIsNotFormatDescription(t *testing.T) { 122 input := binlogEvent(googleRotateEvent) 123 want := false 124 if got := input.IsFormatDescription(); got != want { 125 t.Errorf("%#v.IsFormatDescription() = %v, want %v", input, got, want) 126 } 127 } 128 129 func TestBinlogEventIsQuery(t *testing.T) { 130 input := binlogEvent(googleQueryEvent) 131 want := true 132 if got := input.IsQuery(); got != want { 133 t.Errorf("%#v.IsQuery() = %v, want %v", input, got, want) 134 } 135 } 136 137 func TestBinlogEventIsNotQuery(t *testing.T) { 138 input := binlogEvent(googleFormatEvent) 139 want := false 140 if got := input.IsQuery(); got != want { 141 t.Errorf("%#v.IsQuery() = %v, want %v", input, got, want) 142 } 143 } 144 145 func TestBinlogEventIsIntVar(t *testing.T) { 146 input := binlogEvent(googleIntVarEvent1) 147 want := true 148 if got := input.IsIntVar(); got != want { 149 t.Errorf("%#v.IsIntVar() = %v, want %v", input, got, want) 150 } 151 } 152 153 func TestBinlogEventIsNotIntVar(t *testing.T) { 154 input := binlogEvent(googleFormatEvent) 155 want := false 156 if got := input.IsIntVar(); got != want { 157 t.Errorf("%#v.IsIntVar() = %v, want %v", input, got, want) 158 } 159 } 160 161 func TestBinlogEventIsRotate(t *testing.T) { 162 input := binlogEvent(googleRotateEvent) 163 want := true 164 if got := input.IsRotate(); got != want { 165 t.Errorf("%#v.IsRotate() = %v, want %v", input, got, want) 166 } 167 } 168 169 func TestBinlogEventIsNotRotate(t *testing.T) { 170 input := binlogEvent(googleFormatEvent) 171 want := false 172 if got := input.IsRotate(); got != want { 173 t.Errorf("%#v.IsRotate() = %v, want %v", input, got, want) 174 } 175 } 176 177 func TestBinlogEventIsNotHeartbeat(t *testing.T) { 178 input := binlogEvent(googleFormatEvent) 179 assert.False(t, input.IsHeartbeat()) 180 } 181 182 func TestBinlogEventIsXID(t *testing.T) { 183 input := binlogEvent(googleXIDEvent) 184 want := true 185 if got := input.IsXID(); got != want { 186 t.Errorf("%#v.IsXID() = %v, want %v", input, got, want) 187 } 188 } 189 190 func TestBinlogEventIsNotXID(t *testing.T) { 191 input := binlogEvent(googleFormatEvent) 192 want := false 193 if got := input.IsXID(); got != want { 194 t.Errorf("%#v.IsXID() = %v, want %v", input, got, want) 195 } 196 } 197 198 func TestBinlogEventFormat(t *testing.T) { 199 input := binlogEvent(googleFormatEvent) 200 want := BinlogFormat{ 201 FormatVersion: 4, 202 ServerVersion: "5.1.63-google-log", 203 HeaderLength: 27, 204 HeaderSizes: googleFormatEvent[76 : len(googleFormatEvent)-5], 205 } 206 got, err := input.Format() 207 assert.NoError(t, err, "unexpected error: %v", err) 208 assert.True(t, reflect.DeepEqual(got, want), "%#v.Format() = %v, want %v", input, got, want) 209 assert.False(t, input.IsHeartbeat()) 210 211 } 212 213 func TestBinlogEventFormatWrongVersion(t *testing.T) { 214 buf := make([]byte, len(googleFormatEvent)) 215 copy(buf, googleFormatEvent) 216 buf[19] = 5 // mess up the FormatVersion 217 218 input := binlogEvent(buf) 219 want := "format version = 5, we only support version 4" 220 _, err := input.Format() 221 if err == nil { 222 t.Errorf("expected error, got none") 223 return 224 } 225 if got := err.Error(); got != want { 226 t.Errorf("wrong error, got %#v, want %#v", got, want) 227 } 228 } 229 230 func TestBinlogEventFormatBadHeaderLength(t *testing.T) { 231 buf := make([]byte, len(googleFormatEvent)) 232 copy(buf, googleFormatEvent) 233 buf[19+2+50+4] = 12 // mess up the HeaderLength 234 235 input := binlogEvent(buf) 236 want := "header length = 12, should be >= 19" 237 _, err := input.Format() 238 if err == nil { 239 t.Errorf("expected error, got none") 240 return 241 } 242 if got := err.Error(); got != want { 243 t.Errorf("wrong error, got %#v, want %#v", got, want) 244 } 245 } 246 247 func TestBinlogEventQuery(t *testing.T) { 248 f, err := binlogEvent(googleFormatEvent).Format() 249 if err != nil { 250 t.Errorf("unexpected error: %v", err) 251 return 252 } 253 254 input := binlogEvent(googleQueryEvent) 255 want := Query{ 256 Database: "vt_test_keyspace", 257 Charset: &binlogdatapb.Charset{Client: 8, Conn: 8, Server: 33}, 258 SQL: `create table if not exists vt_a ( 259 eid bigint, 260 id int, 261 primary key(eid, id) 262 ) Engine=InnoDB`, 263 } 264 got, err := input.Query(f) 265 if err != nil { 266 t.Errorf("unexpected error: %v", err) 267 return 268 } 269 assert.True(t, reflect.DeepEqual(got, want), "%#v.Query() = %v, want %v", input, got, want) 270 271 } 272 273 func TestBinlogEventQueryBadLength(t *testing.T) { 274 f, err := binlogEvent(googleFormatEvent).Format() 275 if err != nil { 276 t.Errorf("unexpected error: %v", err) 277 return 278 } 279 280 buf := make([]byte, len(googleQueryEvent)) 281 copy(buf, googleQueryEvent) 282 buf[19+8+4+4] = 200 // mess up the db_name length 283 284 input := binlogEvent(buf) 285 want := "SQL query position overflows buffer (240 > 146)" 286 _, err = input.Query(f) 287 if err == nil { 288 t.Errorf("expected error, got none") 289 return 290 } 291 if got := err.Error(); got != want { 292 t.Errorf("wrong error, got %#v, want %#v", got, want) 293 } 294 } 295 296 func TestBinlogEventIntVar1(t *testing.T) { 297 f, err := binlogEvent(googleFormatEvent).Format() 298 if err != nil { 299 t.Errorf("unexpected error: %v", err) 300 return 301 } 302 303 input := binlogEvent(googleIntVarEvent1) 304 wantType := byte(IntVarLastInsertID) 305 wantValue := uint64(101) 306 gotType, gotValue, err := input.IntVar(f) 307 if err != nil { 308 t.Errorf("unexpected error: %v", err) 309 return 310 } 311 if gotType != wantType || gotValue != wantValue { 312 t.Errorf("%#v.IntVar() = (%#v, %#v), want (%#v, %#v)", input, gotType, gotValue, wantType, wantValue) 313 } 314 } 315 316 func TestBinlogEventIntVar2(t *testing.T) { 317 f, err := binlogEvent(googleFormatEvent).Format() 318 if err != nil { 319 t.Errorf("unexpected error: %v", err) 320 return 321 } 322 323 input := binlogEvent(googleIntVarEvent2) 324 wantType := byte(IntVarInsertID) 325 wantValue := uint64(101) 326 gotType, gotValue, err := input.IntVar(f) 327 if err != nil { 328 t.Errorf("unexpected error: %v", err) 329 return 330 } 331 if gotType != wantType || gotValue != wantValue { 332 t.Errorf("%#v.IntVar() = (%#v, %#v), want (%#v, %#v)", input, gotType, gotValue, wantType, wantValue) 333 } 334 } 335 336 func TestBinlogEventIntVarBadID(t *testing.T) { 337 f, err := binlogEvent(googleFormatEvent).Format() 338 if err != nil { 339 t.Errorf("unexpected error: %v", err) 340 return 341 } 342 343 buf := make([]byte, len(googleIntVarEvent2)) 344 copy(buf, googleIntVarEvent2) 345 buf[19+8] = 3 // mess up the variable ID 346 347 input := binlogEvent(buf) 348 want := "invalid IntVar ID: 3" 349 _, _, err = input.IntVar(f) 350 if err == nil { 351 t.Errorf("expected error, got none") 352 return 353 } 354 if got := err.Error(); got != want { 355 t.Errorf("wrong error, got %#v, want %#v", got, want) 356 } 357 } 358 359 func TestBinlogEventIsSemiSyncNoAckQuery(t *testing.T) { 360 c := Conn{ExpectSemiSyncIndicator: true} 361 buf, semiSyncAckRequested, err := c.AnalyzeSemiSyncAckRequest(googleSemiSyncNoAckQueryEvent) 362 assert.NoError(t, err) 363 input := newFilePosBinlogEventWithSemiSyncInfo(buf, semiSyncAckRequested) 364 365 assert.False(t, input.IsSemiSyncAckRequested()) 366 367 want := true 368 if got := input.IsQuery(); got != want { 369 t.Errorf("%#v.IsQuery() = %v, want %v", input, got, want) 370 } 371 } 372 373 func TestBinlogEventIsNotSemiSyncAckXID(t *testing.T) { 374 { 375 input := newFilePosBinlogEvent(googleXIDEvent) 376 assert.False(t, input.IsSemiSyncAckRequested()) 377 } 378 379 { 380 c := Conn{ExpectSemiSyncIndicator: false} 381 buf, semiSyncAckRequested, err := c.AnalyzeSemiSyncAckRequest(googleXIDEvent) 382 assert.NoError(t, err) 383 input := newFilePosBinlogEventWithSemiSyncInfo(buf, semiSyncAckRequested) 384 assert.False(t, input.IsSemiSyncAckRequested()) 385 } 386 } 387 388 func TestBinlogEventIsSemiSyncAckXID(t *testing.T) { 389 c := Conn{ExpectSemiSyncIndicator: true} 390 buf, semiSyncAckRequested, err := c.AnalyzeSemiSyncAckRequest(googleSemiSyncAckXIDEvent) 391 assert.NoError(t, err) 392 input := newFilePosBinlogEventWithSemiSyncInfo(buf, semiSyncAckRequested) 393 394 assert.True(t, input.IsSemiSyncAckRequested()) 395 396 want := true 397 if got := input.IsXID(); got != want { 398 t.Errorf("%#v.IsXID() = %v, want %v", input, got, want) 399 } 400 }