github.com/kubeshop/testkube@v1.17.23/pkg/triggers/watcher_test.go (about) 1 package triggers 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 corev1 "k8s.io/api/core/v1" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "k8s.io/client-go/kubernetes/fake" 12 13 testtriggersv1 "github.com/kubeshop/testkube-operator/api/testtriggers/v1" 14 faketestkube "github.com/kubeshop/testkube-operator/pkg/clientset/versioned/fake" 15 "github.com/kubeshop/testkube/pkg/event/bus" 16 "github.com/kubeshop/testkube/pkg/log" 17 ) 18 19 func TestService_runWatcher_lease(t *testing.T) { 20 t.Parallel() 21 22 t.Run("create and delete a test trigger", func(t *testing.T) { 23 t.Parallel() 24 25 clientset := fake.NewSimpleClientset() 26 testKubeClientset := faketestkube.NewSimpleClientset() 27 28 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 29 defer cancel() 30 31 s := &Service{ 32 triggerStatus: make(map[statusKey]*triggerStatus), 33 clientset: clientset, 34 testKubeClientset: testKubeClientset, 35 logger: log.DefaultLogger, 36 informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), 37 eventsBus: &bus.EventBusMock{}, 38 } 39 40 leaseChan := make(chan bool) 41 go func() { time.Sleep(50 * time.Millisecond); leaseChan <- true }() 42 go s.runWatcher(ctx, leaseChan) 43 44 time.Sleep(100 * time.Millisecond) 45 46 testNamespace := "testkube" 47 testTrigger := testtriggersv1.TestTrigger{ 48 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-trigger-1"}, 49 Spec: testtriggersv1.TestTriggerSpec{Event: "created"}, 50 } 51 createdTestTrigger, err := testKubeClientset.TestsV1().TestTriggers(testNamespace).Create(ctx, &testTrigger, metav1.CreateOptions{}) 52 assert.NotNil(t, createdTestTrigger) 53 assert.NoError(t, err) 54 55 time.Sleep(100 * time.Millisecond) 56 57 assert.Len(t, s.triggerStatus, 1) 58 key := newStatusKey(testNamespace, "test-trigger-1") 59 assert.Contains(t, s.triggerStatus, key) 60 61 err = testKubeClientset.TestsV1().TestTriggers(testNamespace).Delete(ctx, "test-trigger-1", metav1.DeleteOptions{}) 62 assert.NoError(t, err) 63 64 time.Sleep(100 * time.Millisecond) 65 66 assert.Len(t, s.triggerStatus, 0) 67 }) 68 69 t.Run("create a test trigger for pod created and match event on pod creation", func(t *testing.T) { 70 t.Parallel() 71 72 clientset := fake.NewSimpleClientset() 73 testKubeClientset := faketestkube.NewSimpleClientset() 74 75 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 76 defer cancel() 77 78 testNamespace := "testkube" 79 80 match := false 81 testExecutorF := func(ctx context.Context, e *watcherEvent, trigger *testtriggersv1.TestTrigger) error { 82 assert.Equal(t, testNamespace, trigger.Namespace) 83 assert.Equal(t, "test-trigger-2", trigger.Name) 84 match = true 85 return nil 86 } 87 s := &Service{ 88 triggerExecutor: testExecutorF, 89 identifier: "testkube-api", 90 clusterID: "testkube", 91 triggerStatus: make(map[statusKey]*triggerStatus), 92 clientset: clientset, 93 testKubeClientset: testKubeClientset, 94 logger: log.DefaultLogger, 95 informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), 96 eventsBus: &bus.EventBusMock{}, 97 } 98 99 leaseChan := make(chan bool) 100 go func() { time.Sleep(50 * time.Millisecond); leaseChan <- true }() 101 go s.runWatcher(ctx, leaseChan) 102 103 time.Sleep(50 * time.Millisecond) 104 leaseChan <- true 105 time.Sleep(50 * time.Millisecond) 106 107 testTrigger := testtriggersv1.TestTrigger{ 108 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-trigger-2"}, 109 Spec: testtriggersv1.TestTriggerSpec{ 110 Resource: "pod", 111 ResourceSelector: testtriggersv1.TestTriggerSelector{Name: "test-pod"}, 112 Event: "created", 113 Action: "run", 114 Execution: "test", 115 ConcurrencyPolicy: "allow", 116 TestSelector: testtriggersv1.TestTriggerSelector{Name: "some-test"}, 117 }, 118 } 119 createdTestTrigger, err := testKubeClientset.TestsV1().TestTriggers(testNamespace).Create(ctx, &testTrigger, metav1.CreateOptions{}) 120 assert.NotNil(t, createdTestTrigger) 121 assert.NoError(t, err) 122 123 time.Sleep(100 * time.Millisecond) 124 125 assert.Len(t, s.triggerStatus, 1) 126 key := newStatusKey(testNamespace, "test-trigger-2") 127 assert.Contains(t, s.triggerStatus, key) 128 129 testPod := corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-pod"}} 130 _, err = clientset.CoreV1().Pods(testNamespace).Create(ctx, &testPod, metav1.CreateOptions{}) 131 assert.NoError(t, err) 132 133 time.Sleep(100 * time.Millisecond) 134 assert.True(t, match, "pod created event should match the test trigger condition") 135 }) 136 } 137 138 func TestService_runWatcher_noLease(t *testing.T) { 139 t.Parallel() 140 141 t.Run("watcher will not start if lease is not acquired", func(t *testing.T) { 142 t.Parallel() 143 144 clientset := fake.NewSimpleClientset() 145 testKubeClientset := faketestkube.NewSimpleClientset() 146 147 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 148 defer cancel() 149 150 s := &Service{ 151 triggerStatus: make(map[statusKey]*triggerStatus), 152 identifier: "testkube-api", 153 clusterID: "testkube", 154 clientset: clientset, 155 testKubeClientset: testKubeClientset, 156 logger: log.DefaultLogger, 157 informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), 158 eventsBus: &bus.EventBusMock{}, 159 } 160 161 leaseChan := make(chan bool) 162 go s.runWatcher(ctx, leaseChan) 163 164 time.Sleep(50 * time.Millisecond) 165 leaseChan <- false 166 time.Sleep(50 * time.Millisecond) 167 168 testNamespace := "testkube" 169 testTrigger := testtriggersv1.TestTrigger{ 170 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-trigger-1"}, 171 Spec: testtriggersv1.TestTriggerSpec{Event: "created"}, 172 } 173 createdTestTrigger, err := testKubeClientset.TestsV1().TestTriggers(testNamespace).Create(ctx, &testTrigger, metav1.CreateOptions{}) 174 assert.NotNil(t, createdTestTrigger) 175 assert.NoError(t, err) 176 177 time.Sleep(50 * time.Millisecond) 178 179 assert.Len(t, s.triggerStatus, 0) 180 }) 181 182 t.Run("watcher should stop when lease is lost", func(t *testing.T) { 183 t.Parallel() 184 185 clientset := fake.NewSimpleClientset() 186 testKubeClientset := faketestkube.NewSimpleClientset() 187 188 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 189 defer cancel() 190 191 s := &Service{ 192 triggerStatus: make(map[statusKey]*triggerStatus), 193 identifier: "testkube-api", 194 clusterID: "testkube", 195 clientset: clientset, 196 testKubeClientset: testKubeClientset, 197 logger: log.DefaultLogger, 198 informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), 199 eventsBus: &bus.EventBusMock{}, 200 } 201 202 leaseChan := make(chan bool) 203 go s.runWatcher(ctx, leaseChan) 204 205 time.Sleep(50 * time.Millisecond) 206 leaseChan <- true 207 time.Sleep(50 * time.Millisecond) 208 leaseChan <- false 209 time.Sleep(50 * time.Millisecond) 210 211 testNamespace := "testkube" 212 testTrigger := testtriggersv1.TestTrigger{ 213 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-trigger-1"}, 214 Spec: testtriggersv1.TestTriggerSpec{Event: "created"}, 215 } 216 createdTestTrigger, err := testKubeClientset.TestsV1().TestTriggers(testNamespace).Create(ctx, &testTrigger, metav1.CreateOptions{}) 217 assert.NotNil(t, createdTestTrigger) 218 assert.NoError(t, err) 219 220 time.Sleep(50 * time.Millisecond) 221 222 assert.Len(t, s.triggerStatus, 0) 223 }) 224 225 t.Run("watcher should successfully restart on a newly acquired lease", func(t *testing.T) { 226 t.Parallel() 227 228 clientset := fake.NewSimpleClientset() 229 testKubeClientset := faketestkube.NewSimpleClientset() 230 231 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 232 defer cancel() 233 234 s := &Service{ 235 triggerStatus: make(map[statusKey]*triggerStatus), 236 identifier: "testkube-api", 237 clusterID: "testkube", 238 clientset: clientset, 239 testKubeClientset: testKubeClientset, 240 logger: log.DefaultLogger, 241 informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), 242 eventsBus: &bus.EventBusMock{}, 243 } 244 245 leaseChan := make(chan bool) 246 go s.runWatcher(ctx, leaseChan) 247 248 time.Sleep(50 * time.Millisecond) 249 leaseChan <- true 250 time.Sleep(50 * time.Millisecond) 251 leaseChan <- false 252 time.Sleep(50 * time.Millisecond) 253 leaseChan <- true 254 time.Sleep(50 * time.Millisecond) 255 256 testNamespace := "testkube" 257 testTrigger := testtriggersv1.TestTrigger{ 258 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-trigger-1"}, 259 Spec: testtriggersv1.TestTriggerSpec{Event: "created"}, 260 } 261 createdTestTrigger, err := testKubeClientset.TestsV1().TestTriggers(testNamespace).Create(ctx, &testTrigger, metav1.CreateOptions{}) 262 assert.NotNil(t, createdTestTrigger) 263 assert.NoError(t, err) 264 265 time.Sleep(50 * time.Millisecond) 266 267 assert.Len(t, s.triggerStatus, 1) 268 key := newStatusKey(testNamespace, "test-trigger-1") 269 assert.Contains(t, s.triggerStatus, key) 270 }) 271 }