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