github.com/livekit/protocol@v1.39.3/utils/events/emitter_test.go (about)

     1  // Copyright 2023 LiveKit, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package events
    16  
    17  import (
    18  	"sort"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  func TestEventEmitter(t *testing.T) {
    26  	t.Run("emitter", func(t *testing.T) {
    27  		emitter := NewEmitter[string, int]()
    28  		ao0 := emitter.Observe("a")
    29  		ao1 := emitter.Observe("a")
    30  		bo := emitter.Observe("b")
    31  
    32  		emitter.Emit("a", 1)
    33  		emitter.Emit("b", 2)
    34  		require.Equal(t, 1, <-ao0.Events())
    35  		require.Equal(t, 1, <-ao1.Events())
    36  		require.Equal(t, 2, <-bo.Events())
    37  
    38  		ao1.Stop()
    39  		emitter.Emit("a", 3)
    40  		require.Equal(t, 3, <-ao0.Events())
    41  		select {
    42  		case <-ao1.Events():
    43  			require.Fail(t, "expected no event from stopped observer")
    44  		default:
    45  		}
    46  
    47  		ao0.Stop()
    48  
    49  		keys := emitter.ObservedKeys()
    50  		sort.Strings(keys)
    51  		require.Equal(t, []string{"b"}, keys)
    52  	})
    53  
    54  	t.Run("observer", func(t *testing.T) {
    55  		var closeCalled bool
    56  		o, emit := NewObserver[int](func() { closeCalled = true })
    57  
    58  		emit(1)
    59  		require.Equal(t, 1, <-o.Events())
    60  
    61  		o.Stop()
    62  		require.True(t, closeCalled)
    63  	})
    64  
    65  	t.Run("notify", func(t *testing.T) {
    66  		emitter := NewEmitter[string, int]()
    67  
    68  		as := make(chan int, 1)
    69  		stop := emitter.Notify("a", as)
    70  
    71  		emitter.Emit("a", 0)
    72  		select {
    73  		case v := <-as:
    74  			require.Equal(t, 0, v)
    75  		default:
    76  			require.FailNow(t, "expected event in channel")
    77  		}
    78  
    79  		stop()
    80  
    81  		emitter.Emit("a", 0)
    82  		select {
    83  		case <-as:
    84  			require.FailNow(t, "expected no event in channel after stop")
    85  		default:
    86  		}
    87  	})
    88  
    89  	t.Run("on", func(t *testing.T) {
    90  		emitter := NewEmitter[string, int]()
    91  
    92  		as := make(chan int, 1)
    93  		stop := emitter.On("a", func(i int) {
    94  			as <- i
    95  		})
    96  
    97  		emitter.Emit("a", 0)
    98  		select {
    99  		case v := <-as:
   100  			require.Equal(t, 0, v)
   101  		case <-time.After(100 * time.Millisecond):
   102  			require.FailNow(t, "expected event in channel")
   103  		}
   104  
   105  		stop()
   106  
   107  		emitter.Emit("a", 0)
   108  		select {
   109  		case <-as:
   110  			require.FailNow(t, "expected no event in channel after stop")
   111  		case <-time.After(100 * time.Millisecond):
   112  		}
   113  	})
   114  
   115  	t.Run("stop unblocks blocking observers", func(t *testing.T) {
   116  		observer, emit := NewObserver[int](func() {})
   117  
   118  		list := NewObserverList[int](WithBlocking())
   119  
   120  		emitter := NewEmitter[int, int](WithBlocking())
   121  
   122  		cases := []struct {
   123  			label    string
   124  			emit     func()
   125  			observer Observer[int]
   126  		}{
   127  			{
   128  				label:    "observer",
   129  				emit:     func() { emit(0) },
   130  				observer: observer,
   131  			},
   132  			{
   133  				label:    "list",
   134  				emit:     func() { list.Emit(0) },
   135  				observer: list.Observe(),
   136  			},
   137  			{
   138  				label:    "emitter",
   139  				emit:     func() { emitter.Emit(0, 0) },
   140  				observer: emitter.Observe(0),
   141  			},
   142  		}
   143  
   144  		for _, c := range cases {
   145  			t.Run(c.label, func(t *testing.T) {
   146  				emitDone := make(chan struct{})
   147  				stopDone := make(chan struct{})
   148  				ready := make(chan struct{})
   149  
   150  				go func() {
   151  					for i := 0; i < DefaultQueueSize; i++ {
   152  						c.emit()
   153  					}
   154  					close(ready)
   155  					c.emit()
   156  					close(emitDone)
   157  				}()
   158  
   159  				go func() {
   160  					<-ready
   161  					time.Sleep(100 * time.Millisecond)
   162  					c.observer.Stop()
   163  					close(stopDone)
   164  				}()
   165  
   166  				select {
   167  				case <-emitDone:
   168  				case <-time.After(time.Second):
   169  					require.FailNow(t, "timeout waiting for emit to unblock")
   170  				}
   171  
   172  				select {
   173  				case <-stopDone:
   174  				case <-time.After(time.Second):
   175  					require.FailNow(t, "timeout waiting for stop to unblock")
   176  				}
   177  			})
   178  		}
   179  	})
   180  }
   181  
   182  func BenchmarkEventEmitter(b *testing.B) {
   183  	e := NewEmitter[int, int]()
   184  	for i := 0; i < b.N; i++ {
   185  		o := e.Observe(i)
   186  		e.Emit(i, i)
   187  		<-o.Events()
   188  		o.Stop()
   189  	}
   190  }
   191  
   192  func BenchmarkEventObserverList(b *testing.B) {
   193  	l := NewObserverList[int]()
   194  	for i := 0; i < b.N; i++ {
   195  		o := l.Observe()
   196  		l.Emit(i)
   197  		<-o.Events()
   198  		o.Stop()
   199  	}
   200  }