github.com/searKing/golang/go@v1.2.117/sync/subject_test.go (about) 1 // Copyright 2022 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 package sync_test 5 6 import ( 7 "context" 8 "errors" 9 "sync" 10 "testing" 11 "time" 12 13 sync_ "github.com/searKing/golang/go/sync" 14 ) 15 16 func TestSubject_PublishSignal(t *testing.T) { 17 var s sync_.Subject 18 n := 2 19 awake := make(chan bool, n) 20 var wg sync.WaitGroup 21 eventC, _ := s.Subscribe() 22 for i := 0; i < n; i++ { 23 wg.Add(1) 24 go func() { 25 wg.Done() 26 <-eventC 27 awake <- true 28 }() 29 } 30 // Wait for everyone to run. 31 wg.Wait() 32 33 for n > 0 { 34 select { 35 case <-awake: 36 t.Fatal("goroutine not asleep") 37 default: 38 } 39 go func() { 40 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 41 defer cancel() 42 err := s.PublishSignal(ctx, nil) 43 if err != nil { 44 t.Fatalf("PublishSignal: %s", err) 45 return 46 } 47 }() 48 <-awake // Will deadlock if no goroutine wakes up 49 select { 50 case <-awake: 51 t.Fatal("too many goroutines awake") 52 default: 53 } 54 n-- 55 } 56 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 57 defer cancel() 58 err := s.PublishSignal(ctx, nil) 59 if !errors.Is(err, context.DeadlineExceeded) { 60 t.Fatalf("PublishSignal: %s", err) 61 return 62 } 63 } 64 65 func TestSubject_PublishBroadcast(t *testing.T) { 66 s := sync_.Subject{} 67 n := 2 68 awake := make(chan bool, n) 69 var wg sync.WaitGroup 70 for i := 0; i < n; i++ { 71 eventC, _ := s.Subscribe() 72 wg.Add(1) 73 go func() { 74 wg.Done() 75 <-eventC 76 awake <- true 77 }() 78 } 79 // Wait for everyone to run. 80 wg.Wait() 81 { 82 select { 83 case <-awake: 84 t.Fatal("goroutine not asleep") 85 default: 86 } 87 go func() { 88 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 89 defer cancel() 90 err := s.PublishBroadcast(ctx, nil) 91 if err != nil { 92 t.Fatalf("PublishBroadcast: %s", err) 93 return 94 } 95 }() 96 for n > 0 { 97 <-awake // Will deadlock if no goroutine wakes up 98 n-- 99 } 100 select { 101 case <-awake: 102 t.Fatal("too many goroutines awake") 103 default: 104 } 105 } 106 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 107 defer cancel() 108 err := s.PublishBroadcast(ctx, nil) 109 if !errors.Is(err, context.DeadlineExceeded) { 110 t.Fatalf("PublishBroadcast: %s", err) 111 return 112 } 113 } 114 115 func TestSubject_PublishBroadcastDeadLock(t *testing.T) { 116 s := sync_.Subject{} 117 func() { 118 eventC, cancel := s.Subscribe() 119 go func() { 120 defer cancel() 121 <-eventC 122 }() 123 }() 124 err := s.PublishBroadcast(context.Background(), struct{}{}) 125 if err != nil { 126 t.Errorf("PublishBroadcast: %s", err) 127 return 128 } 129 }