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  }