github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/relay/upstream_reader_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  	"time"
    19  
    20  	"github.com/go-mysql-org/go-mysql/replication"
    21  	"github.com/pingcap/check"
    22  	"github.com/pingcap/errors"
    23  	"github.com/pingcap/tiflow/dm/pkg/binlog/reader"
    24  )
    25  
    26  var _ = check.Suite(&testRemoteReaderSuite{})
    27  
    28  type testRemoteReaderSuite struct{}
    29  
    30  func (t *testRemoteReaderSuite) TestInterface(c *check.C) {
    31  	cases := []*replication.BinlogEvent{
    32  		{RawData: []byte{1}},
    33  		{RawData: []byte{2}},
    34  		{RawData: []byte{3}},
    35  	}
    36  
    37  	cfg := &RConfig{
    38  		SyncConfig: replication.BinlogSyncerConfig{
    39  			ServerID: 101,
    40  		},
    41  		MasterID: "test-master",
    42  	}
    43  
    44  	// test with position
    45  	r := NewUpstreamReader(cfg)
    46  	t.testInterfaceWithReader(c, r, cases)
    47  
    48  	// test with GTID
    49  	cfg.EnableGTID = true
    50  	r = NewUpstreamReader(cfg)
    51  	t.testInterfaceWithReader(c, r, cases)
    52  }
    53  
    54  func (t *testRemoteReaderSuite) testInterfaceWithReader(c *check.C, r Reader, cases []*replication.BinlogEvent) {
    55  	// replace underlying reader with a mock reader for testing
    56  	concreteR := r.(*upstreamReader)
    57  	c.Assert(concreteR, check.NotNil)
    58  	mockR := reader.NewMockReader()
    59  	concreteR.in = mockR
    60  
    61  	// start reader
    62  	err := r.Start()
    63  	c.Assert(err, check.IsNil)
    64  	err = r.Start() // call multi times
    65  	c.Assert(err, check.NotNil)
    66  
    67  	// getEvent by pushing event to mock reader
    68  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    69  	defer cancel()
    70  	concreteMR := mockR.(*reader.MockReader)
    71  	go func() {
    72  		for _, cs := range cases {
    73  			c.Assert(concreteMR.PushEvent(ctx, cs), check.IsNil)
    74  		}
    75  	}()
    76  	obtained := make([]*replication.BinlogEvent, 0, len(cases))
    77  	for {
    78  		result, err2 := r.GetEvent(ctx)
    79  		c.Assert(err2, check.IsNil)
    80  		obtained = append(obtained, result.Event)
    81  		if len(obtained) == len(cases) {
    82  			break
    83  		}
    84  	}
    85  	c.Assert(obtained, check.DeepEquals, cases)
    86  
    87  	// close reader
    88  	err = r.Close()
    89  	c.Assert(err, check.IsNil)
    90  	err = r.Close()
    91  	c.Assert(err, check.NotNil) // call multi times
    92  
    93  	// getEvent from a closed reader
    94  	result, err := r.GetEvent(ctx)
    95  	c.Assert(err, check.NotNil)
    96  	c.Assert(result.Event, check.IsNil)
    97  }
    98  
    99  func (t *testRemoteReaderSuite) TestGetEventWithError(c *check.C) {
   100  	cfg := &RConfig{
   101  		SyncConfig: replication.BinlogSyncerConfig{
   102  			ServerID: 101,
   103  		},
   104  		MasterID: "test-master",
   105  	}
   106  
   107  	r := NewUpstreamReader(cfg)
   108  	// replace underlying reader with a mock reader for testing
   109  	concreteR := r.(*upstreamReader)
   110  	c.Assert(concreteR, check.NotNil)
   111  	mockR := reader.NewMockReader()
   112  	concreteR.in = mockR
   113  
   114  	errOther := errors.New("other error")
   115  	in := []error{
   116  		context.Canceled,
   117  		errOther,
   118  	}
   119  	expected := []error{
   120  		context.Canceled,
   121  		errOther,
   122  	}
   123  
   124  	err := r.Start()
   125  	c.Assert(err, check.IsNil)
   126  
   127  	// getEvent by pushing event to mock reader
   128  	ctx, cancel := context.WithCancel(context.Background())
   129  	defer cancel()
   130  	concreteMR := mockR.(*reader.MockReader)
   131  	go func() {
   132  		for _, cs := range in {
   133  			c.Assert(concreteMR.PushError(ctx, cs), check.IsNil)
   134  		}
   135  	}()
   136  
   137  	results := make([]error, 0, len(expected))
   138  	for {
   139  		_, err2 := r.GetEvent(ctx)
   140  		c.Assert(err2, check.NotNil)
   141  		results = append(results, errors.Cause(err2))
   142  		if err2 == errOther {
   143  			break // all received
   144  		}
   145  	}
   146  	c.Assert(results, check.DeepEquals, expected)
   147  }