github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/event/feed_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:38</date> 10 //</624450091108798464> 11 12 13 package event 14 15 import ( 16 "fmt" 17 "reflect" 18 "sync" 19 "testing" 20 "time" 21 ) 22 23 func TestFeedPanics(t *testing.T) { 24 { 25 var f Feed 26 f.Send(int(2)) 27 want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(int(0))} 28 if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil { 29 t.Error(err) 30 } 31 } 32 { 33 var f Feed 34 ch := make(chan int) 35 f.Subscribe(ch) 36 want := feedTypeError{op: "Send", got: reflect.TypeOf(uint64(0)), want: reflect.TypeOf(int(0))} 37 if err := checkPanic(want, func() { f.Send(uint64(2)) }); err != nil { 38 t.Error(err) 39 } 40 } 41 { 42 var f Feed 43 f.Send(int(2)) 44 want := feedTypeError{op: "Subscribe", got: reflect.TypeOf(make(chan uint64)), want: reflect.TypeOf(make(chan<- int))} 45 if err := checkPanic(want, func() { f.Subscribe(make(chan uint64)) }); err != nil { 46 t.Error(err) 47 } 48 } 49 { 50 var f Feed 51 if err := checkPanic(errBadChannel, func() { f.Subscribe(make(<-chan int)) }); err != nil { 52 t.Error(err) 53 } 54 } 55 { 56 var f Feed 57 if err := checkPanic(errBadChannel, func() { f.Subscribe(int(0)) }); err != nil { 58 t.Error(err) 59 } 60 } 61 } 62 63 func checkPanic(want error, fn func()) (err error) { 64 defer func() { 65 panic := recover() 66 if panic == nil { 67 err = fmt.Errorf("didn't panic") 68 } else if !reflect.DeepEqual(panic, want) { 69 err = fmt.Errorf("panicked with wrong error: got %q, want %q", panic, want) 70 } 71 }() 72 fn() 73 return nil 74 } 75 76 func TestFeed(t *testing.T) { 77 var feed Feed 78 var done, subscribed sync.WaitGroup 79 subscriber := func(i int) { 80 defer done.Done() 81 82 subchan := make(chan int) 83 sub := feed.Subscribe(subchan) 84 timeout := time.NewTimer(2 * time.Second) 85 subscribed.Done() 86 87 select { 88 case v := <-subchan: 89 if v != 1 { 90 t.Errorf("%d: received value %d, want 1", i, v) 91 } 92 case <-timeout.C: 93 t.Errorf("%d: receive timeout", i) 94 } 95 96 sub.Unsubscribe() 97 select { 98 case _, ok := <-sub.Err(): 99 if ok { 100 t.Errorf("%d: error channel not closed after unsubscribe", i) 101 } 102 case <-timeout.C: 103 t.Errorf("%d: unsubscribe timeout", i) 104 } 105 } 106 107 const n = 1000 108 done.Add(n) 109 subscribed.Add(n) 110 for i := 0; i < n; i++ { 111 go subscriber(i) 112 } 113 subscribed.Wait() 114 if nsent := feed.Send(1); nsent != n { 115 t.Errorf("first send delivered %d times, want %d", nsent, n) 116 } 117 if nsent := feed.Send(2); nsent != 0 { 118 t.Errorf("second send delivered %d times, want 0", nsent) 119 } 120 done.Wait() 121 } 122 123 func TestFeedSubscribeSameChannel(t *testing.T) { 124 var ( 125 feed Feed 126 done sync.WaitGroup 127 ch = make(chan int) 128 sub1 = feed.Subscribe(ch) 129 sub2 = feed.Subscribe(ch) 130 _ = feed.Subscribe(ch) 131 ) 132 expectSends := func(value, n int) { 133 if nsent := feed.Send(value); nsent != n { 134 t.Errorf("send delivered %d times, want %d", nsent, n) 135 } 136 done.Done() 137 } 138 expectRecv := func(wantValue, n int) { 139 for i := 0; i < n; i++ { 140 if v := <-ch; v != wantValue { 141 t.Errorf("received %d, want %d", v, wantValue) 142 } 143 } 144 } 145 146 done.Add(1) 147 go expectSends(1, 3) 148 expectRecv(1, 3) 149 done.Wait() 150 151 sub1.Unsubscribe() 152 153 done.Add(1) 154 go expectSends(2, 2) 155 expectRecv(2, 2) 156 done.Wait() 157 158 sub2.Unsubscribe() 159 160 done.Add(1) 161 go expectSends(3, 1) 162 expectRecv(3, 1) 163 done.Wait() 164 } 165 166 func TestFeedSubscribeBlockedPost(t *testing.T) { 167 var ( 168 feed Feed 169 nsends = 2000 170 ch1 = make(chan int) 171 ch2 = make(chan int) 172 wg sync.WaitGroup 173 ) 174 defer wg.Wait() 175 176 feed.Subscribe(ch1) 177 wg.Add(nsends) 178 for i := 0; i < nsends; i++ { 179 go func() { 180 feed.Send(99) 181 wg.Done() 182 }() 183 } 184 185 sub2 := feed.Subscribe(ch2) 186 defer sub2.Unsubscribe() 187 188 //当ch1收到n次时,我们就完成了。 189 //CH2上的接收数取决于调度。 190 for i := 0; i < nsends; { 191 select { 192 case <-ch1: 193 i++ 194 case <-ch2: 195 } 196 } 197 } 198 199 func TestFeedUnsubscribeBlockedPost(t *testing.T) { 200 var ( 201 feed Feed 202 nsends = 200 203 chans = make([]chan int, 2000) 204 subs = make([]Subscription, len(chans)) 205 bchan = make(chan int) 206 bsub = feed.Subscribe(bchan) 207 wg sync.WaitGroup 208 ) 209 for i := range chans { 210 chans[i] = make(chan int, nsends) 211 } 212 213 //排队发送一些邮件。当bchan不被读取时,这些都不能取得进展。 214 wg.Add(nsends) 215 for i := 0; i < nsends; i++ { 216 go func() { 217 feed.Send(99) 218 wg.Done() 219 }() 220 } 221 //订阅其他频道。 222 for i, ch := range chans { 223 subs[i] = feed.Subscribe(ch) 224 } 225 //再次取消订阅。 226 for _, sub := range subs { 227 sub.Unsubscribe() 228 } 229 //取消阻止发送。 230 bsub.Unsubscribe() 231 wg.Wait() 232 } 233 234 //检查在发送期间取消订阅频道是否有效 235 //频道已发送。 236 func TestFeedUnsubscribeSentChan(t *testing.T) { 237 var ( 238 feed Feed 239 ch1 = make(chan int) 240 ch2 = make(chan int) 241 sub1 = feed.Subscribe(ch1) 242 sub2 = feed.Subscribe(ch2) 243 wg sync.WaitGroup 244 ) 245 defer sub2.Unsubscribe() 246 247 wg.Add(1) 248 go func() { 249 feed.Send(0) 250 wg.Done() 251 }() 252 253 //等待ch1上的值。 254 <-ch1 255 //取消订阅ch1,将其从发送案例中删除。 256 sub1.Unsubscribe() 257 258 //接收CH2,完成发送。 259 <-ch2 260 wg.Wait() 261 262 //再发一次。这应该只发送到ch2,因此等待组将取消阻止 263 //一旦收到CH2上的值。 264 wg.Add(1) 265 go func() { 266 feed.Send(0) 267 wg.Done() 268 }() 269 <-ch2 270 wg.Wait() 271 } 272 273 func TestFeedUnsubscribeFromInbox(t *testing.T) { 274 var ( 275 feed Feed 276 ch1 = make(chan int) 277 ch2 = make(chan int) 278 sub1 = feed.Subscribe(ch1) 279 sub2 = feed.Subscribe(ch1) 280 sub3 = feed.Subscribe(ch2) 281 ) 282 if len(feed.inbox) != 3 { 283 t.Errorf("inbox length != 3 after subscribe") 284 } 285 if len(feed.sendCases) != 1 { 286 t.Errorf("sendCases is non-empty after unsubscribe") 287 } 288 289 sub1.Unsubscribe() 290 sub2.Unsubscribe() 291 sub3.Unsubscribe() 292 if len(feed.inbox) != 0 { 293 t.Errorf("inbox is non-empty after unsubscribe") 294 } 295 if len(feed.sendCases) != 1 { 296 t.Errorf("sendCases is non-empty after unsubscribe") 297 } 298 } 299 300 func BenchmarkFeedSend1000(b *testing.B) { 301 var ( 302 done sync.WaitGroup 303 feed Feed 304 nsubs = 1000 305 ) 306 subscriber := func(ch <-chan int) { 307 for i := 0; i < b.N; i++ { 308 <-ch 309 } 310 done.Done() 311 } 312 done.Add(nsubs) 313 for i := 0; i < nsubs; i++ { 314 ch := make(chan int, 200) 315 feed.Subscribe(ch) 316 go subscriber(ch) 317 } 318 319 //实际基准。 320 b.ResetTimer() 321 for i := 0; i < b.N; i++ { 322 if feed.Send(i) != nsubs { 323 panic("wrong number of sends") 324 } 325 } 326 327 b.StopTimer() 328 done.Wait() 329 } 330