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  }