Introduce events_test.go with five unit tests asserting normal behaviour
and a sixth unit test to probe race conditions on RemoveListener.
This commit is contained in:
parent
7b75ca7bb5
commit
acabc4d3bb
|
@ -0,0 +1,335 @@
|
|||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestAddListenerForEventFireOnce sets up an EventSwitch, subscribes a single
|
||||
// listener to an event, and sends a string "data".
|
||||
func TestAddListenerForEventFireOnce(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
started, err := evsw.Start()
|
||||
if started == false || err != nil {
|
||||
t.Errorf("Failed to start EventSwitch, error: %v", err)
|
||||
}
|
||||
messages := make(chan EventData)
|
||||
evsw.AddListenerForEvent("listener", "event",
|
||||
func(data EventData) {
|
||||
messages <- data
|
||||
})
|
||||
go evsw.FireEvent("event", "data")
|
||||
received := <-messages
|
||||
if received != "data" {
|
||||
t.Errorf("Message received does not match: %v", received)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddListenerForEventFireMany sets up an EventSwitch, subscribes a single
|
||||
// listener to an event, and sends a thousand integers.
|
||||
func TestAddListenerForEventFireMany(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
started, err := evsw.Start()
|
||||
if started == false || err != nil {
|
||||
t.Errorf("Failed to start EventSwitch, error: %v", err)
|
||||
}
|
||||
doneSum := make(chan uint64)
|
||||
doneSending := make(chan uint64)
|
||||
numbers := make(chan uint64, 4)
|
||||
// subscribe one listener for one event
|
||||
evsw.AddListenerForEvent("listener", "event",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
// collect received events
|
||||
go sumReceivedNumbers(numbers, doneSum)
|
||||
// go fire events
|
||||
go fireEvents(evsw, "event", doneSending, uint64(1))
|
||||
checkSum := <-doneSending
|
||||
close(numbers)
|
||||
eventSum := <-doneSum
|
||||
if checkSum != eventSum {
|
||||
t.Errorf("Not all messages sent were received.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddListenerForDifferentEvents sets up an EventSwitch, subscribes a single
|
||||
// listener to three different events and sends a thousand integers for each
|
||||
// of the three events.
|
||||
func TestAddListenerForDifferentEvents(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
started, err := evsw.Start()
|
||||
if started == false || err != nil {
|
||||
t.Errorf("Failed to start EventSwitch, error: %v", err)
|
||||
}
|
||||
doneSum := make(chan uint64)
|
||||
doneSending1 := make(chan uint64)
|
||||
doneSending2 := make(chan uint64)
|
||||
doneSending3 := make(chan uint64)
|
||||
numbers := make(chan uint64, 4)
|
||||
// subscribe one listener to three events
|
||||
evsw.AddListenerForEvent("listener", "event1",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener", "event2",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener", "event3",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
// collect received events
|
||||
go sumReceivedNumbers(numbers, doneSum)
|
||||
// go fire events
|
||||
go fireEvents(evsw, "event1", doneSending1, uint64(1))
|
||||
go fireEvents(evsw, "event2", doneSending2, uint64(1))
|
||||
go fireEvents(evsw, "event3", doneSending3, uint64(1))
|
||||
var checkSum uint64 = 0
|
||||
checkSum += <-doneSending1
|
||||
checkSum += <-doneSending2
|
||||
checkSum += <-doneSending3
|
||||
close(numbers)
|
||||
eventSum := <-doneSum
|
||||
if checkSum != eventSum {
|
||||
t.Errorf("Not all messages sent were received.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddDifferentListenerForDifferentEvents sets up an EventSwitch,
|
||||
// subscribes a first listener to three events, and subscribes a second
|
||||
// listener to two of those three events, and then sends a thousand integers
|
||||
// for each of the three events.
|
||||
func TestAddDifferentListenerForDifferentEvents(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
started, err := evsw.Start()
|
||||
if started == false || err != nil {
|
||||
t.Errorf("Failed to start EventSwitch, error: %v", err)
|
||||
}
|
||||
doneSum1 := make(chan uint64)
|
||||
doneSum2 := make(chan uint64)
|
||||
doneSending1 := make(chan uint64)
|
||||
doneSending2 := make(chan uint64)
|
||||
doneSending3 := make(chan uint64)
|
||||
numbers1 := make(chan uint64, 4)
|
||||
numbers2 := make(chan uint64, 4)
|
||||
// subscribe two listener to three events
|
||||
evsw.AddListenerForEvent("listener1", "event1",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener1", "event2",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener1", "event3",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener2", "event2",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener2", "event3",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
// collect received events for listener1
|
||||
go sumReceivedNumbers(numbers1, doneSum1)
|
||||
// collect received events for listener2
|
||||
go sumReceivedNumbers(numbers2, doneSum2)
|
||||
// go fire events
|
||||
go fireEvents(evsw, "event1", doneSending1, uint64(1))
|
||||
go fireEvents(evsw, "event2", doneSending2, uint64(1001))
|
||||
go fireEvents(evsw, "event3", doneSending3, uint64(2001))
|
||||
checkSumEvent1 := <-doneSending1
|
||||
checkSumEvent2 := <-doneSending2
|
||||
checkSumEvent3 := <-doneSending3
|
||||
checkSum1 := checkSumEvent1 + checkSumEvent2 + checkSumEvent3
|
||||
checkSum2 := checkSumEvent2 + checkSumEvent3
|
||||
close(numbers1)
|
||||
close(numbers2)
|
||||
eventSum1 := <-doneSum1
|
||||
eventSum2 := <-doneSum2
|
||||
if checkSum1 != eventSum1 ||
|
||||
checkSum2 != eventSum2 {
|
||||
t.Errorf("Not all messages sent were received for different listeners to different events.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddAndRemoveListener sets up an EventSwitch, subscribes a listener to
|
||||
// two events, fires a thousand integers for the first event, then unsubscribes
|
||||
// the listener and fires a thousand integers for the second event.
|
||||
func TestAddAndRemoveListener(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
started, err := evsw.Start()
|
||||
if started == false || err != nil {
|
||||
t.Errorf("Failed to start EventSwitch, error: %v", err)
|
||||
}
|
||||
doneSum1 := make(chan uint64)
|
||||
doneSum2 := make(chan uint64)
|
||||
doneSending1 := make(chan uint64)
|
||||
doneSending2 := make(chan uint64)
|
||||
numbers1 := make(chan uint64, 4)
|
||||
numbers2 := make(chan uint64, 4)
|
||||
// subscribe two listener to three events
|
||||
evsw.AddListenerForEvent("listener", "event1",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener", "event2",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
// collect received events for event1
|
||||
go sumReceivedNumbers(numbers1, doneSum1)
|
||||
// collect received events for event2
|
||||
go sumReceivedNumbers(numbers2, doneSum2)
|
||||
// go fire events
|
||||
go fireEvents(evsw, "event1", doneSending1, uint64(1))
|
||||
checkSumEvent1 := <-doneSending1
|
||||
// after sending all event1, unsubscribe for all events
|
||||
evsw.RemoveListener("listener")
|
||||
go fireEvents(evsw, "event2", doneSending2, uint64(1001))
|
||||
checkSumEvent2 := <-doneSending2
|
||||
close(numbers1)
|
||||
close(numbers2)
|
||||
eventSum1 := <-doneSum1
|
||||
eventSum2 := <-doneSum2
|
||||
if checkSumEvent1 != eventSum1 ||
|
||||
// correct value asserted by preceding tests, suffices to be non-zero
|
||||
checkSumEvent2 == uint64(0) ||
|
||||
eventSum2 != uint64(0) {
|
||||
t.Errorf("Not all messages sent were received or unsubscription did not register.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAddAndRemoveListenersAsync sets up an EventSwitch, subscribes two
|
||||
// listeners to three events, and fires a thousand integers for each event.
|
||||
// These two listeners serve as the baseline validation while other listeners
|
||||
// are randomly subscribed and unsubscribed.
|
||||
// More precisely it randomly subscribes new listeners (different from the first
|
||||
// two listeners) to one of these three events. At the same time it starts
|
||||
// randomly unsubscribing these additional listeners from all events they are
|
||||
// at that point subscribed to.
|
||||
// NOTE: it is important to run this test with race conditions tracking on,
|
||||
// `go test -race`, to examine for possible race conditions.
|
||||
func TestRemoveListenersAsync(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
started, err := evsw.Start()
|
||||
if started == false || err != nil {
|
||||
t.Errorf("Failed to start EventSwitch, error: %v", err)
|
||||
}
|
||||
doneSum1 := make(chan uint64)
|
||||
doneSum2 := make(chan uint64)
|
||||
doneSending1 := make(chan uint64)
|
||||
doneSending2 := make(chan uint64)
|
||||
doneSending3 := make(chan uint64)
|
||||
numbers1 := make(chan uint64, 4)
|
||||
numbers2 := make(chan uint64, 4)
|
||||
// subscribe two listener to three events
|
||||
evsw.AddListenerForEvent("listener1", "event1",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener1", "event2",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener1", "event3",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener2", "event1",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener2", "event2",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
evsw.AddListenerForEvent("listener2", "event3",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
// collect received events for event1
|
||||
go sumReceivedNumbers(numbers1, doneSum1)
|
||||
// collect received events for event2
|
||||
go sumReceivedNumbers(numbers2, doneSum2)
|
||||
addListenersStress := func() {
|
||||
s1 := rand.NewSource(time.Now().UnixNano())
|
||||
r1 := rand.New(s1)
|
||||
for k := uint16(0); k < 400; k++ {
|
||||
listenerNumber := r1.Intn(100) + 3
|
||||
eventNumber := r1.Intn(3) + 1
|
||||
go evsw.AddListenerForEvent(fmt.Sprintf("listener%v", listenerNumber),
|
||||
fmt.Sprintf("event%v", eventNumber),
|
||||
func(_ EventData) {})
|
||||
}
|
||||
}
|
||||
removeListenersStress := func() {
|
||||
s2 := rand.NewSource(time.Now().UnixNano())
|
||||
r2 := rand.New(s2)
|
||||
for k := uint16(0); k < 80; k++ {
|
||||
listenerNumber := r2.Intn(100) + 3
|
||||
go evsw.RemoveListener(fmt.Sprintf("listener%v", listenerNumber))
|
||||
}
|
||||
}
|
||||
addListenersStress()
|
||||
// go fire events
|
||||
go fireEvents(evsw, "event1", doneSending1, uint64(1))
|
||||
removeListenersStress()
|
||||
go fireEvents(evsw, "event2", doneSending2, uint64(1001))
|
||||
go fireEvents(evsw, "event3", doneSending3, uint64(2001))
|
||||
checkSumEvent1 := <-doneSending1
|
||||
checkSumEvent2 := <-doneSending2
|
||||
checkSumEvent3 := <-doneSending3
|
||||
checkSum := checkSumEvent1 + checkSumEvent2 + checkSumEvent3
|
||||
close(numbers1)
|
||||
close(numbers2)
|
||||
eventSum1 := <-doneSum1
|
||||
eventSum2 := <-doneSum2
|
||||
if checkSum != eventSum1 ||
|
||||
checkSum != eventSum2 {
|
||||
t.Errorf("Not all messages sent were received.\n")
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper functions
|
||||
|
||||
// sumReceivedNumbers takes two channels and adds all numbers received
|
||||
// until the receiving channel `numbers` is closed; it then sends the sum
|
||||
// on `doneSum` and closes that channel. Expected to be run in a go-routine.
|
||||
func sumReceivedNumbers(numbers, doneSum chan uint64) {
|
||||
var sum uint64 = 0
|
||||
for {
|
||||
j, more := <-numbers
|
||||
sum += j
|
||||
if !more {
|
||||
doneSum <- sum
|
||||
close(doneSum)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fireEvents takes an EventSwitch and fires a thousand integers under
|
||||
// a given `event` with the integers mootonically increasing from `offset`
|
||||
// to `offset` + 999. It additionally returns the addition of all integers
|
||||
// sent on `doneChan` for assertion that all events have been sent, and enabling
|
||||
// the test to assert all events have also been received.
|
||||
func fireEvents(evsw *EventSwitch, event string, doneChan chan uint64,
|
||||
offset uint64) {
|
||||
var sentSum uint64 = 0
|
||||
for i := offset; i <= offset+uint64(999); i++ {
|
||||
sentSum += i
|
||||
evsw.FireEvent(event, i)
|
||||
}
|
||||
doneChan <- sentSum
|
||||
close(doneChan)
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue