github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/notify/notify_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 notify 15 16 import ( 17 "context" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/pingcap/tiflow/pkg/errors" 23 "github.com/stretchr/testify/require" 24 "go.uber.org/atomic" 25 ) 26 27 func TestNotifyHub(t *testing.T) { 28 t.Parallel() 29 30 notifier := new(Notifier) 31 r1, err := notifier.NewReceiver(-1) 32 require.Nil(t, err) 33 r2, err := notifier.NewReceiver(-1) 34 require.Nil(t, err) 35 r3, err := notifier.NewReceiver(-1) 36 require.Nil(t, err) 37 finishedCh := make(chan struct{}) 38 go func() { 39 for i := 0; i < 5; i++ { 40 time.Sleep(time.Second) 41 notifier.Notify() 42 } 43 close(finishedCh) 44 }() 45 <-r1.C 46 r1.Stop() 47 <-r2.C 48 <-r3.C 49 50 r2.Stop() 51 r3.Stop() 52 require.Equal(t, 0, len(notifier.receivers)) 53 r4, err := notifier.NewReceiver(-1) 54 require.Nil(t, err) 55 <-r4.C 56 r4.Stop() 57 58 notifier2 := new(Notifier) 59 r5, err := notifier2.NewReceiver(10 * time.Millisecond) 60 require.Nil(t, err) 61 <-r5.C 62 r5.Stop() 63 <-finishedCh // To make the leak checker happy 64 } 65 66 func TestContinusStop(t *testing.T) { 67 t.Parallel() 68 69 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 70 defer cancel() 71 notifier := new(Notifier) 72 go func() { 73 for { 74 select { 75 case <-ctx.Done(): 76 return 77 default: 78 } 79 notifier.Notify() 80 } 81 }() 82 n := 50 83 receivers := make([]*Receiver, n) 84 var err error 85 for i := 0; i < n; i++ { 86 receivers[i], err = notifier.NewReceiver(10 * time.Millisecond) 87 require.Nil(t, err) 88 } 89 for i := 0; i < n; i++ { 90 i := i 91 go func() { 92 for { 93 select { 94 case <-ctx.Done(): 95 return 96 case <-receivers[i].C: 97 } 98 } 99 }() 100 } 101 for i := 0; i < n; i++ { 102 receivers[i].Stop() 103 } 104 <-ctx.Done() 105 } 106 107 func TestNewReceiverWithClosedNotifier(t *testing.T) { 108 t.Parallel() 109 110 notifier := new(Notifier) 111 notifier.Close() 112 _, err := notifier.NewReceiver(50 * time.Millisecond) 113 require.True(t, errors.ErrOperateOnClosedNotifier.Equal(err)) 114 } 115 116 func TestNotifierMultiple(t *testing.T) { 117 t.Parallel() 118 notifier := new(Notifier) 119 120 receiver, err := notifier.NewReceiver(-1) 121 require.NoError(t, err) 122 counter := atomic.NewInt32(0) 123 124 var wg sync.WaitGroup 125 wg.Add(1) 126 go func() { 127 defer wg.Done() 128 for { 129 _, ok := <-receiver.C 130 if !ok { 131 return 132 } 133 counter.Add(1) 134 } 135 }() 136 137 receiver1, err := notifier.NewReceiver(time.Minute) 138 require.NoError(t, err) 139 counter1 := atomic.NewInt32(0) 140 141 wg.Add(1) 142 go func() { 143 defer wg.Done() 144 for { 145 _, ok := <-receiver1.C 146 if !ok { 147 return 148 } 149 counter1.Add(1) 150 } 151 }() 152 153 N := 5 154 for i := 0; i < N; i++ { 155 notifier.Notify() 156 time.Sleep(time.Millisecond * 100) 157 } 158 159 notifier.Close() 160 wg.Wait() 161 require.LessOrEqual(t, counter.Load(), int32(N)) 162 require.LessOrEqual(t, counter1.Load(), int32(N)) 163 }