vitess.io/vitess@v0.16.2/go/mysql/binlog_event_make_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 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 26 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 27 ) 28 29 // TestFormatDescriptionEvent tests both MySQL 5.6 and MariaDB 10.0 30 // FormatDescriptionEvent is working properly. 31 func TestFormatDescriptionEvent(t *testing.T) { 32 // MySQL 5.6 33 f := NewMySQL56BinlogFormat() 34 s := NewFakeBinlogStream() 35 36 event := NewFormatDescriptionEvent(f, s) 37 require.True(t, event.IsValid(), "IsValid() returned false") 38 require.True(t, event.IsFormatDescription(), "IsFormatDescription returned false") 39 40 gotF, err := event.Format() 41 require.NoError(t, err, "Format failed: %v", err) 42 require.True(t, reflect.DeepEqual(gotF, f), "Parsed BinlogFormat doesn't match, got:\n%v\nexpected:\n%v", gotF, f) 43 44 // MariaDB 45 f = NewMariaDBBinlogFormat() 46 s = NewFakeBinlogStream() 47 48 event = NewFormatDescriptionEvent(f, s) 49 require.True(t, event.IsValid(), "IsValid() returned false") 50 require.True(t, event.IsFormatDescription(), "IsFormatDescription returned false") 51 52 gotF, err = event.Format() 53 require.NoError(t, err, "Format failed: %v", err) 54 require.True(t, reflect.DeepEqual(gotF, f), "Parsed BinlogFormat doesn't match, got:\n%v\nexpected:\n%v", gotF, f) 55 56 } 57 58 func TestQueryEvent(t *testing.T) { 59 f := NewMySQL56BinlogFormat() 60 s := NewFakeBinlogStream() 61 62 q := Query{ 63 Database: "my database", 64 SQL: "my query", 65 Charset: &binlogdatapb.Charset{ 66 Client: 0x1234, 67 Conn: 0x5678, 68 Server: 0x9abc, 69 }, 70 } 71 event := NewQueryEvent(f, s, q) 72 require.True(t, event.IsValid(), "NewQueryEvent returned an invalid event") 73 require.True(t, event.IsQuery(), "NewQueryEvent returned a non-query event: %v", event) 74 75 event, _, err := event.StripChecksum(f) 76 require.NoError(t, err, "StripChecksum failed: %v", err) 77 78 gotQ, err := event.Query(f) 79 require.NoError(t, err, "event.Query() failed: %v", err) 80 require.True(t, reflect.DeepEqual(gotQ, q), "event.Query() returned %v was expecting %v", gotQ, q) 81 82 } 83 84 func TestXIDEvent(t *testing.T) { 85 f := NewMySQL56BinlogFormat() 86 s := NewFakeBinlogStream() 87 88 event := NewXIDEvent(f, s) 89 require.True(t, event.IsValid(), "NewXIDEvent().IsValid() is false") 90 require.True(t, event.IsXID(), "NewXIDEvent().IsXID() is false") 91 92 } 93 94 func TestIntVarEvent(t *testing.T) { 95 f := NewMySQL56BinlogFormat() 96 s := NewFakeBinlogStream() 97 98 event := NewIntVarEvent(f, s, IntVarLastInsertID, 0x123456789abcdef0) 99 require.True(t, event.IsValid(), "NewIntVarEvent().IsValid() is false") 100 require.True(t, event.IsIntVar(), "NewIntVarEvent().IsIntVar() is false") 101 102 name, value, err := event.IntVar(f) 103 if name != IntVarLastInsertID || value != 0x123456789abcdef0 || err != nil { 104 t.Fatalf("IntVar() returned %v/%v/%v", name, value, err) 105 } 106 107 event = NewIntVarEvent(f, s, IntVarInvalidInt, 0x123456789abcdef0) 108 require.True(t, event.IsValid(), "NewIntVarEvent().IsValid() is false") 109 require.True(t, event.IsIntVar(), "NewIntVarEvent().IsIntVar() is false") 110 111 name, value, err = event.IntVar(f) 112 require.Error(t, err, "IntVar(invalid) returned %v/%v/%v", name, value, err) 113 114 } 115 116 func TestInvalidEvents(t *testing.T) { 117 f := NewMySQL56BinlogFormat() 118 s := NewFakeBinlogStream() 119 120 // InvalidEvent 121 event := NewInvalidEvent() 122 if event.IsValid() { 123 t.Fatalf("NewInvalidEvent().IsValid() is true") 124 } 125 126 // InvalidFormatDescriptionEvent 127 event = NewInvalidFormatDescriptionEvent(f, s) 128 require.True(t, event.IsValid(), "NewInvalidFormatDescriptionEvent().IsValid() is false") 129 require.True(t, event.IsFormatDescription(), "NewInvalidFormatDescriptionEvent().IsFormatDescription() is false") 130 131 if _, err := event.Format(); err == nil { 132 t.Fatalf("NewInvalidFormatDescriptionEvent().Format() returned err=nil") 133 } 134 135 // InvalidQueryEvent 136 event = NewInvalidQueryEvent(f, s) 137 require.True(t, event.IsValid(), "NewInvalidQueryEvent().IsValid() is false") 138 require.True(t, event.IsQuery(), "NewInvalidQueryEvent().IsQuery() is false") 139 140 if _, err := event.Query(f); err == nil { 141 t.Fatalf("NewInvalidQueryEvent().Query() returned err=nil") 142 } 143 } 144 145 func TestMariadDBGTIDEVent(t *testing.T) { 146 f := NewMySQL56BinlogFormat() 147 s := NewFakeBinlogStream() 148 s.ServerID = 0x87654321 149 150 // With built-in begin. 151 event := NewMariaDBGTIDEvent(f, s, MariadbGTID{Domain: 0, Sequence: 0x123456789abcdef0}, true) 152 require.True(t, event.IsValid(), "NewMariaDBGTIDEvent().IsValid() is false") 153 require.True(t, event.IsGTID(), "NewMariaDBGTIDEvent().IsGTID() if false") 154 155 event, _, err := event.StripChecksum(f) 156 require.NoError(t, err, "StripChecksum failed: %v", err) 157 158 gtid, hasBegin, err := event.GTID(f) 159 require.NoError(t, err, "NewMariaDBGTIDEvent().GTID() returned error: %v", err) 160 require.True(t, hasBegin, "NewMariaDBGTIDEvent() didn't store hasBegin properly.") 161 162 mgtid, ok := gtid.(MariadbGTID) 163 require.True(t, ok, "NewMariaDBGTIDEvent().GTID() returned a non-MariaDBGTID GTID") 164 165 if mgtid.Domain != 0 || mgtid.Server != 0x87654321 || mgtid.Sequence != 0x123456789abcdef0 { 166 t.Fatalf("NewMariaDBGTIDEvent().GTID() returned invalid GITD: %v", mgtid) 167 } 168 169 // Without built-in begin. 170 event = NewMariaDBGTIDEvent(f, s, MariadbGTID{Domain: 0, Sequence: 0x123456789abcdef0}, false) 171 require.True(t, event.IsValid(), "NewMariaDBGTIDEvent().IsValid() is false") 172 require.True(t, event.IsGTID(), "NewMariaDBGTIDEvent().IsGTID() if false") 173 174 event, _, err = event.StripChecksum(f) 175 require.NoError(t, err, "StripChecksum failed: %v", err) 176 177 gtid, hasBegin, err = event.GTID(f) 178 require.NoError(t, err, "NewMariaDBGTIDEvent().GTID() returned error: %v", err) 179 require.False(t, hasBegin, "NewMariaDBGTIDEvent() didn't store hasBegin properly.") 180 181 mgtid, ok = gtid.(MariadbGTID) 182 require.True(t, ok, "NewMariaDBGTIDEvent().GTID() returned a non-MariaDBGTID GTID") 183 184 if mgtid.Domain != 0 || mgtid.Server != 0x87654321 || mgtid.Sequence != 0x123456789abcdef0 { 185 t.Fatalf("NewMariaDBGTIDEvent().GTID() returned invalid GITD: %v", mgtid) 186 } 187 } 188 189 func TestTableMapEvent(t *testing.T) { 190 f := NewMySQL56BinlogFormat() 191 s := NewFakeBinlogStream() 192 193 tm := &TableMap{ 194 Flags: 0x8090, 195 Database: "my_database", 196 Name: "my_table", 197 Types: []byte{ 198 TypeLongLong, 199 TypeLongLong, 200 TypeLongLong, 201 TypeLongLong, 202 TypeLongLong, 203 TypeTime, 204 TypeLongLong, 205 TypeLongLong, 206 TypeLongLong, 207 TypeVarchar, 208 }, 209 CanBeNull: NewServerBitmap(10), 210 Metadata: []uint16{ 211 0, 212 0, 213 0, 214 0, 215 0, 216 0, 217 0, 218 0, 219 0, 220 384, // Length of the varchar field. 221 }, 222 } 223 tm.CanBeNull.Set(1, true) 224 tm.CanBeNull.Set(2, true) 225 tm.CanBeNull.Set(5, true) 226 tm.CanBeNull.Set(9, true) 227 228 event := NewTableMapEvent(f, s, 0x102030405060, tm) 229 require.True(t, event.IsValid(), "NewTableMapEvent().IsValid() is false") 230 require.True(t, event.IsTableMap(), "NewTableMapEvent().IsTableMap() if false") 231 232 event, _, err := event.StripChecksum(f) 233 require.NoError(t, err, "StripChecksum failed: %v", err) 234 235 tableID := event.TableID(f) 236 require.Equal(t, uint64(0x102030405060), tableID, "NewTableMapEvent().ID returned %x", tableID) 237 238 gotTm, err := event.TableMap(f) 239 require.NoError(t, err, "NewTableMapEvent().TableMapEvent() returned error: %v", err) 240 require.True(t, reflect.DeepEqual(gotTm, tm), "NewTableMapEvent().TableMapEvent() got TableMap:\n%v\nexpected:\n%v", gotTm, tm) 241 242 } 243 244 func TestLargeTableMapEvent(t *testing.T) { 245 f := NewMySQL56BinlogFormat() 246 s := NewFakeBinlogStream() 247 248 colLen := 256 249 types := make([]byte, 0, colLen) 250 metadata := make([]uint16, 0, colLen) 251 252 for i := 0; i < colLen; i++ { 253 types = append(types, TypeLongLong) 254 metadata = append(metadata, 0) 255 } 256 257 tm := &TableMap{ 258 Flags: 0x8090, 259 Database: "my_database", 260 Name: "my_table", 261 Types: types, 262 CanBeNull: NewServerBitmap(colLen), 263 Metadata: metadata, 264 } 265 tm.CanBeNull.Set(1, true) 266 tm.CanBeNull.Set(2, true) 267 tm.CanBeNull.Set(5, true) 268 tm.CanBeNull.Set(9, true) 269 270 event := NewTableMapEvent(f, s, 0x102030405060, tm) 271 require.True(t, event.IsValid(), "NewTableMapEvent().IsValid() is false") 272 require.True(t, event.IsTableMap(), "NewTableMapEvent().IsTableMap() if false") 273 274 event, _, err := event.StripChecksum(f) 275 require.NoError(t, err, "StripChecksum failed: %v", err) 276 277 tableID := event.TableID(f) 278 require.Equal(t, uint64(0x102030405060), tableID, "NewTableMapEvent().ID returned %x", tableID) 279 280 gotTm, err := event.TableMap(f) 281 require.NoError(t, err, "NewTableMapEvent().TableMapEvent() returned error: %v", err) 282 require.True(t, reflect.DeepEqual(gotTm, tm), "NewTableMapEvent().TableMapEvent() got TableMap:\n%v\nexpected:\n%v", gotTm, tm) 283 284 } 285 286 func TestRowsEvent(t *testing.T) { 287 f := NewMySQL56BinlogFormat() 288 s := NewFakeBinlogStream() 289 290 /* 291 Reason for nolint 292 Used in line 384 to 387 293 tableID = event.ID(f) 294 if tableID != 0x102030405060 { 295 t.Fatalf("NewRowsEvent().ID returned %x", tableID) 296 } 297 */ 298 tableID := uint64(0x102030405060) //nolint 299 300 tm := &TableMap{ 301 Flags: 0x8090, 302 Database: "my_database", 303 Name: "my_table", 304 Types: []byte{ 305 TypeLong, 306 TypeVarchar, 307 }, 308 CanBeNull: NewServerBitmap(2), 309 Metadata: []uint16{ 310 0, 311 384, 312 }, 313 } 314 tm.CanBeNull.Set(1, true) 315 316 // Do an update packet with all fields set. 317 rows := Rows{ 318 Flags: 0x1234, 319 IdentifyColumns: NewServerBitmap(2), 320 DataColumns: NewServerBitmap(2), 321 Rows: []Row{ 322 { 323 NullIdentifyColumns: NewServerBitmap(2), 324 NullColumns: NewServerBitmap(2), 325 Identify: []byte{ 326 0x10, 0x20, 0x30, 0x40, // long 327 0x03, 0x00, // len('abc') 328 'a', 'b', 'c', // 'abc' 329 }, 330 Data: []byte{ 331 0x10, 0x20, 0x30, 0x40, // long 332 0x04, 0x00, // len('abcd') 333 'a', 'b', 'c', 'd', // 'abcd' 334 }, 335 }, 336 }, 337 } 338 339 // All rows are included, none are NULL. 340 rows.IdentifyColumns.Set(0, true) 341 rows.IdentifyColumns.Set(1, true) 342 rows.DataColumns.Set(0, true) 343 rows.DataColumns.Set(1, true) 344 345 // Test the Rows we just created, to be sure. 346 // 1076895760 is 0x40302010. 347 identifies, _ := rows.StringIdentifiesForTests(tm, 0) 348 if expected := []string{"1076895760", "abc"}; !reflect.DeepEqual(identifies, expected) { 349 t.Fatalf("bad Rows identify, got %v expected %v", identifies, expected) 350 } 351 values, _ := rows.StringValuesForTests(tm, 0) 352 if expected := []string{"1076895760", "abcd"}; !reflect.DeepEqual(values, expected) { 353 t.Fatalf("bad Rows data, got %v expected %v", values, expected) 354 } 355 356 event := NewUpdateRowsEvent(f, s, 0x102030405060, rows) 357 require.True(t, event.IsValid(), "NewRowsEvent().IsValid() is false") 358 require.True(t, event.IsUpdateRows(), "NewRowsEvent().IsUpdateRows() if false") 359 360 event, _, err := event.StripChecksum(f) 361 require.NoError(t, err, "StripChecksum failed: %v", err) 362 363 tableID = event.TableID(f) 364 require.Equal(t, uint64(0x102030405060), tableID, "NewRowsEvent().ID returned %x", tableID) 365 366 gotRows, err := event.Rows(f, tm) 367 require.NoError(t, err, "NewRowsEvent().Rows() returned error: %v", err) 368 require.True(t, reflect.DeepEqual(gotRows, rows), "NewRowsEvent().Rows() got Rows:\n%v\nexpected:\n%v", gotRows, rows) 369 370 assert.NotZero(t, event.Timestamp()) 371 } 372 373 func TestHeartbeatEvent(t *testing.T) { 374 // MySQL 5.6 375 f := NewMySQL56BinlogFormat() 376 s := NewFakeBinlogStream() 377 event := NewHeartbeatEvent(f, s) 378 require.NotNil(t, event) 379 assert.True(t, event.IsHeartbeat()) 380 assert.Zero(t, event.Timestamp()) 381 } 382 383 func TestRotateRotateEvent(t *testing.T) { 384 // MySQL 5.6 385 f := NewMySQL56BinlogFormat() 386 s := NewFakeBinlogStream() 387 event := NewRotateEvent(f, s, 456, "mysql-bin.000123") 388 require.NotNil(t, event) 389 assert.True(t, event.IsRotate()) 390 nextFile, pos, err := event.NextLogFile(f) 391 assert.NoError(t, err) 392 assert.Equal(t, 456, int(pos)) 393 assert.Equal(t, "mysql-bin.000123", nextFile) 394 } 395 396 func TestFakeRotateEvent(t *testing.T) { 397 // MySQL 5.6 398 f := NewMySQL56BinlogFormat() 399 s := NewFakeBinlogStream() 400 event := NewFakeRotateEvent(f, s, "mysql-bin.000123") 401 require.NotNil(t, event) 402 assert.True(t, event.IsRotate()) 403 nextFile, pos, err := event.NextLogFile(f) 404 assert.NoError(t, err) 405 assert.Equal(t, 4, int(pos)) 406 assert.Equal(t, "mysql-bin.000123", nextFile) 407 } 408 func TestLargeRowsEvent(t *testing.T) { 409 f := NewMySQL56BinlogFormat() 410 s := NewFakeBinlogStream() 411 412 /* 413 Reason for nolint 414 Used in line 384 to 387 415 tableID = event.ID(f) 416 if tableID != 0x102030405060 { 417 t.Fatalf("NewRowsEvent().ID returned %x", tableID) 418 } 419 */ 420 tableID := uint64(0x102030405060) //nolint 421 422 colLen := 256 423 types := make([]byte, 0, colLen) 424 metadata := make([]uint16, 0, colLen) 425 426 for i := 0; i < colLen; i++ { 427 types = append(types, TypeLong) 428 metadata = append(metadata, 0) 429 } 430 431 tm := &TableMap{ 432 Flags: 0x8090, 433 Database: "my_database", 434 Name: "my_table", 435 Types: types, 436 CanBeNull: NewServerBitmap(colLen), 437 Metadata: metadata, 438 } 439 tm.CanBeNull.Set(1, true) 440 441 identify := make([]byte, 0, colLen*4) 442 data := make([]byte, 0, colLen*4) 443 for i := 0; i < colLen; i++ { 444 identify = append(identify, 0x10, 0x20, 0x30, 0x40) 445 data = append(data, 0x10, 0x20, 0x30, 0x40) 446 } 447 448 // Do an update packet with all fields set. 449 rows := Rows{ 450 Flags: 0x1234, 451 IdentifyColumns: NewServerBitmap(colLen), 452 DataColumns: NewServerBitmap(colLen), 453 Rows: []Row{ 454 { 455 NullIdentifyColumns: NewServerBitmap(colLen), 456 NullColumns: NewServerBitmap(colLen), 457 Identify: identify, 458 Data: data, 459 }, 460 }, 461 } 462 463 // All rows are included, none are NULL. 464 for i := 0; i < colLen; i++ { 465 rows.IdentifyColumns.Set(i, true) 466 rows.DataColumns.Set(i, true) 467 } 468 469 // Test the Rows we just created, to be sure. 470 // 1076895760 is 0x40302010. 471 identifies, _ := rows.StringIdentifiesForTests(tm, 0) 472 expected := make([]string, 0, colLen) 473 for i := 0; i < colLen; i++ { 474 expected = append(expected, "1076895760") 475 } 476 if !reflect.DeepEqual(identifies, expected) { 477 t.Fatalf("bad Rows identify, got %v expected %v", identifies, expected) 478 } 479 values, _ := rows.StringValuesForTests(tm, 0) 480 if !reflect.DeepEqual(values, expected) { 481 t.Fatalf("bad Rows data, got %v expected %v", values, expected) 482 } 483 484 event := NewUpdateRowsEvent(f, s, 0x102030405060, rows) 485 require.True(t, event.IsValid(), "NewRowsEvent().IsValid() is false") 486 require.True(t, event.IsUpdateRows(), "NewRowsEvent().IsUpdateRows() if false") 487 488 event, _, err := event.StripChecksum(f) 489 require.NoError(t, err, "StripChecksum failed: %v", err) 490 491 tableID = event.TableID(f) 492 require.Equal(t, uint64(0x102030405060), tableID, "NewRowsEvent().ID returned %x", tableID) 493 494 gotRows, err := event.Rows(f, tm) 495 require.NoError(t, err, "NewRowsEvent().Rows() returned error: %v", err) 496 require.True(t, reflect.DeepEqual(gotRows, rows), "NewRowsEvent().Rows() got Rows:\n%v\nexpected:\n%v", gotRows, rows) 497 498 }