github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/relay/util_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 relay
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"io"
    20  
    21  	"github.com/DATA-DOG/go-sqlmock"
    22  	gmysql "github.com/go-mysql-org/go-mysql/mysql"
    23  	. "github.com/pingcap/check"
    24  	"github.com/pingcap/errors"
    25  	"github.com/pingcap/tiflow/dm/pkg/conn"
    26  	tcontext "github.com/pingcap/tiflow/dm/pkg/context"
    27  	"github.com/pingcap/tiflow/dm/pkg/log"
    28  )
    29  
    30  var _ = Suite(&testUtilSuite{})
    31  
    32  type testUtilSuite struct{}
    33  
    34  func (t *testUtilSuite) TestIsNewServer(c *C) {
    35  	ctx, cancel := context.WithTimeout(context.Background(), conn.DefaultDBTimeout)
    36  	defer cancel()
    37  
    38  	mockDB := conn.InitMockDB(c)
    39  	baseDB, err := conn.GetUpstreamDB(getDBConfigForTest())
    40  	c.Assert(err, IsNil)
    41  
    42  	flavor := gmysql.MySQLFlavor
    43  	// no prevUUID, is new server.
    44  	isNew, err := isNewServer(ctx, "", baseDB, flavor)
    45  	c.Assert(err, IsNil)
    46  	c.Assert(isNew, IsTrue)
    47  
    48  	// different server
    49  	mockGetServerUUID(mockDB)
    50  	isNew, err = isNewServer(ctx, "not-exists-uuid.000001", baseDB, flavor)
    51  	c.Assert(err, IsNil)
    52  	c.Assert(isNew, IsTrue)
    53  
    54  	// the same server
    55  	mockGetServerUUID(mockDB)
    56  	currUUID, err := conn.GetServerUUID(tcontext.NewContext(ctx, log.L()), baseDB, flavor)
    57  	c.Assert(err, IsNil)
    58  
    59  	mockGetServerUUID(mockDB)
    60  	isNew, err = isNewServer(ctx, fmt.Sprintf("%s.000001", currUUID), baseDB, flavor)
    61  	c.Assert(err, IsNil)
    62  	c.Assert(isNew, IsFalse)
    63  	c.Assert(mockDB.ExpectationsWereMet(), IsNil)
    64  }
    65  
    66  func mockGetServerUUID(mockDB sqlmock.Sqlmock) {
    67  	mockDB.ExpectQuery("SHOW GLOBAL VARIABLES LIKE 'server_uuid'").WithArgs().
    68  		WillReturnRows(sqlmock.NewRows([]string{"Variable_name", "Value"}).AddRow("server_uuid", "12e57f06-f360-11eb-8235-585cc2bc66c9"))
    69  }
    70  
    71  func mockGetRandomServerID(mockDB sqlmock.Sqlmock) {
    72  	rows := sqlmock.NewRows([]string{"Server_id", "Host", "Port", "Master_id", "Slave_UUID"})
    73  	rows.AddRow("2", "127.0.0.1", "3307", "1", "uuid2")
    74  	mockDB.ExpectQuery("SHOW SLAVE HOSTS").WillReturnRows(rows)
    75  	mockDB.ExpectQuery("SHOW GLOBAL VARIABLES LIKE 'server_id'").WillReturnRows(
    76  		sqlmock.NewRows([]string{"Variable_name", "Value"}).AddRow("server_id", "1"))
    77  }
    78  
    79  func (t *testUtilSuite) TestGetNextUUID(c *C) {
    80  	UUIDs := []string{
    81  		"b60868af-5a6f-11e9-9ea3-0242ac160006.000001",
    82  		"7acfedb5-3008-4fa2-9776-6bac42b025fe.000002",
    83  		"92ffd03b-813e-4391-b16a-177524e8d531.000003",
    84  		"338513ce-b24e-4ff8-9ded-9ac5aa8f4d74.000004",
    85  	}
    86  	cases := []struct {
    87  		currUUID       string
    88  		UUIDs          []string
    89  		nextUUID       string
    90  		nextUUIDSuffix string
    91  		errMsgReg      string
    92  	}{
    93  		{
    94  			// empty current and UUID list
    95  		},
    96  		{
    97  			// non-empty current UUID, but empty UUID list
    98  			currUUID: "b60868af-5a6f-11e9-9ea3-0242ac160006.000001",
    99  		},
   100  		{
   101  			// empty current UUID, but non-empty UUID list
   102  			UUIDs: UUIDs,
   103  		},
   104  		{
   105  			// current UUID in UUID list, has next UUID
   106  			currUUID:       UUIDs[0],
   107  			UUIDs:          UUIDs,
   108  			nextUUID:       UUIDs[1],
   109  			nextUUIDSuffix: UUIDs[1][len(UUIDs[1])-6:],
   110  		},
   111  		{
   112  			// current UUID in UUID list, but has no next UUID
   113  			currUUID: UUIDs[len(UUIDs)-1],
   114  			UUIDs:    UUIDs,
   115  		},
   116  		{
   117  			// current UUID not in UUID list
   118  			currUUID: "40ed16c1-f6f7-4012-aa9b-d360261d2b22.666666",
   119  			UUIDs:    UUIDs,
   120  		},
   121  		{
   122  			// invalid next UUID in UUID list
   123  			currUUID:  UUIDs[len(UUIDs)-1],
   124  			UUIDs:     append(UUIDs, "invalid-uuid"),
   125  			errMsgReg: ".*invalid-uuid.*",
   126  		},
   127  	}
   128  
   129  	for _, cs := range cases {
   130  		nu, nus, err := getNextRelaySubDir(cs.currUUID, cs.UUIDs)
   131  		if len(cs.errMsgReg) > 0 {
   132  			c.Assert(err, ErrorMatches, cs.errMsgReg)
   133  		} else {
   134  			c.Assert(err, IsNil)
   135  		}
   136  		c.Assert(nu, Equals, cs.nextUUID)
   137  		c.Assert(nus, Equals, cs.nextUUIDSuffix)
   138  	}
   139  }
   140  
   141  func (t *testUtilSuite) TestIsIgnorableParseError(c *C) {
   142  	cases := []struct {
   143  		err       error
   144  		ignorable bool
   145  	}{
   146  		{
   147  			err:       nil,
   148  			ignorable: false,
   149  		},
   150  		{
   151  			err:       io.EOF,
   152  			ignorable: true,
   153  		},
   154  		{
   155  			err:       errors.Annotate(io.EOF, "annotated end of file"),
   156  			ignorable: true,
   157  		},
   158  		{
   159  			err:       errors.New("get event header err EOF xxxx"),
   160  			ignorable: true,
   161  		},
   162  		{
   163  			err:       errors.New("some other error"),
   164  			ignorable: false,
   165  		},
   166  	}
   167  
   168  	for _, cs := range cases {
   169  		c.Assert(isIgnorableParseError(cs.err), Equals, cs.ignorable)
   170  	}
   171  }