github.com/theQRL/go-zond@v0.1.1/event/feedof_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 "sync" 21 "testing" 22 "time" 23 ) 24 25 func TestFeedOf(t *testing.T) { 26 var feed FeedOf[int] 27 var done, subscribed sync.WaitGroup 28 subscriber := func(i int) { 29 defer done.Done() 30 31 subchan := make(chan int) 32 sub := feed.Subscribe(subchan) 33 timeout := time.NewTimer(2 * time.Second) 34 defer timeout.Stop() 35 subscribed.Done() 36 37 select { 38 case v := <-subchan: 39 if v != 1 { 40 t.Errorf("%d: received value %d, want 1", i, v) 41 } 42 case <-timeout.C: 43 t.Errorf("%d: receive timeout", i) 44 } 45 46 sub.Unsubscribe() 47 select { 48 case _, ok := <-sub.Err(): 49 if ok { 50 t.Errorf("%d: error channel not closed after unsubscribe", i) 51 } 52 case <-timeout.C: 53 t.Errorf("%d: unsubscribe timeout", i) 54 } 55 } 56 57 const n = 1000 58 done.Add(n) 59 subscribed.Add(n) 60 for i := 0; i < n; i++ { 61 go subscriber(i) 62 } 63 subscribed.Wait() 64 if nsent := feed.Send(1); nsent != n { 65 t.Errorf("first send delivered %d times, want %d", nsent, n) 66 } 67 if nsent := feed.Send(2); nsent != 0 { 68 t.Errorf("second send delivered %d times, want 0", nsent) 69 } 70 done.Wait() 71 } 72 73 func TestFeedOfSubscribeSameChannel(t *testing.T) { 74 var ( 75 feed FeedOf[int] 76 done sync.WaitGroup 77 ch = make(chan int) 78 sub1 = feed.Subscribe(ch) 79 sub2 = feed.Subscribe(ch) 80 _ = feed.Subscribe(ch) 81 ) 82 expectSends := func(value, n int) { 83 if nsent := feed.Send(value); nsent != n { 84 t.Errorf("send delivered %d times, want %d", nsent, n) 85 } 86 done.Done() 87 } 88 expectRecv := func(wantValue, n int) { 89 for i := 0; i < n; i++ { 90 if v := <-ch; v != wantValue { 91 t.Errorf("received %d, want %d", v, wantValue) 92 } 93 } 94 } 95 96 done.Add(1) 97 go expectSends(1, 3) 98 expectRecv(1, 3) 99 done.Wait() 100 101 sub1.Unsubscribe() 102 103 done.Add(1) 104 go expectSends(2, 2) 105 expectRecv(2, 2) 106 done.Wait() 107 108 sub2.Unsubscribe() 109 110 done.Add(1) 111 go expectSends(3, 1) 112 expectRecv(3, 1) 113 done.Wait() 114 } 115 116 func TestFeedOfSubscribeBlockedPost(t *testing.T) { 117 var ( 118 feed FeedOf[int] 119 nsends = 2000 120 ch1 = make(chan int) 121 ch2 = make(chan int) 122 wg sync.WaitGroup 123 ) 124 defer wg.Wait() 125 126 feed.Subscribe(ch1) 127 wg.Add(nsends) 128 for i := 0; i < nsends; i++ { 129 go func() { 130 feed.Send(99) 131 wg.Done() 132 }() 133 } 134 135 sub2 := feed.Subscribe(ch2) 136 defer sub2.Unsubscribe() 137 138 // We're done when ch1 has received N times. 139 // The number of receives on ch2 depends on scheduling. 140 for i := 0; i < nsends; { 141 select { 142 case <-ch1: 143 i++ 144 case <-ch2: 145 } 146 } 147 } 148 149 func TestFeedOfUnsubscribeBlockedPost(t *testing.T) { 150 var ( 151 feed FeedOf[int] 152 nsends = 200 153 chans = make([]chan int, 2000) 154 subs = make([]Subscription, len(chans)) 155 bchan = make(chan int) 156 bsub = feed.Subscribe(bchan) 157 wg sync.WaitGroup 158 ) 159 for i := range chans { 160 chans[i] = make(chan int, nsends) 161 } 162 163 // Queue up some Sends. None of these can make progress while bchan isn't read. 164 wg.Add(nsends) 165 for i := 0; i < nsends; i++ { 166 go func() { 167 feed.Send(99) 168 wg.Done() 169 }() 170 } 171 // Subscribe the other channels. 172 for i, ch := range chans { 173 subs[i] = feed.Subscribe(ch) 174 } 175 // Unsubscribe them again. 176 for _, sub := range subs { 177 sub.Unsubscribe() 178 } 179 // Unblock the Sends. 180 bsub.Unsubscribe() 181 wg.Wait() 182 } 183 184 // Checks that unsubscribing a channel during Send works even if that 185 // channel has already been sent on. 186 func TestFeedOfUnsubscribeSentChan(t *testing.T) { 187 var ( 188 feed FeedOf[int] 189 ch1 = make(chan int) 190 ch2 = make(chan int) 191 sub1 = feed.Subscribe(ch1) 192 sub2 = feed.Subscribe(ch2) 193 wg sync.WaitGroup 194 ) 195 defer sub2.Unsubscribe() 196 197 wg.Add(1) 198 go func() { 199 feed.Send(0) 200 wg.Done() 201 }() 202 203 // Wait for the value on ch1. 204 <-ch1 205 // Unsubscribe ch1, removing it from the send cases. 206 sub1.Unsubscribe() 207 208 // Receive ch2, finishing Send. 209 <-ch2 210 wg.Wait() 211 212 // Send again. This should send to ch2 only, so the wait group will unblock 213 // as soon as a value is received on ch2. 214 wg.Add(1) 215 go func() { 216 feed.Send(0) 217 wg.Done() 218 }() 219 <-ch2 220 wg.Wait() 221 } 222 223 func TestFeedOfUnsubscribeFromInbox(t *testing.T) { 224 var ( 225 feed FeedOf[int] 226 ch1 = make(chan int) 227 ch2 = make(chan int) 228 sub1 = feed.Subscribe(ch1) 229 sub2 = feed.Subscribe(ch1) 230 sub3 = feed.Subscribe(ch2) 231 ) 232 if len(feed.inbox) != 3 { 233 t.Errorf("inbox length != 3 after subscribe") 234 } 235 if len(feed.sendCases) != 1 { 236 t.Errorf("sendCases is non-empty after unsubscribe") 237 } 238 239 sub1.Unsubscribe() 240 sub2.Unsubscribe() 241 sub3.Unsubscribe() 242 if len(feed.inbox) != 0 { 243 t.Errorf("inbox is non-empty after unsubscribe") 244 } 245 if len(feed.sendCases) != 1 { 246 t.Errorf("sendCases is non-empty after unsubscribe") 247 } 248 } 249 250 func BenchmarkFeedOfSend1000(b *testing.B) { 251 var ( 252 done sync.WaitGroup 253 feed FeedOf[int] 254 nsubs = 1000 255 ) 256 subscriber := func(ch <-chan int) { 257 for i := 0; i < b.N; i++ { 258 <-ch 259 } 260 done.Done() 261 } 262 done.Add(nsubs) 263 for i := 0; i < nsubs; i++ { 264 ch := make(chan int, 200) 265 feed.Subscribe(ch) 266 go subscriber(ch) 267 } 268 269 // The actual benchmark. 270 b.ResetTimer() 271 for i := 0; i < b.N; i++ { 272 if feed.Send(i) != nsubs { 273 panic("wrong number of sends") 274 } 275 } 276 277 b.StopTimer() 278 done.Wait() 279 }