github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/libs/events/events_test.go (about) 1 package events 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/pure-x-eth/consensus_tm/libs/rand" 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 evsw := NewEventSwitch() 18 err := evsw.Start() 19 require.NoError(t, err) 20 t.Cleanup(func() { 21 if err := evsw.Stop(); err != nil { 22 t.Error(err) 23 } 24 }) 25 26 messages := make(chan EventData) 27 err = evsw.AddListenerForEvent("listener", "event", 28 func(data EventData) { 29 // test there's no deadlock if we remove the listener inside a callback 30 evsw.RemoveListener("listener") 31 messages <- data 32 }) 33 require.NoError(t, err) 34 go evsw.FireEvent("event", "data") 35 received := <-messages 36 if received != "data" { 37 t.Errorf("message received does not match: %v", received) 38 } 39 } 40 41 // TestAddListenerForEventFireMany sets up an EventSwitch, subscribes a single 42 // listener to an event, and sends a thousand integers. 43 func TestAddListenerForEventFireMany(t *testing.T) { 44 evsw := NewEventSwitch() 45 err := evsw.Start() 46 require.NoError(t, err) 47 t.Cleanup(func() { 48 if err := evsw.Stop(); err != nil { 49 t.Error(err) 50 } 51 }) 52 53 doneSum := make(chan uint64) 54 doneSending := make(chan uint64) 55 numbers := make(chan uint64, 4) 56 // subscribe one listener for one event 57 err = evsw.AddListenerForEvent("listener", "event", 58 func(data EventData) { 59 numbers <- data.(uint64) 60 }) 61 require.NoError(t, err) 62 // collect received events 63 go sumReceivedNumbers(numbers, doneSum) 64 // go fire events 65 go fireEvents(evsw, "event", doneSending, uint64(1)) 66 checkSum := <-doneSending 67 close(numbers) 68 eventSum := <-doneSum 69 if checkSum != eventSum { 70 t.Errorf("not all messages sent were received.\n") 71 } 72 } 73 74 // TestAddListenerForDifferentEvents sets up an EventSwitch, subscribes a single 75 // listener to three different events and sends a thousand integers for each 76 // of the three events. 77 func TestAddListenerForDifferentEvents(t *testing.T) { 78 evsw := NewEventSwitch() 79 err := evsw.Start() 80 require.NoError(t, err) 81 t.Cleanup(func() { 82 if err := evsw.Stop(); err != nil { 83 t.Error(err) 84 } 85 }) 86 87 doneSum := make(chan uint64) 88 doneSending1 := make(chan uint64) 89 doneSending2 := make(chan uint64) 90 doneSending3 := make(chan uint64) 91 numbers := make(chan uint64, 4) 92 // subscribe one listener to three events 93 err = evsw.AddListenerForEvent("listener", "event1", 94 func(data EventData) { 95 numbers <- data.(uint64) 96 }) 97 require.NoError(t, err) 98 err = evsw.AddListenerForEvent("listener", "event2", 99 func(data EventData) { 100 numbers <- data.(uint64) 101 }) 102 require.NoError(t, err) 103 err = evsw.AddListenerForEvent("listener", "event3", 104 func(data EventData) { 105 numbers <- data.(uint64) 106 }) 107 require.NoError(t, err) 108 // collect received events 109 go sumReceivedNumbers(numbers, doneSum) 110 // go fire events 111 go fireEvents(evsw, "event1", doneSending1, uint64(1)) 112 go fireEvents(evsw, "event2", doneSending2, uint64(1)) 113 go fireEvents(evsw, "event3", doneSending3, uint64(1)) 114 var checkSum uint64 115 checkSum += <-doneSending1 116 checkSum += <-doneSending2 117 checkSum += <-doneSending3 118 close(numbers) 119 eventSum := <-doneSum 120 if checkSum != eventSum { 121 t.Errorf("not all messages sent were received.\n") 122 } 123 } 124 125 // TestAddDifferentListenerForDifferentEvents sets up an EventSwitch, 126 // subscribes a first listener to three events, and subscribes a second 127 // listener to two of those three events, and then sends a thousand integers 128 // for each of the three events. 129 func TestAddDifferentListenerForDifferentEvents(t *testing.T) { 130 evsw := NewEventSwitch() 131 err := evsw.Start() 132 require.NoError(t, err) 133 134 t.Cleanup(func() { 135 if err := evsw.Stop(); err != nil { 136 t.Error(err) 137 } 138 }) 139 140 doneSum1 := make(chan uint64) 141 doneSum2 := make(chan uint64) 142 doneSending1 := make(chan uint64) 143 doneSending2 := make(chan uint64) 144 doneSending3 := make(chan uint64) 145 numbers1 := make(chan uint64, 4) 146 numbers2 := make(chan uint64, 4) 147 // subscribe two listener to three events 148 err = evsw.AddListenerForEvent("listener1", "event1", 149 func(data EventData) { 150 numbers1 <- data.(uint64) 151 }) 152 require.NoError(t, err) 153 err = evsw.AddListenerForEvent("listener1", "event2", 154 func(data EventData) { 155 numbers1 <- data.(uint64) 156 }) 157 require.NoError(t, err) 158 err = evsw.AddListenerForEvent("listener1", "event3", 159 func(data EventData) { 160 numbers1 <- data.(uint64) 161 }) 162 require.NoError(t, err) 163 err = evsw.AddListenerForEvent("listener2", "event2", 164 func(data EventData) { 165 numbers2 <- data.(uint64) 166 }) 167 require.NoError(t, err) 168 err = evsw.AddListenerForEvent("listener2", "event3", 169 func(data EventData) { 170 numbers2 <- data.(uint64) 171 }) 172 require.NoError(t, err) 173 // collect received events for listener1 174 go sumReceivedNumbers(numbers1, doneSum1) 175 // collect received events for listener2 176 go sumReceivedNumbers(numbers2, doneSum2) 177 // go fire events 178 go fireEvents(evsw, "event1", doneSending1, uint64(1)) 179 go fireEvents(evsw, "event2", doneSending2, uint64(1001)) 180 go fireEvents(evsw, "event3", doneSending3, uint64(2001)) 181 checkSumEvent1 := <-doneSending1 182 checkSumEvent2 := <-doneSending2 183 checkSumEvent3 := <-doneSending3 184 checkSum1 := checkSumEvent1 + checkSumEvent2 + checkSumEvent3 185 checkSum2 := checkSumEvent2 + checkSumEvent3 186 close(numbers1) 187 close(numbers2) 188 eventSum1 := <-doneSum1 189 eventSum2 := <-doneSum2 190 if checkSum1 != eventSum1 || 191 checkSum2 != eventSum2 { 192 t.Errorf("not all messages sent were received for different listeners to different events.\n") 193 } 194 } 195 196 func TestAddAndRemoveListenerConcurrency(t *testing.T) { 197 var ( 198 stopInputEvent = false 199 roundCount = 2000 200 ) 201 202 evsw := NewEventSwitch() 203 err := evsw.Start() 204 require.NoError(t, err) 205 t.Cleanup(func() { 206 if err := evsw.Stop(); err != nil { 207 t.Error(err) 208 } 209 }) 210 211 done1 := make(chan struct{}) 212 done2 := make(chan struct{}) 213 214 // Must be executed concurrently to uncover the data race. 215 // 1. RemoveListener 216 go func() { 217 defer close(done1) 218 for i := 0; i < roundCount; i++ { 219 evsw.RemoveListener("listener") 220 } 221 }() 222 223 // 2. AddListenerForEvent 224 go func() { 225 defer close(done2) 226 for i := 0; i < roundCount; i++ { 227 index := i 228 // we explicitly ignore errors here, since the listener will sometimes be removed 229 // (that's what we're testing) 230 _ = evsw.AddListenerForEvent("listener", fmt.Sprintf("event%d", index), 231 func(data EventData) { 232 t.Errorf("should not run callback for %d.\n", index) 233 stopInputEvent = true 234 }) 235 } 236 }() 237 238 <-done1 239 <-done2 240 241 evsw.RemoveListener("listener") // remove the last listener 242 243 for i := 0; i < roundCount && !stopInputEvent; i++ { 244 evsw.FireEvent(fmt.Sprintf("event%d", i), uint64(1001)) 245 } 246 } 247 248 // TestAddAndRemoveListener sets up an EventSwitch, subscribes a listener to 249 // two events, fires a thousand integers for the first event, then unsubscribes 250 // the listener and fires a thousand integers for the second event. 251 func TestAddAndRemoveListener(t *testing.T) { 252 evsw := NewEventSwitch() 253 err := evsw.Start() 254 require.NoError(t, err) 255 t.Cleanup(func() { 256 if err := evsw.Stop(); err != nil { 257 t.Error(err) 258 } 259 }) 260 261 doneSum1 := make(chan uint64) 262 doneSum2 := make(chan uint64) 263 doneSending1 := make(chan uint64) 264 doneSending2 := make(chan uint64) 265 numbers1 := make(chan uint64, 4) 266 numbers2 := make(chan uint64, 4) 267 // subscribe two listener to three events 268 err = evsw.AddListenerForEvent("listener", "event1", 269 func(data EventData) { 270 numbers1 <- data.(uint64) 271 }) 272 require.NoError(t, err) 273 err = evsw.AddListenerForEvent("listener", "event2", 274 func(data EventData) { 275 numbers2 <- data.(uint64) 276 }) 277 require.NoError(t, err) 278 // collect received events for event1 279 go sumReceivedNumbers(numbers1, doneSum1) 280 // collect received events for event2 281 go sumReceivedNumbers(numbers2, doneSum2) 282 // go fire events 283 go fireEvents(evsw, "event1", doneSending1, uint64(1)) 284 checkSumEvent1 := <-doneSending1 285 // after sending all event1, unsubscribe for all events 286 evsw.RemoveListener("listener") 287 go fireEvents(evsw, "event2", doneSending2, uint64(1001)) 288 checkSumEvent2 := <-doneSending2 289 close(numbers1) 290 close(numbers2) 291 eventSum1 := <-doneSum1 292 eventSum2 := <-doneSum2 293 if checkSumEvent1 != eventSum1 || 294 // correct value asserted by preceding tests, suffices to be non-zero 295 checkSumEvent2 == uint64(0) || 296 eventSum2 != uint64(0) { 297 t.Errorf("not all messages sent were received or unsubscription did not register.\n") 298 } 299 } 300 301 // TestRemoveListener does basic tests on adding and removing 302 func TestRemoveListener(t *testing.T) { 303 evsw := NewEventSwitch() 304 err := evsw.Start() 305 require.NoError(t, err) 306 t.Cleanup(func() { 307 if err := evsw.Stop(); err != nil { 308 t.Error(err) 309 } 310 }) 311 312 count := 10 313 sum1, sum2 := 0, 0 314 // add some listeners and make sure they work 315 err = evsw.AddListenerForEvent("listener", "event1", 316 func(data EventData) { 317 sum1++ 318 }) 319 require.NoError(t, err) 320 321 err = evsw.AddListenerForEvent("listener", "event2", 322 func(data EventData) { 323 sum2++ 324 }) 325 require.NoError(t, err) 326 327 for i := 0; i < count; i++ { 328 evsw.FireEvent("event1", true) 329 evsw.FireEvent("event2", true) 330 } 331 assert.Equal(t, count, sum1) 332 assert.Equal(t, count, sum2) 333 334 // remove one by event and make sure it is gone 335 evsw.RemoveListenerForEvent("event2", "listener") 336 for i := 0; i < count; i++ { 337 evsw.FireEvent("event1", true) 338 evsw.FireEvent("event2", true) 339 } 340 assert.Equal(t, count*2, sum1) 341 assert.Equal(t, count, sum2) 342 343 // remove the listener entirely and make sure both gone 344 evsw.RemoveListener("listener") 345 for i := 0; i < count; i++ { 346 evsw.FireEvent("event1", true) 347 evsw.FireEvent("event2", true) 348 } 349 assert.Equal(t, count*2, sum1) 350 assert.Equal(t, count, sum2) 351 } 352 353 // TestAddAndRemoveListenersAsync sets up an EventSwitch, subscribes two 354 // listeners to three events, and fires a thousand integers for each event. 355 // These two listeners serve as the baseline validation while other listeners 356 // are randomly subscribed and unsubscribed. 357 // More precisely it randomly subscribes new listeners (different from the first 358 // two listeners) to one of these three events. At the same time it starts 359 // randomly unsubscribing these additional listeners from all events they are 360 // at that point subscribed to. 361 // NOTE: it is important to run this test with race conditions tracking on, 362 // `go test -race`, to examine for possible race conditions. 363 func TestRemoveListenersAsync(t *testing.T) { 364 evsw := NewEventSwitch() 365 err := evsw.Start() 366 require.NoError(t, err) 367 t.Cleanup(func() { 368 if err := evsw.Stop(); err != nil { 369 t.Error(err) 370 } 371 }) 372 373 doneSum1 := make(chan uint64) 374 doneSum2 := make(chan uint64) 375 doneSending1 := make(chan uint64) 376 doneSending2 := make(chan uint64) 377 doneSending3 := make(chan uint64) 378 numbers1 := make(chan uint64, 4) 379 numbers2 := make(chan uint64, 4) 380 // subscribe two listener to three events 381 err = evsw.AddListenerForEvent("listener1", "event1", 382 func(data EventData) { 383 numbers1 <- data.(uint64) 384 }) 385 require.NoError(t, err) 386 err = evsw.AddListenerForEvent("listener1", "event2", 387 func(data EventData) { 388 numbers1 <- data.(uint64) 389 }) 390 require.NoError(t, err) 391 err = evsw.AddListenerForEvent("listener1", "event3", 392 func(data EventData) { 393 numbers1 <- data.(uint64) 394 }) 395 require.NoError(t, err) 396 err = evsw.AddListenerForEvent("listener2", "event1", 397 func(data EventData) { 398 numbers2 <- data.(uint64) 399 }) 400 require.NoError(t, err) 401 err = evsw.AddListenerForEvent("listener2", "event2", 402 func(data EventData) { 403 numbers2 <- data.(uint64) 404 }) 405 require.NoError(t, err) 406 err = evsw.AddListenerForEvent("listener2", "event3", 407 func(data EventData) { 408 numbers2 <- data.(uint64) 409 }) 410 require.NoError(t, err) 411 // collect received events for event1 412 go sumReceivedNumbers(numbers1, doneSum1) 413 // collect received events for event2 414 go sumReceivedNumbers(numbers2, doneSum2) 415 addListenersStress := func() { 416 r1 := rand.NewRand() 417 r1.Seed(time.Now().UnixNano()) 418 for k := uint16(0); k < 400; k++ { 419 listenerNumber := r1.Intn(100) + 3 420 eventNumber := r1.Intn(3) + 1 421 go evsw.AddListenerForEvent(fmt.Sprintf("listener%v", listenerNumber), //nolint:errcheck // ignore for tests 422 fmt.Sprintf("event%v", eventNumber), 423 func(_ EventData) {}) 424 } 425 } 426 removeListenersStress := func() { 427 r2 := rand.NewRand() 428 r2.Seed(time.Now().UnixNano()) 429 for k := uint16(0); k < 80; k++ { 430 listenerNumber := r2.Intn(100) + 3 431 go evsw.RemoveListener(fmt.Sprintf("listener%v", listenerNumber)) 432 } 433 } 434 addListenersStress() 435 // go fire events 436 go fireEvents(evsw, "event1", doneSending1, uint64(1)) 437 removeListenersStress() 438 go fireEvents(evsw, "event2", doneSending2, uint64(1001)) 439 go fireEvents(evsw, "event3", doneSending3, uint64(2001)) 440 checkSumEvent1 := <-doneSending1 441 checkSumEvent2 := <-doneSending2 442 checkSumEvent3 := <-doneSending3 443 checkSum := checkSumEvent1 + checkSumEvent2 + checkSumEvent3 444 close(numbers1) 445 close(numbers2) 446 eventSum1 := <-doneSum1 447 eventSum2 := <-doneSum2 448 if checkSum != eventSum1 || 449 checkSum != eventSum2 { 450 t.Errorf("not all messages sent were received.\n") 451 } 452 } 453 454 //------------------------------------------------------------------------------ 455 // Helper functions 456 457 // sumReceivedNumbers takes two channels and adds all numbers received 458 // until the receiving channel `numbers` is closed; it then sends the sum 459 // on `doneSum` and closes that channel. Expected to be run in a go-routine. 460 func sumReceivedNumbers(numbers, doneSum chan uint64) { 461 var sum uint64 462 for { 463 j, more := <-numbers 464 sum += j 465 if !more { 466 doneSum <- sum 467 close(doneSum) 468 return 469 } 470 } 471 } 472 473 // fireEvents takes an EventSwitch and fires a thousand integers under 474 // a given `event` with the integers mootonically increasing from `offset` 475 // to `offset` + 999. It additionally returns the addition of all integers 476 // sent on `doneChan` for assertion that all events have been sent, and enabling 477 // the test to assert all events have also been received. 478 func fireEvents(evsw Fireable, event string, doneChan chan uint64, 479 offset uint64) { 480 var sentSum uint64 481 for i := offset; i <= offset+uint64(999); i++ { 482 sentSum += i 483 evsw.FireEvent(event, i) 484 } 485 doneChan <- sentSum 486 close(doneChan) 487 }