github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/async/async_initializer_test.go (about) 1 // Copyright 2024 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 async 15 16 import ( 17 "context" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/pingcap/errors" 23 "github.com/pingcap/tiflow/cdc/vars" 24 "github.com/stretchr/testify/require" 25 "go.uber.org/atomic" 26 ) 27 28 type fakePool struct { 29 f func() 30 submitErr error 31 submitTimes int 32 } 33 34 func (f *fakePool) Go(_ context.Context, fn func()) error { 35 f.f = fn 36 f.submitTimes++ 37 return f.submitErr 38 } 39 40 func (f *fakePool) Run(_ context.Context) error { 41 return nil 42 } 43 44 func TestTryInitialize(t *testing.T) { 45 initializer := NewInitializer() 46 pool := &vars.NonAsyncPool{} 47 initialized, err := initializer.TryInitialize(context.Background(), 48 func(ctx context.Context) error { 49 return nil 50 }, pool) 51 require.Nil(t, err) 52 require.True(t, initialized) 53 // Try to initialize again 54 initialized, err = initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 55 return nil 56 }, pool) 57 require.Nil(t, err) 58 require.True(t, initialized) 59 // init failed 60 initializer = NewInitializer() 61 initialized, err = initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 62 return errors.New("failed to init") 63 }, pool) 64 require.NotNil(t, err) 65 require.False(t, initializer.initialized.Load()) 66 require.True(t, initializer.initializing.Load()) 67 require.False(t, initialized) 68 initialized, err = initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 69 return errors.New("failed to init") 70 }, pool) 71 require.NotNil(t, err) 72 require.False(t, initializer.initialized.Load()) 73 require.True(t, initializer.initializing.Load()) 74 require.False(t, initialized) 75 76 // test submit error 77 initializer = NewInitializer() 78 initialized, err = initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 79 return nil 80 }, &fakePool{submitErr: errors.New("submit error")}) 81 require.NotNil(t, err) 82 require.False(t, initialized) 83 require.False(t, initializer.initialized.Load()) 84 require.True(t, initializer.initializing.Load()) 85 } 86 87 func TestTerminate(t *testing.T) { 88 initializer := NewInitializer() 89 pool := &vars.NonAsyncPool{} 90 initialized, err := initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 91 return nil 92 }, pool) 93 require.Nil(t, err) 94 require.True(t, initialized) 95 initializer.Terminate() 96 require.False(t, initializer.initialized.Load()) 97 require.False(t, initializer.initializing.Load()) 98 99 // test submit error 100 initializer = NewInitializer() 101 fpool := &fakePool{} 102 initialized, err = initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 103 return nil 104 }, fpool) 105 require.Nil(t, err) 106 require.False(t, initialized) 107 require.True(t, initializer.initializing.Load()) 108 require.Equal(t, 1, fpool.submitTimes) 109 110 initialized, err = initializer.TryInitialize(context.Background(), func(ctx context.Context) error { 111 return nil 112 }, fpool) 113 require.Nil(t, err) 114 require.False(t, initialized) 115 require.True(t, initializer.initializing.Load()) 116 require.Equal(t, 1, fpool.submitTimes) 117 118 wg := sync.WaitGroup{} 119 wg.Add(1) 120 terminated := atomic.NewInt32(1) 121 go func() { 122 defer wg.Done() 123 initializer.Terminate() 124 require.Equal(t, int32(2), terminated.Swap(3)) 125 }() 126 require.Equal(t, int32(1), terminated.Swap(2)) 127 time.Sleep(1 * time.Second) 128 fpool.f() 129 wg.Wait() 130 require.Equal(t, int32(3), terminated.Load()) 131 }