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