github.com/kubeshop/testkube@v1.17.23/pkg/event/emitter_test.go (about)

     1  package event
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  
    11  	"github.com/kubeshop/testkube/pkg/api/v1/testkube"
    12  	"github.com/kubeshop/testkube/pkg/event/bus"
    13  	"github.com/kubeshop/testkube/pkg/event/kind/common"
    14  	"github.com/kubeshop/testkube/pkg/event/kind/dummy"
    15  )
    16  
    17  func init() {
    18  	os.Setenv("DEBUG", "true")
    19  }
    20  
    21  func TestEmitter_Register(t *testing.T) {
    22  	t.Parallel()
    23  
    24  	t.Run("Register adds new listener", func(t *testing.T) {
    25  		t.Parallel()
    26  		// given
    27  		eventBus := bus.NewEventBusMock()
    28  		emitter := NewEmitter(eventBus, "", nil)
    29  		// when
    30  		emitter.Register(&dummy.DummyListener{Id: "l1"})
    31  
    32  		// then
    33  		assert.Equal(t, 1, len(emitter.Listeners))
    34  
    35  		t.Log("T1 completed")
    36  	})
    37  }
    38  
    39  func TestEmitter_Listen(t *testing.T) {
    40  	t.Parallel()
    41  
    42  	t.Run("listener handles only given events based on selectors", func(t *testing.T) {
    43  		t.Parallel()
    44  		// given
    45  		eventBus := bus.NewEventBusMock()
    46  		emitter := NewEmitter(eventBus, "", nil)
    47  		// given listener with matching selector
    48  		listener1 := &dummy.DummyListener{Id: "l1", SelectorString: "type=listener1"}
    49  		// and listener with second matic selector
    50  		listener2 := &dummy.DummyListener{Id: "l2", SelectorString: "type=listener2"}
    51  
    52  		// and emitter with registered listeners
    53  		emitter.Register(listener1)
    54  		emitter.Register(listener2)
    55  
    56  		// listening emitter
    57  		ctx, cancel := context.WithCancel(context.Background())
    58  		defer cancel()
    59  
    60  		emitter.Listen(ctx)
    61  		// wait for listeners to start
    62  		time.Sleep(time.Millisecond * 50)
    63  
    64  		// events
    65  		event1 := newExampleTestEvent1()
    66  		event1.TestExecution.Labels = map[string]string{"type": "listener1"}
    67  		event2 := newExampleTestEvent2()
    68  		event2.TestExecution.Labels = map[string]string{"type": "listener2"}
    69  
    70  		// when
    71  		emitter.Notify(event1)
    72  		emitter.Notify(event2)
    73  
    74  		// then
    75  		retryCount := 100
    76  		notificationsCountListener1 := 0
    77  		notificationsCountListener2 := 0
    78  		for i := 0; i < retryCount; i++ {
    79  			notificationsCountListener1 = listener1.GetNotificationCount()
    80  			notificationsCountListener2 = listener2.GetNotificationCount()
    81  			if notificationsCountListener1 == 1 && notificationsCountListener2 == 1 {
    82  				break
    83  			}
    84  			time.Sleep(50 * time.Millisecond)
    85  		}
    86  
    87  		assert.Equal(t, 1, notificationsCountListener1)
    88  		assert.Equal(t, 1, notificationsCountListener2)
    89  	})
    90  
    91  }
    92  
    93  func TestEmitter_Notify(t *testing.T) {
    94  	t.Parallel()
    95  
    96  	t.Run("notifies listeners in queue groups", func(t *testing.T) {
    97  		t.Parallel()
    98  		// given
    99  		eventBus := bus.NewEventBusMock()
   100  		emitter := NewEmitter(eventBus, "", nil)
   101  		// and 2 listeners subscribed to the same queue
   102  		// * first on pod1
   103  		listener1 := &dummy.DummyListener{Id: "l3"}
   104  		// * second on pod2
   105  		listener2 := &dummy.DummyListener{Id: "l3"}
   106  
   107  		emitter.Register(listener1)
   108  		emitter.Register(listener2)
   109  
   110  		// and listening emitter
   111  		ctx, cancel := context.WithCancel(context.Background())
   112  		defer cancel()
   113  		emitter.Listen(ctx)
   114  
   115  		time.Sleep(time.Millisecond * 50)
   116  
   117  		// when event sent to queue group
   118  		emitter.Notify(newExampleTestEvent1())
   119  
   120  		time.Sleep(time.Millisecond * 50)
   121  
   122  		// then only one listener should be notified
   123  		assert.Equal(t, 1, listener2.GetNotificationCount()+listener1.GetNotificationCount())
   124  	})
   125  }
   126  
   127  func TestEmitter_Reconcile(t *testing.T) {
   128  	t.Parallel()
   129  
   130  	t.Run("emitter refersh listeners in reconcile loop", func(t *testing.T) {
   131  		t.Parallel()
   132  		// given first reconciler loop was done
   133  		eventBus := bus.NewEventBusMock()
   134  		emitter := NewEmitter(eventBus, "", nil)
   135  		emitter.Loader.Register(&dummy.DummyLoader{IdPrefix: "dummy1"})
   136  		emitter.Loader.Register(&dummy.DummyLoader{IdPrefix: "dummy2"})
   137  
   138  		ctx, cancel := context.WithCancel(context.Background())
   139  
   140  		go emitter.Reconcile(ctx)
   141  
   142  		time.Sleep(100 * time.Millisecond)
   143  		assert.Len(t, emitter.GetListeners(), 4)
   144  
   145  		cancel()
   146  
   147  		// and we'll add additional new loader
   148  		emitter.Loader.Register(&dummy.DummyLoader{IdPrefix: "dummy1"}) // existing one
   149  		emitter.Loader.Register(&dummy.DummyLoader{IdPrefix: "dummy3"})
   150  
   151  		ctx, cancel = context.WithCancel(context.Background())
   152  
   153  		// when
   154  		go emitter.Reconcile(ctx)
   155  
   156  		// then each reconciler (3 reconcilers) should load 2 listeners
   157  		time.Sleep(100 * time.Millisecond)
   158  		assert.Len(t, emitter.GetListeners(), 6)
   159  
   160  		cancel()
   161  	})
   162  
   163  }
   164  
   165  func newExampleTestEvent1() testkube.Event {
   166  	return testkube.Event{
   167  		Id:            "eventID1",
   168  		Type_:         testkube.EventStartTest,
   169  		TestExecution: testkube.NewExecutionWithID("executionID1", "test/test", "test"),
   170  	}
   171  }
   172  
   173  func newExampleTestEvent2() testkube.Event {
   174  	return testkube.Event{
   175  		Id:            "eventID2",
   176  		Type_:         testkube.EventStartTest,
   177  		TestExecution: testkube.NewExecutionWithID("executionID2", "test/test", "test"),
   178  	}
   179  }
   180  
   181  func TestEmitter_UpdateListeners(t *testing.T) {
   182  	t.Parallel()
   183  
   184  	t.Run("add, update and delete new listeners", func(t *testing.T) {
   185  		t.Parallel()
   186  		// given
   187  		eventBus := bus.NewEventBusMock()
   188  		emitter := NewEmitter(eventBus, "", nil)
   189  		// given listener with matching selector
   190  		listener1 := &dummy.DummyListener{Id: "l1", SelectorString: "type=listener1"}
   191  		// and listener with second matching selector
   192  		listener2 := &dummy.DummyListener{Id: "l2", SelectorString: "type=listener2"}
   193  		// and listener with third matching selector
   194  		listener3 := &dummy.DummyListener{Id: "l1", SelectorString: "type=listener3"}
   195  		// and listener with different kind
   196  		listener4 := &FakeListener{name: "l4"}
   197  		// and listener with different kind
   198  		listener5 := &FakeListener{name: "l5"}
   199  
   200  		// when listeners are added
   201  		emitter.UpdateListeners(common.Listeners{listener1, listener2})
   202  
   203  		// then should have 2 listeners
   204  		assert.Len(t, emitter.Listeners, 2)
   205  
   206  		// when listeners are deleted
   207  		emitter.UpdateListeners(common.Listeners{listener1})
   208  		assert.Equal(t, "type=listener1", emitter.Listeners[0].Selector())
   209  
   210  		// then should have 1 listener
   211  		assert.Len(t, emitter.Listeners, 1)
   212  
   213  		// when listeners are updated
   214  		emitter.UpdateListeners(common.Listeners{listener3})
   215  
   216  		// then should have 1 listener
   217  		assert.Len(t, emitter.Listeners, 1)
   218  		assert.Equal(t, "type=listener3", emitter.Listeners[0].Selector())
   219  
   220  		// when listeners are added
   221  		emitter.UpdateListeners(common.Listeners{listener3, listener2})
   222  
   223  		// then should have 2 listeners
   224  		assert.Len(t, emitter.Listeners, 2)
   225  
   226  		// when listeners are added
   227  		emitter.UpdateListeners(common.Listeners{listener4})
   228  
   229  		// then should have 1 listeners
   230  		assert.Len(t, emitter.Listeners, 1)
   231  
   232  		// when listeners are added
   233  		emitter.UpdateListeners(common.Listeners{listener4, listener5})
   234  
   235  		// then should have 4 listeners
   236  		assert.Len(t, emitter.Listeners, 2)
   237  	})
   238  
   239  }
   240  
   241  var _ common.Listener = (*FakeListener)(nil)
   242  
   243  type FakeListener struct {
   244  	name string
   245  }
   246  
   247  func (l *FakeListener) Notify(event testkube.Event) testkube.EventResult {
   248  	return testkube.EventResult{Id: event.Id}
   249  }
   250  
   251  func (l *FakeListener) Name() string {
   252  	return l.name
   253  }
   254  
   255  func (l *FakeListener) Events() []testkube.EventType {
   256  	return nil
   257  }
   258  
   259  func (l FakeListener) Selector() string {
   260  	return ""
   261  }
   262  
   263  func (l *FakeListener) Kind() string {
   264  	return "fake"
   265  }
   266  
   267  func (l *FakeListener) Metadata() map[string]string {
   268  	return map[string]string{}
   269  }