github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/puller/puller_test.go (about) 1 // Copyright 2020 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 puller 15 16 import ( 17 "bytes" 18 "context" 19 "fmt" 20 "sync" 21 22 "github.com/pingcap/check" 23 "github.com/pingcap/errors" 24 "github.com/pingcap/ticdc/cdc/kv" 25 "github.com/pingcap/ticdc/cdc/model" 26 cerrors "github.com/pingcap/ticdc/pkg/errors" 27 "github.com/pingcap/ticdc/pkg/regionspan" 28 "github.com/pingcap/ticdc/pkg/retry" 29 "github.com/pingcap/ticdc/pkg/security" 30 "github.com/pingcap/ticdc/pkg/txnutil" 31 "github.com/pingcap/ticdc/pkg/util/testleak" 32 tidbkv "github.com/pingcap/tidb/kv" 33 "github.com/pingcap/tidb/store/mockstore" 34 "github.com/pingcap/tidb/store/tikv" 35 pd "github.com/tikv/pd/client" 36 ) 37 38 type pullerSuite struct { 39 } 40 41 var _ = check.Suite(&pullerSuite{}) 42 43 type mockPdClientForPullerTest struct { 44 pd.Client 45 clusterID uint64 46 } 47 48 func (mc *mockPdClientForPullerTest) GetClusterID(ctx context.Context) uint64 { 49 return mc.clusterID 50 } 51 52 type mockCDCKVClient struct { 53 expectations chan model.RegionFeedEvent 54 } 55 56 type mockInjectedPuller struct { 57 Puller 58 cli *mockCDCKVClient 59 } 60 61 func newMockCDCKVClient( 62 ctx context.Context, 63 pd pd.Client, 64 kvStorage tikv.Storage, 65 grpcPool kv.GrpcPool, 66 ) kv.CDCKVClient { 67 return &mockCDCKVClient{ 68 expectations: make(chan model.RegionFeedEvent, 1024), 69 } 70 } 71 72 func (mc *mockCDCKVClient) EventFeed( 73 ctx context.Context, 74 span regionspan.ComparableSpan, 75 ts uint64, 76 enableOldValue bool, 77 lockResolver txnutil.LockResolver, 78 isPullerInit kv.PullerInitialization, 79 eventCh chan<- model.RegionFeedEvent, 80 ) error { 81 for { 82 select { 83 case <-ctx.Done(): 84 return ctx.Err() 85 case ev, ok := <-mc.expectations: 86 if !ok { 87 return nil 88 } 89 eventCh <- ev 90 } 91 } 92 } 93 94 func (mc *mockCDCKVClient) Close() error { 95 close(mc.expectations) 96 if len(mc.expectations) > 0 { 97 buf := bytes.NewBufferString("mockCDCKVClient: not all expectations were satisfied! Still waiting\n") 98 for e := range mc.expectations { 99 _, _ = buf.WriteString(fmt.Sprintf("%s", e.GetValue())) 100 } 101 return errors.New(buf.String()) 102 } 103 return nil 104 } 105 106 func (mc *mockCDCKVClient) Returns(ev model.RegionFeedEvent) { 107 mc.expectations <- ev 108 } 109 110 func (s *pullerSuite) newPullerForTest( 111 c *check.C, 112 spans []regionspan.Span, 113 checkpointTs uint64, 114 ) (*mockInjectedPuller, context.CancelFunc, *sync.WaitGroup, tidbkv.Storage) { 115 var wg sync.WaitGroup 116 ctx, cancel := context.WithCancel(context.Background()) 117 store, err := mockstore.NewMockStore() 118 c.Assert(err, check.IsNil) 119 enableOldValue := true 120 backupNewCDCKVClient := kv.NewCDCKVClient 121 kv.NewCDCKVClient = newMockCDCKVClient 122 defer func() { 123 kv.NewCDCKVClient = backupNewCDCKVClient 124 }() 125 pdCli := &mockPdClientForPullerTest{clusterID: uint64(1)} 126 grpcPool := kv.NewGrpcPoolImpl(ctx, &security.Credential{}) 127 defer grpcPool.Close() 128 plr := NewPuller(ctx, pdCli, grpcPool, store, checkpointTs, spans, enableOldValue) 129 wg.Add(1) 130 go func() { 131 defer wg.Done() 132 err := plr.Run(ctx) 133 if err != nil { 134 c.Assert(errors.Cause(err), check.Equals, context.Canceled) 135 } 136 }() 137 c.Assert(err, check.IsNil) 138 mockPlr := &mockInjectedPuller{ 139 Puller: plr, 140 cli: plr.(*pullerImpl).kvCli.(*mockCDCKVClient), 141 } 142 return mockPlr, cancel, &wg, store 143 } 144 145 func (s *pullerSuite) TestPullerResolvedForward(c *check.C) { 146 defer testleak.AfterTest(c)() 147 spans := []regionspan.Span{ 148 {Start: []byte("t_a"), End: []byte("t_e")}, 149 } 150 checkpointTs := uint64(996) 151 plr, cancel, wg, store := s.newPullerForTest(c, spans, checkpointTs) 152 153 plr.cli.Returns(model.RegionFeedEvent{ 154 Resolved: &model.ResolvedSpan{ 155 Span: regionspan.ToComparableSpan(regionspan.Span{Start: []byte("t_a"), End: []byte("t_c")}), 156 ResolvedTs: uint64(1001), 157 }, 158 }) 159 plr.cli.Returns(model.RegionFeedEvent{ 160 Resolved: &model.ResolvedSpan{ 161 Span: regionspan.ToComparableSpan(regionspan.Span{Start: []byte("t_c"), End: []byte("t_d")}), 162 ResolvedTs: uint64(1002), 163 }, 164 }) 165 plr.cli.Returns(model.RegionFeedEvent{ 166 Resolved: &model.ResolvedSpan{ 167 Span: regionspan.ToComparableSpan(regionspan.Span{Start: []byte("t_d"), End: []byte("t_e")}), 168 ResolvedTs: uint64(1000), 169 }, 170 }) 171 ev := <-plr.Output() 172 c.Assert(ev.OpType, check.Equals, model.OpTypeResolved) 173 c.Assert(ev.CRTs, check.Equals, uint64(1000)) 174 c.Assert(plr.IsInitialized(), check.IsTrue) 175 err := retry.Do(context.Background(), func() error { 176 ts := plr.GetResolvedTs() 177 if ts != uint64(1000) { 178 return errors.Errorf("resolved ts %d of puller does not forward to 1000", ts) 179 } 180 return nil 181 }, retry.WithBackoffBaseDelay(10), retry.WithMaxTries(10), retry.WithIsRetryableErr(cerrors.IsRetryableError)) 182 183 c.Assert(err, check.IsNil) 184 185 store.Close() 186 cancel() 187 wg.Wait() 188 } 189 190 func (s *pullerSuite) TestPullerRawKV(c *check.C) { 191 defer testleak.AfterTest(c)() 192 spans := []regionspan.Span{ 193 {Start: []byte("c"), End: []byte("e")}, 194 } 195 checkpointTs := uint64(996) 196 plr, cancel, wg, store := s.newPullerForTest(c, spans, checkpointTs) 197 198 plr.cli.Returns(model.RegionFeedEvent{ 199 Val: &model.RawKVEntry{ 200 OpType: model.OpTypePut, 201 Key: []byte("a"), 202 Value: []byte("test-value"), 203 CRTs: uint64(1002), 204 }, 205 }) 206 plr.cli.Returns(model.RegionFeedEvent{ 207 Val: &model.RawKVEntry{ 208 OpType: model.OpTypePut, 209 Key: []byte("d"), 210 Value: []byte("test-value"), 211 CRTs: uint64(1003), 212 }, 213 }) 214 var ev *model.RawKVEntry 215 ev = <-plr.Output() 216 c.Assert(ev.OpType, check.Equals, model.OpTypePut) 217 c.Assert(ev.Key, check.DeepEquals, []byte("a")) 218 ev = <-plr.Output() 219 c.Assert(ev.OpType, check.Equals, model.OpTypePut) 220 c.Assert(ev.Key, check.DeepEquals, []byte("d")) 221 222 store.Close() 223 cancel() 224 wg.Wait() 225 }