github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/binlog/event/common_test.go (about)

     1  // Copyright 2019 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package event
    15  
    16  import (
    17  	"fmt"
    18  	"os"
    19  	"path/filepath"
    20  	"testing"
    21  
    22  	gmysql "github.com/go-mysql-org/go-mysql/mysql"
    23  	"github.com/go-mysql-org/go-mysql/replication"
    24  	"github.com/pingcap/tiflow/dm/pkg/gtid"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func TestGenCommonFileHeader(t *testing.T) {
    29  	t.Parallel()
    30  	var (
    31  		flavor          = gmysql.MySQLFlavor
    32  		serverID uint32 = 101
    33  		gSetStr         = "3ccc475b-2343-11e7-be21-6c0b84d59f30:1-14,406a3f61-690d-11e7-87c5-6c92bf46f384:1-94321383,53bfca22-690d-11e7-8a62-18ded7a37b78:1-495,686e1ab6-c47e-11e7-a42c-6c92bf46f384:1-34981190,03fc0263-28c7-11e7-a653-6c0b84d59f30:1-7041423,05474d3c-28c7-11e7-8352-203db246dd3d:1-170,10b039fc-c843-11e7-8f6a-1866daf8d810:1-308290454"
    34  		gSet     gmysql.GTIDSet
    35  	)
    36  	gSet, err := gtid.ParserGTID(flavor, gSetStr)
    37  	require.Nil(t, err)
    38  
    39  	events, data, err := GenCommonFileHeader(flavor, serverID, gSet, true, 0)
    40  	require.Nil(t, err)
    41  	require.Equal(t, 2, len(events))
    42  	require.Equal(t, replication.FORMAT_DESCRIPTION_EVENT, events[0].Header.EventType)
    43  	require.Equal(t, replication.PREVIOUS_GTIDS_EVENT, events[1].Header.EventType)
    44  
    45  	// write to file then parse it
    46  	dir := t.TempDir()
    47  	mysqlFilename := filepath.Join(dir, "mysql-bin-test.000001")
    48  	mysqlFile, err := os.Create(mysqlFilename)
    49  	require.Nil(t, err)
    50  	defer mysqlFile.Close()
    51  
    52  	_, err = mysqlFile.Write(data)
    53  	require.Nil(t, err)
    54  
    55  	count := 0
    56  	onEventFunc := func(e *replication.BinlogEvent) error {
    57  		count++
    58  		if count > 2 {
    59  			t.Fatalf("too many binlog events got, current is %+v", e.Header)
    60  		}
    61  		require.Equal(t, events[count-1].Header, e.Header)
    62  		require.Equal(t, events[count-1].Event, e.Event)
    63  		require.Equal(t, events[count-1].RawData, e.RawData)
    64  		return nil
    65  	}
    66  
    67  	parser2 := replication.NewBinlogParser()
    68  	parser2.SetVerifyChecksum(true)
    69  	err = parser2.ParseFile(mysqlFilename, 0, onEventFunc)
    70  	require.Nil(t, err)
    71  
    72  	// MariaDB
    73  	flavor = gmysql.MariaDBFlavor
    74  	gSetStr = "1-2-12,2-2-3,3-3-8,3-4-9"
    75  
    76  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
    77  	require.Nil(t, err)
    78  
    79  	events, data, err = GenCommonFileHeader(flavor, serverID, gSet, true, 0)
    80  	require.Nil(t, err)
    81  	require.Equal(t, 2, len(events))
    82  	require.Equal(t, replication.FORMAT_DESCRIPTION_EVENT, events[0].Header.EventType)
    83  	require.Equal(t, replication.MARIADB_GTID_LIST_EVENT, events[1].Header.EventType)
    84  
    85  	mariadbFilename := filepath.Join(dir, "mariadb-bin-test.000001")
    86  	mariadbFile, err := os.Create(mariadbFilename)
    87  	require.Nil(t, err)
    88  	defer mariadbFile.Close()
    89  
    90  	_, err = mariadbFile.Write(data)
    91  	require.Nil(t, err)
    92  
    93  	count = 0 // reset to 0
    94  	err = parser2.ParseFile(mariadbFilename, 0, onEventFunc)
    95  	require.Nil(t, err)
    96  }
    97  
    98  func TestGenCommonGTIDEvent(t *testing.T) {
    99  	t.Parallel()
   100  	var (
   101  		flavor           = gmysql.MySQLFlavor
   102  		serverID  uint32 = 101
   103  		gSet      gmysql.GTIDSet
   104  		latestPos uint32 = 123
   105  	)
   106  
   107  	// nil gSet, invalid
   108  	gtidEv, err := GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   109  	require.NotNil(t, err)
   110  	require.Nil(t, gtidEv)
   111  
   112  	// multi GTID in set, invalid
   113  	gSetStr := "03fc0263-28c7-11e7-a653-6c0b84d59f30:1-123,05474d3c-28c7-11e7-8352-203db246dd3d:1-456,10b039fc-c843-11e7-8f6a-1866daf8d810:1-789"
   114  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   115  	require.Nil(t, err)
   116  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   117  	require.NotNil(t, err)
   118  	require.Nil(t, gtidEv)
   119  
   120  	// multi intervals, invalid
   121  	gSetStr = "03fc0263-28c7-11e7-a653-6c0b84d59f30:1-123:200-456"
   122  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   123  	require.Nil(t, err)
   124  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   125  	require.NotNil(t, err)
   126  	require.Nil(t, gtidEv)
   127  
   128  	// interval > 1, invalid
   129  	gSetStr = "03fc0263-28c7-11e7-a653-6c0b84d59f30:1-123"
   130  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   131  	require.Nil(t, err)
   132  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   133  	require.NotNil(t, err)
   134  	require.Nil(t, gtidEv)
   135  
   136  	// valid
   137  	gSetStr = "03fc0263-28c7-11e7-a653-6c0b84d59f30:123"
   138  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   139  	require.Nil(t, err)
   140  	sid, err := ParseSID(gSetStr[:len(gSetStr)-4])
   141  	require.Nil(t, err)
   142  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   143  	require.Nil(t, err)
   144  	require.NotNil(t, gtidEv)
   145  	require.Equal(t, replication.GTID_EVENT, gtidEv.Header.EventType)
   146  
   147  	// verify the body
   148  	gtidEvBody1, ok := gtidEv.Event.(*replication.GTIDEvent)
   149  	require.True(t, ok)
   150  	require.NotNil(t, gtidEvBody1)
   151  	require.Equal(t, sid.Bytes(), gtidEvBody1.SID)
   152  	require.Equal(t, int64(123), gtidEvBody1.GNO)
   153  	require.Equal(t, defaultGTIDFlags, gtidEvBody1.CommitFlag)
   154  	require.Equal(t, defaultLastCommitted, gtidEvBody1.LastCommitted)
   155  	require.Equal(t, defaultSequenceNumber, gtidEvBody1.SequenceNumber)
   156  
   157  	// change flavor to MariaDB
   158  	flavor = gmysql.MariaDBFlavor
   159  
   160  	// GTID mismatch with flavor
   161  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   162  	require.NotNil(t, err)
   163  	require.Nil(t, gtidEv)
   164  
   165  	// multi GTID in set, invalid
   166  	gSetStr = "1-2-3,4-5-6"
   167  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   168  	require.Nil(t, err)
   169  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   170  	require.NotNil(t, err)
   171  	require.Nil(t, gtidEv)
   172  
   173  	// server_id mismatch, invalid
   174  	gSetStr = "1-2-3"
   175  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   176  	require.Nil(t, err)
   177  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   178  	require.NotNil(t, err)
   179  	require.Nil(t, gtidEv)
   180  
   181  	// valid
   182  	gSetStr = fmt.Sprintf("1-%d-3", serverID)
   183  	gSet, err = gtid.ParserGTID(flavor, gSetStr)
   184  	require.Nil(t, err)
   185  	gtidEv, err = GenCommonGTIDEvent(flavor, serverID, latestPos, gSet, false, 0)
   186  	require.Nil(t, err)
   187  	require.NotNil(t, gtidEv)
   188  	require.Equal(t, replication.MARIADB_GTID_EVENT, gtidEv.Header.EventType)
   189  
   190  	// verify the body, we
   191  	gtidEvBody2, ok := gtidEv.Event.(*replication.MariadbGTIDEvent)
   192  	require.True(t, ok)
   193  	require.Equal(t, uint32(1), gtidEvBody2.GTID.DomainID)
   194  	require.Equal(t, serverID, gtidEvBody2.GTID.ServerID)
   195  	require.Equal(t, uint64(3), gtidEvBody2.GTID.SequenceNumber)
   196  }
   197  
   198  func TestGTIDIncrease(t *testing.T) {
   199  	t.Parallel()
   200  	var (
   201  		flavor  = gmysql.MySQLFlavor
   202  		gSetStr = "03fc0263-28c7-11e7-a653-6c0b84d59f30:123"
   203  		gSetIn  gmysql.GTIDSet
   204  		gSetOut gmysql.GTIDSet
   205  	)
   206  
   207  	// increase for MySQL
   208  	gSetIn, err := gtid.ParserGTID(flavor, gSetStr)
   209  	require.Nil(t, err)
   210  	gSetOut, err = GTIDIncrease(flavor, gSetIn)
   211  	require.Nil(t, err)
   212  	require.NotNil(t, gSetOut)
   213  	require.Equal(t, "03fc0263-28c7-11e7-a653-6c0b84d59f30:124", gSetOut.String())
   214  
   215  	// increase for MariaDB
   216  	flavor = gmysql.MariaDBFlavor
   217  	gSetStr = "1-2-3"
   218  	gSetIn, err = gtid.ParserGTID(flavor, gSetStr)
   219  	require.Nil(t, err)
   220  	gSetOut, err = GTIDIncrease(flavor, gSetIn)
   221  	require.Nil(t, err)
   222  	require.NotNil(t, gSetOut)
   223  	require.Equal(t, "1-2-4", gSetOut.String())
   224  }