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  }