github.com/klaytn/klaytn@v1.12.1/event/event_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from event/event_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package event 22 23 import ( 24 "math/rand" 25 "sync" 26 "testing" 27 "time" 28 ) 29 30 type testEvent int 31 32 func TestSubCloseUnsub(t *testing.T) { 33 // the point of this test is **not** to panic 34 var mux TypeMux 35 mux.Stop() 36 sub := mux.Subscribe(int(0)) 37 sub.Unsubscribe() 38 } 39 40 func TestSub(t *testing.T) { 41 mux := new(TypeMux) 42 defer mux.Stop() 43 44 sub := mux.Subscribe(testEvent(0)) 45 go func() { 46 if err := mux.Post(testEvent(5)); err != nil { 47 t.Errorf("Post returned unexpected error: %v", err) 48 } 49 }() 50 ev := <-sub.Chan() 51 52 if ev.Data.(testEvent) != testEvent(5) { 53 t.Errorf("Got %v (%T), expected event %v (%T)", 54 ev, ev, testEvent(5), testEvent(5)) 55 } 56 } 57 58 func TestMuxErrorAfterStop(t *testing.T) { 59 mux := new(TypeMux) 60 mux.Stop() 61 62 sub := mux.Subscribe(testEvent(0)) 63 if _, isopen := <-sub.Chan(); isopen { 64 t.Errorf("subscription channel was not closed") 65 } 66 if err := mux.Post(testEvent(0)); err != ErrMuxClosed { 67 t.Errorf("Post error mismatch, got: %s, expected: %s", err, ErrMuxClosed) 68 } 69 } 70 71 func TestUnsubscribeUnblockPost(t *testing.T) { 72 mux := new(TypeMux) 73 defer mux.Stop() 74 75 sub := mux.Subscribe(testEvent(0)) 76 unblocked := make(chan bool) 77 go func() { 78 mux.Post(testEvent(5)) 79 unblocked <- true 80 }() 81 82 select { 83 case <-unblocked: 84 t.Errorf("Post returned before Unsubscribe") 85 default: 86 sub.Unsubscribe() 87 <-unblocked 88 } 89 } 90 91 func TestSubscribeDuplicateType(t *testing.T) { 92 mux := new(TypeMux) 93 expected := "event: duplicate type event.testEvent in Subscribe" 94 95 defer func() { 96 err := recover() 97 if err == nil { 98 t.Errorf("Subscribe didn't panic for duplicate type") 99 } else if err != expected { 100 t.Errorf("panic mismatch: ɡot %#v, expected %#v", err, expected) 101 } 102 }() 103 mux.Subscribe(testEvent(1), testEvent(2)) 104 } 105 106 func TestMuxConcurrent(t *testing.T) { 107 rand.Seed(time.Now().Unix()) 108 mux := new(TypeMux) 109 defer mux.Stop() 110 111 recv := make(chan int) 112 poster := func() { 113 for { 114 err := mux.Post(testEvent(0)) 115 if err != nil { 116 return 117 } 118 } 119 } 120 sub := func(i int) { 121 time.Sleep(time.Duration(rand.Intn(99)) * time.Millisecond) 122 sub := mux.Subscribe(testEvent(0)) 123 <-sub.Chan() 124 sub.Unsubscribe() 125 recv <- i 126 } 127 128 go poster() 129 go poster() 130 go poster() 131 nsubs := 1000 132 for i := 0; i < nsubs; i++ { 133 go sub(i) 134 } 135 136 // wait until everyone has been served 137 counts := make(map[int]int, nsubs) 138 for i := 0; i < nsubs; i++ { 139 counts[<-recv]++ 140 } 141 for i, count := range counts { 142 if count != 1 { 143 t.Errorf("receiver %d called %d times, expected only 1 call", i, count) 144 } 145 } 146 } 147 148 func emptySubscriber(mux *TypeMux) { 149 s := mux.Subscribe(testEvent(0)) 150 go func() { 151 for range s.Chan() { 152 } 153 }() 154 } 155 156 func BenchmarkPost1000(b *testing.B) { 157 var ( 158 mux = new(TypeMux) 159 subscribed, done sync.WaitGroup 160 nsubs = 1000 161 ) 162 subscribed.Add(nsubs) 163 done.Add(nsubs) 164 for i := 0; i < nsubs; i++ { 165 go func() { 166 s := mux.Subscribe(testEvent(0)) 167 subscribed.Done() 168 for range s.Chan() { 169 } 170 done.Done() 171 }() 172 } 173 subscribed.Wait() 174 175 // The actual benchmark. 176 b.ResetTimer() 177 for i := 0; i < b.N; i++ { 178 mux.Post(testEvent(0)) 179 } 180 181 b.StopTimer() 182 mux.Stop() 183 done.Wait() 184 } 185 186 func BenchmarkPostConcurrent(b *testing.B) { 187 mux := new(TypeMux) 188 defer mux.Stop() 189 emptySubscriber(mux) 190 emptySubscriber(mux) 191 emptySubscriber(mux) 192 193 var wg sync.WaitGroup 194 poster := func() { 195 for i := 0; i < b.N; i++ { 196 mux.Post(testEvent(0)) 197 } 198 wg.Done() 199 } 200 wg.Add(5) 201 for i := 0; i < 5; i++ { 202 go poster() 203 } 204 wg.Wait() 205 } 206 207 // for comparison 208 func BenchmarkChanSend(b *testing.B) { 209 c := make(chan interface{}) 210 closed := make(chan struct{}) 211 go func() { 212 for range c { 213 } 214 }() 215 216 for i := 0; i < b.N; i++ { 217 select { 218 case c <- i: 219 case <-closed: 220 } 221 } 222 }