github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/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  }