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