@@ -19,6 +19,7 @@ import (
1919 "testing"
2020 "time"
2121
22+ "github.com/pingcap/failpoint"
2223 "github.com/pingcap/kvproto/pkg/cdcpb"
2324 "github.com/pingcap/tidb/pkg/store/mockstore/mockcopr"
2425 "github.com/pingcap/tiflow/cdc/kv/regionlock"
@@ -212,6 +213,105 @@ func TestConnectToOfflineOrFailedTiKV(t *testing.T) {
212213 }
213214}
214215
216+ func TestGetStoreFailed (t * testing.T ) {
217+ ctx , cancel := context .WithCancel (context .Background ())
218+ wg := & sync.WaitGroup {}
219+
220+ events1 := make (chan * cdcpb.ChangeDataEvent , 10 )
221+ srv1 := newMockChangeDataServer (events1 )
222+ server1 , addr1 := newMockService (ctx , t , srv1 , wg )
223+
224+ rpcClient , cluster , pdClient , _ := testutils .NewMockTiKV ("" , mockcopr .NewCoprRPCHandler ())
225+
226+ pdClient = & mockPDClient {Client : pdClient , versionGen : defaultVersionGen }
227+
228+ grpcPool := sharedconn .NewConnAndClientPool (& security.Credential {}, nil )
229+
230+ regionCache := tikv .NewRegionCache (pdClient )
231+
232+ pdClock := pdutil .NewClock4Test ()
233+
234+ kvStorage , err := tikv .NewTestTiKVStore (rpcClient , pdClient , nil , nil , 0 )
235+ require .Nil (t , err )
236+ lockResolver := txnutil .NewLockerResolver (kvStorage , model.ChangeFeedID {})
237+
238+ invalidStore1 := "localhost:1"
239+ invalidStore2 := "localhost:2"
240+ cluster .AddStore (1 , addr1 )
241+ cluster .AddStore (2 , invalidStore1 )
242+ cluster .AddStore (3 , invalidStore2 )
243+ cluster .Bootstrap (11 , []uint64 {1 , 2 , 3 }, []uint64 {4 , 5 , 6 }, 4 )
244+
245+ client := NewSharedClient (
246+ model.ChangeFeedID {ID : "test" },
247+ & config.ServerConfig {
248+ KVClient : & config.KVClientConfig {
249+ WorkerConcurrent : 1 ,
250+ GrpcStreamConcurrent : 1 ,
251+ AdvanceIntervalInMs : 10 ,
252+ },
253+ Debug : & config.DebugConfig {Puller : & config.PullerConfig {}},
254+ },
255+ false , pdClient , grpcPool , regionCache , pdClock , lockResolver ,
256+ )
257+
258+ defer func () {
259+ cancel ()
260+ client .Close ()
261+ _ = kvStorage .Close ()
262+ regionCache .Close ()
263+ pdClient .Close ()
264+ srv1 .wg .Wait ()
265+ server1 .Stop ()
266+ wg .Wait ()
267+ }()
268+
269+ wg .Add (1 )
270+ go func () {
271+ defer wg .Done ()
272+ err := client .Run (ctx )
273+ require .Equal (t , context .Canceled , errors .Cause (err ))
274+ }()
275+
276+ failpoint .Enable ("github.com/pingcap/tiflow/pkg/version/GetStoreFailed" , `return(true)` )
277+ subID := client .AllocSubscriptionID ()
278+ span := tablepb.Span {TableID : 1 , StartKey : []byte ("a" ), EndKey : []byte ("b" )}
279+ eventCh := make (chan MultiplexingEvent , 50 )
280+ client .Subscribe (subID , span , 1 , eventCh )
281+
282+ makeTsEvent := func (regionID , ts , requestID uint64 ) * cdcpb.ChangeDataEvent {
283+ return & cdcpb.ChangeDataEvent {
284+ Events : []* cdcpb.Event {
285+ {
286+ RegionId : regionID ,
287+ RequestId : requestID ,
288+ Event : & cdcpb.Event_ResolvedTs {ResolvedTs : ts },
289+ },
290+ },
291+ }
292+ }
293+
294+ checkTsEvent := func (event model.RegionFeedEvent , ts uint64 ) {
295+ require .Equal (t , ts , event .Resolved .ResolvedTs )
296+ }
297+
298+ events1 <- mockInitializedEvent (11 , uint64 (subID ))
299+ ts := oracle .GoTimeToTS (pdClock .CurrentTime ())
300+ events1 <- makeTsEvent (11 , ts , uint64 (subID ))
301+ select {
302+ case <- eventCh :
303+ require .True (t , false , "should not get event when get store failed" )
304+ case <- time .After (5 * time .Second ):
305+ }
306+ failpoint .Disable ("github.com/pingcap/tiflow/pkg/version/GetStoreFailed" )
307+ select {
308+ case event := <- eventCh :
309+ checkTsEvent (event .RegionFeedEvent , ts )
310+ case <- time .After (5 * time .Second ):
311+ require .True (t , false , "reconnection not succeed in 5 second" )
312+ }
313+ }
314+
215315type mockChangeDataServer struct {
216316 ch chan * cdcpb.ChangeDataEvent
217317 wg sync.WaitGroup
0 commit comments