github.com/theQRL/go-zond@v0.1.1/event/event_test.go (about) 1 // Copyright 2014 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 "math/rand" 21 "sync" 22 "testing" 23 "time" 24 ) 25 26 type testEvent int 27 28 func TestSubCloseUnsub(t *testing.T) { 29 // the point of this test is **not** to panic 30 var mux TypeMux 31 mux.Stop() 32 sub := mux.Subscribe(0) 33 sub.Unsubscribe() 34 } 35 36 func TestSub(t *testing.T) { 37 mux := new(TypeMux) 38 defer mux.Stop() 39 40 sub := mux.Subscribe(testEvent(0)) 41 go func() { 42 if err := mux.Post(testEvent(5)); err != nil { 43 t.Errorf("Post returned unexpected error: %v", err) 44 } 45 }() 46 ev := <-sub.Chan() 47 48 if ev.Data.(testEvent) != testEvent(5) { 49 t.Errorf("Got %v (%T), expected event %v (%T)", 50 ev, ev, testEvent(5), testEvent(5)) 51 } 52 } 53 54 func TestMuxErrorAfterStop(t *testing.T) { 55 mux := new(TypeMux) 56 mux.Stop() 57 58 sub := mux.Subscribe(testEvent(0)) 59 if _, isopen := <-sub.Chan(); isopen { 60 t.Errorf("subscription channel was not closed") 61 } 62 if err := mux.Post(testEvent(0)); err != ErrMuxClosed { 63 t.Errorf("Post error mismatch, got: %s, expected: %s", err, ErrMuxClosed) 64 } 65 } 66 67 func TestUnsubscribeUnblockPost(t *testing.T) { 68 mux := new(TypeMux) 69 defer mux.Stop() 70 71 sub := mux.Subscribe(testEvent(0)) 72 unblocked := make(chan bool) 73 go func() { 74 mux.Post(testEvent(5)) 75 unblocked <- true 76 }() 77 78 select { 79 case <-unblocked: 80 t.Errorf("Post returned before Unsubscribe") 81 default: 82 sub.Unsubscribe() 83 <-unblocked 84 } 85 } 86 87 func TestSubscribeDuplicateType(t *testing.T) { 88 mux := new(TypeMux) 89 expected := "event: duplicate type event.testEvent in Subscribe" 90 91 defer func() { 92 err := recover() 93 if err == nil { 94 t.Errorf("Subscribe didn't panic for duplicate type") 95 } else if err != expected { 96 t.Errorf("panic mismatch: got %#v, expected %#v", err, expected) 97 } 98 }() 99 mux.Subscribe(testEvent(1), testEvent(2)) 100 } 101 102 func TestMuxConcurrent(t *testing.T) { 103 mux := new(TypeMux) 104 defer mux.Stop() 105 106 recv := make(chan int) 107 poster := func() { 108 for { 109 err := mux.Post(testEvent(0)) 110 if err != nil { 111 return 112 } 113 } 114 } 115 sub := func(i int) { 116 time.Sleep(time.Duration(rand.Intn(99)) * time.Millisecond) 117 sub := mux.Subscribe(testEvent(0)) 118 <-sub.Chan() 119 sub.Unsubscribe() 120 recv <- i 121 } 122 123 go poster() 124 go poster() 125 go poster() 126 nsubs := 1000 127 for i := 0; i < nsubs; i++ { 128 go sub(i) 129 } 130 131 // wait until everyone has been served 132 counts := make(map[int]int, nsubs) 133 for i := 0; i < nsubs; i++ { 134 counts[<-recv]++ 135 } 136 for i, count := range counts { 137 if count != 1 { 138 t.Errorf("receiver %d called %d times, expected only 1 call", i, count) 139 } 140 } 141 } 142 143 func emptySubscriber(mux *TypeMux) { 144 s := mux.Subscribe(testEvent(0)) 145 go func() { 146 for range s.Chan() { 147 } 148 }() 149 } 150 151 func BenchmarkPost1000(b *testing.B) { 152 var ( 153 mux = new(TypeMux) 154 subscribed, done sync.WaitGroup 155 nsubs = 1000 156 ) 157 subscribed.Add(nsubs) 158 done.Add(nsubs) 159 for i := 0; i < nsubs; i++ { 160 go func() { 161 s := mux.Subscribe(testEvent(0)) 162 subscribed.Done() 163 for range s.Chan() { 164 } 165 done.Done() 166 }() 167 } 168 subscribed.Wait() 169 170 // The actual benchmark. 171 b.ResetTimer() 172 for i := 0; i < b.N; i++ { 173 mux.Post(testEvent(0)) 174 } 175 176 b.StopTimer() 177 mux.Stop() 178 done.Wait() 179 } 180 181 func BenchmarkPostConcurrent(b *testing.B) { 182 var mux = new(TypeMux) 183 defer mux.Stop() 184 emptySubscriber(mux) 185 emptySubscriber(mux) 186 emptySubscriber(mux) 187 188 var wg sync.WaitGroup 189 poster := func() { 190 for i := 0; i < b.N; i++ { 191 mux.Post(testEvent(0)) 192 } 193 wg.Done() 194 } 195 wg.Add(5) 196 for i := 0; i < 5; i++ { 197 go poster() 198 } 199 wg.Wait() 200 } 201 202 // for comparison 203 func BenchmarkChanSend(b *testing.B) { 204 c := make(chan interface{}) 205 defer close(c) 206 closed := make(chan struct{}) 207 go func() { 208 for range c { 209 } 210 }() 211 212 for i := 0; i < b.N; i++ { 213 select { 214 case c <- i: 215 case <-closed: 216 } 217 } 218 }