github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/xsync/event_broadcast_test.go (about) 1 package xsync 2 3 import ( 4 "runtime" 5 "sync/atomic" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/ydb-platform/ydb-go-sdk/v3/internal/empty" 12 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" 13 ) 14 15 func TestEventBroadcast(t *testing.T) { 16 t.Run("Simple", func(t *testing.T) { 17 b := &EventBroadcast{} 18 waiter := b.Waiter() 19 b.Broadcast() 20 xtest.WaitChannelClosed(t, waiter.Done()) 21 }) 22 23 xtest.TestManyTimesWithName(t, "SubscribeAndEventsInRace", func(t testing.TB) { 24 testDuration := time.Second / 100 25 26 b := &EventBroadcast{} 27 var events atomic.Int64 28 29 var backgroundCounter atomic.Int64 30 firstWaiterStarted := atomic.Bool{} 31 32 stopSubscribe := atomic.Bool{} 33 34 subscribeStopped := make(empty.Chan) 35 broadcastStopped := make(empty.Chan) 36 37 // Add subscribers 38 go func() { 39 defer close(subscribeStopped) 40 for { 41 backgroundCounter.Add(1) 42 waiter := b.Waiter() 43 firstWaiterStarted.Store(true) 44 go func() { 45 <-waiter.Done() 46 backgroundCounter.Add(-1) 47 }() 48 if stopSubscribe.Load() { 49 return 50 } 51 } 52 }() 53 54 stopBroadcast := atomic.Bool{} 55 go func() { 56 defer close(broadcastStopped) 57 58 // Fire events 59 for { 60 events.Add(1) 61 b.Broadcast() 62 runtime.Gosched() 63 if stopBroadcast.Load() { 64 return 65 } 66 } 67 }() 68 69 xtest.SpinWaitCondition(t, nil, firstWaiterStarted.Load) 70 71 <-time.After(testDuration) 72 73 stopSubscribe.Store(true) 74 <-subscribeStopped 75 76 for { 77 oldCounter := backgroundCounter.Load() 78 if oldCounter == 0 { 79 break 80 } 81 82 t.Log("background counter", oldCounter) 83 xtest.SpinWaitCondition(t, nil, func() bool { 84 return backgroundCounter.Load() < oldCounter 85 }) 86 } 87 stopBroadcast.Store(true) 88 <-broadcastStopped 89 90 require.Greater(t, events.Load(), int64(0)) 91 }) 92 }