github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/event/feed_test.go (about) 1 package event 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 "testing" 8 "time" 9 ) 10 11 func TestFeedPanics(t *testing.T) { 12 { 13 var f Feed 14 f.Send(int(2)) 15 want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(int(0))} 16 if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil { 17 t.Error(err) 18 } 19 } 20 { 21 var f Feed 22 ch := make(chan int) 23 f.Subscribe(ch) 24 want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(int(0))} 25 if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil { 26 t.Error(err) 27 } 28 } 29 { 30 var f Feed 31 f.Send(int(2)) 32 want := feedTypeError{op: "Subscribe", got: reflect.TypeOf(make(chan uint64)), want: reflect.TypeOf(make(chan<- int))} 33 if err := checkPanic(want, func() { f.Subscribe(make(chan uint64)) }); err != nil { 34 t.Error(err) 35 } 36 } 37 { 38 var f Feed 39 if err := checkPanic(errBadChannel, func() { f.Subscribe(make(<-chan int)) }); err != nil { 40 t.Error(err) 41 } 42 } 43 { 44 var f Feed 45 if err := checkPanic(errBadChannel, func() { f.Subscribe(int(0)) }); err != nil { 46 t.Error(err) 47 } 48 } 49 } 50 51 func checkPanic(want error, fn func()) (err error) { 52 defer func() { 53 panic := recover() 54 if panic == nil { 55 err = fmt.Errorf("didn't panic") 56 } else if !reflect.DeepEqual(panic, want) { 57 err = fmt.Errorf("panicked with wrong error: got %q, want %q", panic, want) 58 } 59 }() 60 fn() 61 return nil 62 } 63 64 func TestFeed(t *testing.T) { 65 var feed Feed 66 var done, subscribed sync.WaitGroup 67 subscriber := func(i int) { 68 defer done.Done() 69 70 subchan := make(chan int) 71 sub := feed.Subscribe(subchan) 72 timeout := time.NewTimer(2 * time.Second) 73 subscribed.Done() 74 75 select { 76 case v := <-subchan: 77 if v != 1 { 78 t.Errorf("%d: received value %d, want 1", i, v) 79 } 80 case <-timeout.C: 81 t.Errorf("%d: receive timeout", i) 82 } 83 84 sub.Unsubscribe() 85 select { 86 case _, ok := <-sub.Err(): 87 if ok { 88 t.Errorf("%d: error channel not closed after unsubscribe", i) 89 } 90 case <-timeout.C: 91 t.Errorf("%d: unsubscribe timeout", i) 92 } 93 } 94 95 const n = 1000 96 done.Add(n) 97 subscribed.Add(n) 98 for i := 0; i < n; i++ { 99 go subscriber(i) 100 } 101 subscribed.Wait() 102 if nsent := feed.Send(1); nsent != n { 103 t.Errorf("first send delivered %d times, want %d", nsent, n) 104 } 105 if nsent := feed.Send(2); nsent != 0 { 106 t.Errorf("second send delivered %d times, want 0", nsent) 107 } 108 done.Wait() 109 } 110 111 func TestFeedSubscribeSameChannel(t *testing.T) { 112 var ( 113 feed Feed 114 done sync.WaitGroup 115 ch = make(chan int) 116 sub1 = feed.Subscribe(ch) 117 sub2 = feed.Subscribe(ch) 118 _ = feed.Subscribe(ch) 119 ) 120 expectSends := func(value, n int) { 121 if nsent := feed.Send(value); nsent != n { 122 t.Errorf("send delivered %d times, want %d", nsent, n) 123 } 124 done.Done() 125 } 126 expectRecv := func(wantValue, n int) { 127 for i := 0; i < n; i++ { 128 if v := <-ch; v != wantValue { 129 t.Errorf("received %d, want %d", v, wantValue) 130 } 131 } 132 } 133 134 done.Add(1) 135 go expectSends(1, 3) 136 expectRecv(1, 3) 137 done.Wait() 138 139 sub1.Unsubscribe() 140 141 done.Add(1) 142 go expectSends(2, 2) 143 expectRecv(2, 2) 144 done.Wait() 145 146 sub2.Unsubscribe() 147 148 done.Add(1) 149 go expectSends(3, 1) 150 expectRecv(3, 1) 151 done.Wait() 152 } 153 154 func TestFeedSubscribeBlockedPost(t *testing.T) { 155 var ( 156 feed Feed 157 nsends = 2000 158 ch1 = make(chan int) 159 ch2 = make(chan int) 160 wg sync.WaitGroup 161 ) 162 defer wg.Wait() 163 164 feed.Subscribe(ch1) 165 wg.Add(nsends) 166 for i := 0; i < nsends; i++ { 167 go func() { 168 feed.Send(99) 169 wg.Done() 170 }() 171 } 172 173 sub2 := feed.Subscribe(ch2) 174 defer sub2.Unsubscribe() 175 176 for i := 0; i < nsends; { 177 select { 178 case <-ch1: 179 i++ 180 case <-ch2: 181 } 182 } 183 } 184 185 func TestFeedUnsubscribeBlockedPost(t *testing.T) { 186 var ( 187 feed Feed 188 nsends = 200 189 chans = make([]chan int, 2000) 190 subs = make([]Subscription, len(chans)) 191 bchan = make(chan int) 192 bsub = feed.Subscribe(bchan) 193 wg sync.WaitGroup 194 ) 195 for i := range chans { 196 chans[i] = make(chan int, nsends) 197 } 198 199 wg.Add(nsends) 200 for i := 0; i < nsends; i++ { 201 go func() { 202 feed.Send(99) 203 wg.Done() 204 }() 205 } 206 207 for i, ch := range chans { 208 subs[i] = feed.Subscribe(ch) 209 } 210 211 for _, sub := range subs { 212 sub.Unsubscribe() 213 } 214 215 bsub.Unsubscribe() 216 wg.Wait() 217 } 218 219 func TestFeedUnsubscribeSentChan(t *testing.T) { 220 var ( 221 feed Feed 222 ch1 = make(chan int) 223 ch2 = make(chan int) 224 sub1 = feed.Subscribe(ch1) 225 sub2 = feed.Subscribe(ch2) 226 wg sync.WaitGroup 227 ) 228 defer sub2.Unsubscribe() 229 230 wg.Add(1) 231 go func() { 232 feed.Send(0) 233 wg.Done() 234 }() 235 236 <-ch1 237 238 sub1.Unsubscribe() 239 240 <-ch2 241 wg.Wait() 242 243 wg.Add(1) 244 go func() { 245 feed.Send(0) 246 wg.Done() 247 }() 248 <-ch2 249 wg.Wait() 250 } 251 252 func TestFeedUnsubscribeFromInbox(t *testing.T) { 253 var ( 254 feed Feed 255 ch1 = make(chan int) 256 ch2 = make(chan int) 257 sub1 = feed.Subscribe(ch1) 258 sub2 = feed.Subscribe(ch1) 259 sub3 = feed.Subscribe(ch2) 260 ) 261 if len(feed.inbox) != 3 { 262 t.Errorf("inbox length != 3 after subscribe") 263 } 264 if len(feed.sendCases) != 1 { 265 t.Errorf("sendCases is non-empty after unsubscribe") 266 } 267 268 sub1.Unsubscribe() 269 sub2.Unsubscribe() 270 sub3.Unsubscribe() 271 if len(feed.inbox) != 0 { 272 t.Errorf("inbox is non-empty after unsubscribe") 273 } 274 if len(feed.sendCases) != 1 { 275 t.Errorf("sendCases is non-empty after unsubscribe") 276 } 277 } 278 279 func BenchmarkFeedSend1000(b *testing.B) { 280 var ( 281 done sync.WaitGroup 282 feed Feed 283 nsubs = 1000 284 ) 285 subscriber := func(ch <-chan int) { 286 for i := 0; i < b.N; i++ { 287 <-ch 288 } 289 done.Done() 290 } 291 done.Add(nsubs) 292 for i := 0; i < nsubs; i++ { 293 ch := make(chan int, 200) 294 feed.Subscribe(ch) 295 go subscriber(ch) 296 } 297 298 b.ResetTimer() 299 for i := 0; i < b.N; i++ { 300 if feed.Send(i) != nsubs { 301 panic("wrong number of sends") 302 } 303 } 304 305 b.StopTimer() 306 done.Wait() 307 }