github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/libs/events/events_test.go (about) 1 package events 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand" 7 "testing" 8 "time" 9 10 "github.com/fortytw2/leaktest" 11 "github.com/stretchr/testify/require" 12 ) 13 14 // TestAddListenerForEventFireOnce sets up an EventSwitch, subscribes a single 15 // listener to an event, and sends a string "data". 16 func TestAddListenerForEventFireOnce(t *testing.T) { 17 ctx, cancel := context.WithCancel(context.Background()) 18 defer cancel() 19 20 evsw := NewEventSwitch() 21 22 messages := make(chan EventData) 23 require.NoError(t, evsw.AddListenerForEvent("listener", "event", 24 func(data EventData) error { 25 select { 26 case messages <- data: 27 return nil 28 case <-ctx.Done(): 29 return ctx.Err() 30 } 31 })) 32 go evsw.FireEvent("event", "data") 33 received := <-messages 34 if received != "data" { 35 t.Errorf("message received does not match: %v", received) 36 } 37 } 38 39 // TestAddListenerForEventFireMany sets up an EventSwitch, subscribes a single 40 // listener to an event, and sends a thousand integers. 41 func TestAddListenerForEventFireMany(t *testing.T) { 42 ctx, cancel := context.WithCancel(context.Background()) 43 defer cancel() 44 45 evsw := NewEventSwitch() 46 47 doneSum := make(chan uint64) 48 doneSending := make(chan uint64) 49 numbers := make(chan uint64, 4) 50 // subscribe one listener for one event 51 require.NoError(t, evsw.AddListenerForEvent("listener", "event", 52 func(data EventData) error { 53 select { 54 case numbers <- data.(uint64): 55 return nil 56 case <-ctx.Done(): 57 return ctx.Err() 58 } 59 })) 60 // collect received events 61 go sumReceivedNumbers(numbers, doneSum) 62 // go fire events 63 go fireEvents(ctx, evsw, "event", doneSending, uint64(1)) 64 checkSum := <-doneSending 65 close(numbers) 66 eventSum := <-doneSum 67 if checkSum != eventSum { 68 t.Errorf("not all messages sent were received.\n") 69 } 70 } 71 72 // TestAddListenerForDifferentEvents sets up an EventSwitch, subscribes a single 73 // listener to three different events and sends a thousand integers for each 74 // of the three events. 75 func TestAddListenerForDifferentEvents(t *testing.T) { 76 ctx, cancel := context.WithCancel(context.Background()) 77 defer cancel() 78 79 t.Cleanup(leaktest.Check(t)) 80 81 evsw := NewEventSwitch() 82 83 doneSum := make(chan uint64) 84 doneSending1 := make(chan uint64) 85 doneSending2 := make(chan uint64) 86 doneSending3 := make(chan uint64) 87 numbers := make(chan uint64, 4) 88 // subscribe one listener to three events 89 require.NoError(t, evsw.AddListenerForEvent("listener", "event1", 90 func(data EventData) error { 91 select { 92 case numbers <- data.(uint64): 93 return nil 94 case <-ctx.Done(): 95 return ctx.Err() 96 } 97 })) 98 require.NoError(t, evsw.AddListenerForEvent("listener", "event2", 99 func(data EventData) error { 100 select { 101 case numbers <- data.(uint64): 102 return nil 103 case <-ctx.Done(): 104 return ctx.Err() 105 } 106 })) 107 require.NoError(t, evsw.AddListenerForEvent("listener", "event3", 108 func(data EventData) error { 109 select { 110 case numbers <- data.(uint64): 111 return nil 112 case <-ctx.Done(): 113 return ctx.Err() 114 } 115 })) 116 // collect received events 117 go sumReceivedNumbers(numbers, doneSum) 118 // go fire events 119 go fireEvents(ctx, evsw, "event1", doneSending1, uint64(1)) 120 go fireEvents(ctx, evsw, "event2", doneSending2, uint64(1)) 121 go fireEvents(ctx, evsw, "event3", doneSending3, uint64(1)) 122 var checkSum uint64 123 checkSum += <-doneSending1 124 checkSum += <-doneSending2 125 checkSum += <-doneSending3 126 close(numbers) 127 eventSum := <-doneSum 128 if checkSum != eventSum { 129 t.Errorf("not all messages sent were received.\n") 130 } 131 } 132 133 // TestAddDifferentListenerForDifferentEvents sets up an EventSwitch, 134 // subscribes a first listener to three events, and subscribes a second 135 // listener to two of those three events, and then sends a thousand integers 136 // for each of the three events. 137 func TestAddDifferentListenerForDifferentEvents(t *testing.T) { 138 ctx, cancel := context.WithCancel(context.Background()) 139 defer cancel() 140 141 t.Cleanup(leaktest.Check(t)) 142 143 evsw := NewEventSwitch() 144 145 doneSum1 := make(chan uint64) 146 doneSum2 := make(chan uint64) 147 doneSending1 := make(chan uint64) 148 doneSending2 := make(chan uint64) 149 doneSending3 := make(chan uint64) 150 numbers1 := make(chan uint64, 4) 151 numbers2 := make(chan uint64, 4) 152 // subscribe two listener to three events 153 require.NoError(t, evsw.AddListenerForEvent("listener1", "event1", 154 func(data EventData) error { 155 select { 156 case numbers1 <- data.(uint64): 157 return nil 158 case <-ctx.Done(): 159 return ctx.Err() 160 } 161 })) 162 require.NoError(t, evsw.AddListenerForEvent("listener1", "event2", 163 func(data EventData) error { 164 select { 165 case numbers1 <- data.(uint64): 166 return nil 167 case <-ctx.Done(): 168 return ctx.Err() 169 } 170 })) 171 require.NoError(t, evsw.AddListenerForEvent("listener1", "event3", 172 func(data EventData) error { 173 select { 174 case numbers1 <- data.(uint64): 175 return nil 176 case <-ctx.Done(): 177 return ctx.Err() 178 } 179 })) 180 require.NoError(t, evsw.AddListenerForEvent("listener2", "event2", 181 func(data EventData) error { 182 select { 183 case numbers2 <- data.(uint64): 184 return nil 185 case <-ctx.Done(): 186 return ctx.Err() 187 } 188 })) 189 require.NoError(t, evsw.AddListenerForEvent("listener2", "event3", 190 func(data EventData) error { 191 select { 192 case numbers2 <- data.(uint64): 193 return nil 194 case <-ctx.Done(): 195 return ctx.Err() 196 } 197 })) 198 // collect received events for listener1 199 go sumReceivedNumbers(numbers1, doneSum1) 200 // collect received events for listener2 201 go sumReceivedNumbers(numbers2, doneSum2) 202 // go fire events 203 go fireEvents(ctx, evsw, "event1", doneSending1, uint64(1)) 204 go fireEvents(ctx, evsw, "event2", doneSending2, uint64(1001)) 205 go fireEvents(ctx, evsw, "event3", doneSending3, uint64(2001)) 206 checkSumEvent1 := <-doneSending1 207 checkSumEvent2 := <-doneSending2 208 checkSumEvent3 := <-doneSending3 209 checkSum1 := checkSumEvent1 + checkSumEvent2 + checkSumEvent3 210 checkSum2 := checkSumEvent2 + checkSumEvent3 211 close(numbers1) 212 close(numbers2) 213 eventSum1 := <-doneSum1 214 eventSum2 := <-doneSum2 215 if checkSum1 != eventSum1 || 216 checkSum2 != eventSum2 { 217 t.Errorf("not all messages sent were received for different listeners to different events.\n") 218 } 219 } 220 221 // TestManagerLiistenersAsync sets up an EventSwitch, subscribes two 222 // listeners to three events, and fires a thousand integers for each event. 223 // These two listeners serve as the baseline validation while other listeners 224 // are randomly subscribed and unsubscribed. 225 // More precisely it randomly subscribes new listeners (different from the first 226 // two listeners) to one of these three events. At the same time it starts 227 // randomly unsubscribing these additional listeners from all events they are 228 // at that point subscribed to. 229 // NOTE: it is important to run this test with race conditions tracking on, 230 // `go test -race`, to examine for possible race conditions. 231 func TestManageListenersAsync(t *testing.T) { 232 ctx, cancel := context.WithCancel(context.Background()) 233 defer cancel() 234 235 evsw := NewEventSwitch() 236 237 doneSum1 := make(chan uint64) 238 doneSum2 := make(chan uint64) 239 doneSending1 := make(chan uint64) 240 doneSending2 := make(chan uint64) 241 doneSending3 := make(chan uint64) 242 numbers1 := make(chan uint64, 4) 243 numbers2 := make(chan uint64, 4) 244 // subscribe two listener to three events 245 require.NoError(t, evsw.AddListenerForEvent("listener1", "event1", 246 func(data EventData) error { 247 select { 248 case numbers1 <- data.(uint64): 249 return nil 250 case <-ctx.Done(): 251 return ctx.Err() 252 } 253 })) 254 require.NoError(t, evsw.AddListenerForEvent("listener1", "event2", 255 func(data EventData) error { 256 select { 257 case numbers1 <- data.(uint64): 258 return nil 259 case <-ctx.Done(): 260 return ctx.Err() 261 } 262 })) 263 require.NoError(t, evsw.AddListenerForEvent("listener1", "event3", 264 func(data EventData) error { 265 select { 266 case numbers1 <- data.(uint64): 267 return nil 268 case <-ctx.Done(): 269 return ctx.Err() 270 } 271 })) 272 require.NoError(t, evsw.AddListenerForEvent("listener2", "event1", 273 func(data EventData) error { 274 select { 275 case numbers2 <- data.(uint64): 276 return nil 277 case <-ctx.Done(): 278 return ctx.Err() 279 } 280 })) 281 require.NoError(t, evsw.AddListenerForEvent("listener2", "event2", 282 func(data EventData) error { 283 select { 284 case numbers2 <- data.(uint64): 285 return nil 286 case <-ctx.Done(): 287 return ctx.Err() 288 } 289 })) 290 require.NoError(t, evsw.AddListenerForEvent("listener2", "event3", 291 func(data EventData) error { 292 select { 293 case numbers2 <- data.(uint64): 294 return nil 295 case <-ctx.Done(): 296 return ctx.Err() 297 } 298 })) 299 // collect received events for event1 300 go sumReceivedNumbers(numbers1, doneSum1) 301 // collect received events for event2 302 go sumReceivedNumbers(numbers2, doneSum2) 303 addListenersStress := func() { 304 r1 := rand.New(rand.NewSource(time.Now().Unix())) 305 r1.Seed(time.Now().UnixNano()) 306 for k := uint16(0); k < 400; k++ { 307 listenerNumber := r1.Intn(100) + 3 308 eventNumber := r1.Intn(3) + 1 309 go evsw.AddListenerForEvent(fmt.Sprintf("listener%v", listenerNumber), //nolint:errcheck // ignore for tests 310 fmt.Sprintf("event%v", eventNumber), 311 func(EventData) error { return nil }) 312 } 313 } 314 addListenersStress() 315 // go fire events 316 go fireEvents(ctx, evsw, "event1", doneSending1, uint64(1)) 317 go fireEvents(ctx, evsw, "event2", doneSending2, uint64(1001)) 318 go fireEvents(ctx, evsw, "event3", doneSending3, uint64(2001)) 319 checkSumEvent1 := <-doneSending1 320 checkSumEvent2 := <-doneSending2 321 checkSumEvent3 := <-doneSending3 322 checkSum := checkSumEvent1 + checkSumEvent2 + checkSumEvent3 323 close(numbers1) 324 close(numbers2) 325 eventSum1 := <-doneSum1 326 eventSum2 := <-doneSum2 327 if checkSum != eventSum1 || 328 checkSum != eventSum2 { 329 t.Errorf("not all messages sent were received.\n") 330 } 331 } 332 333 //------------------------------------------------------------------------------ 334 // Helper functions 335 336 // sumReceivedNumbers takes two channels and adds all numbers received 337 // until the receiving channel `numbers` is closed; it then sends the sum 338 // on `doneSum` and closes that channel. Expected to be run in a go-routine. 339 func sumReceivedNumbers(numbers, doneSum chan uint64) { 340 var sum uint64 341 for { 342 j, more := <-numbers 343 sum += j 344 if !more { 345 doneSum <- sum 346 close(doneSum) 347 return 348 } 349 } 350 } 351 352 // fireEvents takes an EventSwitch and fires a thousand integers under 353 // a given `event` with the integers mootonically increasing from `offset` 354 // to `offset` + 999. It additionally returns the addition of all integers 355 // sent on `doneChan` for assertion that all events have been sent, and enabling 356 // the test to assert all events have also been received. 357 func fireEvents(ctx context.Context, evsw Fireable, event string, doneChan chan uint64, offset uint64) { 358 defer close(doneChan) 359 360 var sentSum uint64 361 for i := offset; i <= offset+uint64(999); i++ { 362 if ctx.Err() != nil { 363 break 364 } 365 366 evsw.FireEvent(event, i) 367 sentSum += i 368 } 369 370 select { 371 case <-ctx.Done(): 372 case doneChan <- sentSum: 373 } 374 }