github.com/nisdas/go-ethereum@v1.9.7/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(int(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 rand.Seed(time.Now().Unix()) 104 mux := new(TypeMux) 105 defer mux.Stop() 106 107 recv := make(chan int) 108 poster := func() { 109 for { 110 err := mux.Post(testEvent(0)) 111 if err != nil { 112 return 113 } 114 } 115 } 116 sub := func(i int) { 117 time.Sleep(time.Duration(rand.Intn(99)) * time.Millisecond) 118 sub := mux.Subscribe(testEvent(0)) 119 <-sub.Chan() 120 sub.Unsubscribe() 121 recv <- i 122 } 123 124 go poster() 125 go poster() 126 go poster() 127 nsubs := 1000 128 for i := 0; i < nsubs; i++ { 129 go sub(i) 130 } 131 132 // wait until everyone has been served 133 counts := make(map[int]int, nsubs) 134 for i := 0; i < nsubs; i++ { 135 counts[<-recv]++ 136 } 137 for i, count := range counts { 138 if count != 1 { 139 t.Errorf("receiver %d called %d times, expected only 1 call", i, count) 140 } 141 } 142 } 143 144 func emptySubscriber(mux *TypeMux) { 145 s := mux.Subscribe(testEvent(0)) 146 go func() { 147 for range s.Chan() { 148 } 149 }() 150 } 151 152 func BenchmarkPost1000(b *testing.B) { 153 var ( 154 mux = new(TypeMux) 155 subscribed, done sync.WaitGroup 156 nsubs = 1000 157 ) 158 subscribed.Add(nsubs) 159 done.Add(nsubs) 160 for i := 0; i < nsubs; i++ { 161 go func() { 162 s := mux.Subscribe(testEvent(0)) 163 subscribed.Done() 164 for range s.Chan() { 165 } 166 done.Done() 167 }() 168 } 169 subscribed.Wait() 170 171 // The actual benchmark. 172 b.ResetTimer() 173 for i := 0; i < b.N; i++ { 174 mux.Post(testEvent(0)) 175 } 176 177 b.StopTimer() 178 mux.Stop() 179 done.Wait() 180 } 181 182 func BenchmarkPostConcurrent(b *testing.B) { 183 var mux = new(TypeMux) 184 defer mux.Stop() 185 emptySubscriber(mux) 186 emptySubscriber(mux) 187 emptySubscriber(mux) 188 189 var wg sync.WaitGroup 190 poster := func() { 191 for i := 0; i < b.N; i++ { 192 mux.Post(testEvent(0)) 193 } 194 wg.Done() 195 } 196 wg.Add(5) 197 for i := 0; i < 5; i++ { 198 go poster() 199 } 200 wg.Wait() 201 } 202 203 // for comparison 204 func BenchmarkChanSend(b *testing.B) { 205 c := make(chan interface{}) 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 }