github.com/theQRL/go-zond@v0.1.1/event/feed_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package event 18 19 import ( 20 "errors" 21 "fmt" 22 "reflect" 23 "sync" 24 "testing" 25 "time" 26 ) 27 28 func TestFeedPanics(t *testing.T) { 29 { 30 var f Feed 31 f.Send(2) 32 want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(0)} 33 if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil { 34 t.Error(err) 35 } 36 } 37 { 38 var f Feed 39 ch := make(chan int) 40 f.Subscribe(ch) 41 want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(0)} 42 if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil { 43 t.Error(err) 44 } 45 } 46 { 47 var f Feed 48 f.Send(2) 49 want := feedTypeError{op: "Subscribe", got: reflect.TypeOf(make(chan uint64)), want: reflect.TypeOf(make(chan<- int))} 50 if err := checkPanic(want, func() { f.Subscribe(make(chan uint64)) }); err != nil { 51 t.Error(err) 52 } 53 } 54 { 55 var f Feed 56 if err := checkPanic(errBadChannel, func() { f.Subscribe(make(<-chan int)) }); err != nil { 57 t.Error(err) 58 } 59 } 60 { 61 var f Feed 62 if err := checkPanic(errBadChannel, func() { f.Subscribe(0) }); err != nil { 63 t.Error(err) 64 } 65 } 66 } 67 68 func checkPanic(want error, fn func()) (err error) { 69 defer func() { 70 panic := recover() 71 if panic == nil { 72 err = errors.New("didn't panic") 73 } else if !reflect.DeepEqual(panic, want) { 74 err = fmt.Errorf("panicked with wrong error: got %q, want %q", panic, want) 75 } 76 }() 77 fn() 78 return nil 79 } 80 81 func TestFeed(t *testing.T) { 82 var feed Feed 83 var done, subscribed sync.WaitGroup 84 subscriber := func(i int) { 85 defer done.Done() 86 87 subchan := make(chan int) 88 sub := feed.Subscribe(subchan) 89 timeout := time.NewTimer(2 * time.Second) 90 defer timeout.Stop() 91 subscribed.Done() 92 93 select { 94 case v := <-subchan: 95 if v != 1 { 96 t.Errorf("%d: received value %d, want 1", i, v) 97 } 98 case <-timeout.C: 99 t.Errorf("%d: receive timeout", i) 100 } 101 102 sub.Unsubscribe() 103 select { 104 case _, ok := <-sub.Err(): 105 if ok { 106 t.Errorf("%d: error channel not closed after unsubscribe", i) 107 } 108 case <-timeout.C: 109 t.Errorf("%d: unsubscribe timeout", i) 110 } 111 } 112 113 const n = 1000 114 done.Add(n) 115 subscribed.Add(n) 116 for i := 0; i < n; i++ { 117 go subscriber(i) 118 } 119 subscribed.Wait() 120 if nsent := feed.Send(1); nsent != n { 121 t.Errorf("first send delivered %d times, want %d", nsent, n) 122 } 123 if nsent := feed.Send(2); nsent != 0 { 124 t.Errorf("second send delivered %d times, want 0", nsent) 125 } 126 done.Wait() 127 } 128 129 func TestFeedSubscribeSameChannel(t *testing.T) { 130 var ( 131 feed Feed 132 done sync.WaitGroup 133 ch = make(chan int) 134 sub1 = feed.Subscribe(ch) 135 sub2 = feed.Subscribe(ch) 136 _ = feed.Subscribe(ch) 137 ) 138 expectSends := func(value, n int) { 139 if nsent := feed.Send(value); nsent != n { 140 t.Errorf("send delivered %d times, want %d", nsent, n) 141 } 142 done.Done() 143 } 144 expectRecv := func(wantValue, n int) { 145 for i := 0; i < n; i++ { 146 if v := <-ch; v != wantValue { 147 t.Errorf("received %d, want %d", v, wantValue) 148 } 149 } 150 } 151 152 done.Add(1) 153 go expectSends(1, 3) 154 expectRecv(1, 3) 155 done.Wait() 156 157 sub1.Unsubscribe() 158 159 done.Add(1) 160 go expectSends(2, 2) 161 expectRecv(2, 2) 162 done.Wait() 163 164 sub2.Unsubscribe() 165 166 done.Add(1) 167 go expectSends(3, 1) 168 expectRecv(3, 1) 169 done.Wait() 170 } 171 172 func TestFeedSubscribeBlockedPost(t *testing.T) { 173 var ( 174 feed Feed 175 nsends = 2000 176 ch1 = make(chan int) 177 ch2 = make(chan int) 178 wg sync.WaitGroup 179 ) 180 defer wg.Wait() 181 182 feed.Subscribe(ch1) 183 wg.Add(nsends) 184 for i := 0; i < nsends; i++ { 185 go func() { 186 feed.Send(99) 187 wg.Done() 188 }() 189 } 190 191 sub2 := feed.Subscribe(ch2) 192 defer sub2.Unsubscribe() 193 194 // We're done when ch1 has received N times. 195 // The number of receives on ch2 depends on scheduling. 196 for i := 0; i < nsends; { 197 select { 198 case <-ch1: 199 i++ 200 case <-ch2: 201 } 202 } 203 } 204 205 func TestFeedUnsubscribeBlockedPost(t *testing.T) { 206 var ( 207 feed Feed 208 nsends = 200 209 chans = make([]chan int, 2000) 210 subs = make([]Subscription, len(chans)) 211 bchan = make(chan int) 212 bsub = feed.Subscribe(bchan) 213 wg sync.WaitGroup 214 ) 215 for i := range chans { 216 chans[i] = make(chan int, nsends) 217 } 218 219 // Queue up some Sends. None of these can make progress while bchan isn't read. 220 wg.Add(nsends) 221 for i := 0; i < nsends; i++ { 222 go func() { 223 feed.Send(99) 224 wg.Done() 225 }() 226 } 227 // Subscribe the other channels. 228 for i, ch := range chans { 229 subs[i] = feed.Subscribe(ch) 230 } 231 // Unsubscribe them again. 232 for _, sub := range subs { 233 sub.Unsubscribe() 234 } 235 // Unblock the Sends. 236 bsub.Unsubscribe() 237 wg.Wait() 238 } 239 240 // Checks that unsubscribing a channel during Send works even if that 241 // channel has already been sent on. 242 func TestFeedUnsubscribeSentChan(t *testing.T) { 243 var ( 244 feed Feed 245 ch1 = make(chan int) 246 ch2 = make(chan int) 247 sub1 = feed.Subscribe(ch1) 248 sub2 = feed.Subscribe(ch2) 249 wg sync.WaitGroup 250 ) 251 defer sub2.Unsubscribe() 252 253 wg.Add(1) 254 go func() { 255 feed.Send(0) 256 wg.Done() 257 }() 258 259 // Wait for the value on ch1. 260 <-ch1 261 // Unsubscribe ch1, removing it from the send cases. 262 sub1.Unsubscribe() 263 264 // Receive ch2, finishing Send. 265 <-ch2 266 wg.Wait() 267 268 // Send again. This should send to ch2 only, so the wait group will unblock 269 // as soon as a value is received on ch2. 270 wg.Add(1) 271 go func() { 272 feed.Send(0) 273 wg.Done() 274 }() 275 <-ch2 276 wg.Wait() 277 } 278 279 func TestFeedUnsubscribeFromInbox(t *testing.T) { 280 var ( 281 feed Feed 282 ch1 = make(chan int) 283 ch2 = make(chan int) 284 sub1 = feed.Subscribe(ch1) 285 sub2 = feed.Subscribe(ch1) 286 sub3 = feed.Subscribe(ch2) 287 ) 288 if len(feed.inbox) != 3 { 289 t.Errorf("inbox length != 3 after subscribe") 290 } 291 if len(feed.sendCases) != 1 { 292 t.Errorf("sendCases is non-empty after unsubscribe") 293 } 294 295 sub1.Unsubscribe() 296 sub2.Unsubscribe() 297 sub3.Unsubscribe() 298 if len(feed.inbox) != 0 { 299 t.Errorf("inbox is non-empty after unsubscribe") 300 } 301 if len(feed.sendCases) != 1 { 302 t.Errorf("sendCases is non-empty after unsubscribe") 303 } 304 } 305 306 func BenchmarkFeedSend1000(b *testing.B) { 307 var ( 308 done sync.WaitGroup 309 feed Feed 310 nsubs = 1000 311 ) 312 subscriber := func(ch <-chan int) { 313 for i := 0; i < b.N; i++ { 314 <-ch 315 } 316 done.Done() 317 } 318 done.Add(nsubs) 319 for i := 0; i < nsubs; i++ { 320 ch := make(chan int, 200) 321 feed.Subscribe(ch) 322 go subscriber(ch) 323 } 324 325 // The actual benchmark. 326 b.ResetTimer() 327 for i := 0; i < b.N; i++ { 328 if feed.Send(i) != nsubs { 329 panic("wrong number of sends") 330 } 331 } 332 333 b.StopTimer() 334 done.Wait() 335 }