github.com/kubeshop/testkube@v1.17.23/pkg/triggers/service_test.go (about) 1 package triggers 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/golang/mock/gomock" 9 "github.com/stretchr/testify/assert" 10 corev1 "k8s.io/api/core/v1" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "k8s.io/client-go/kubernetes/fake" 13 14 executorv1 "github.com/kubeshop/testkube-operator/api/executor/v1" 15 testsv3 "github.com/kubeshop/testkube-operator/api/tests/v3" 16 testtriggersv1 "github.com/kubeshop/testkube-operator/api/testtriggers/v1" 17 executorsclientv1 "github.com/kubeshop/testkube-operator/pkg/client/executors/v1" 18 testsclientv3 "github.com/kubeshop/testkube-operator/pkg/client/tests/v3" 19 testsourcesv1 "github.com/kubeshop/testkube-operator/pkg/client/testsources/v1" 20 testsuiteexecutionsv1 "github.com/kubeshop/testkube-operator/pkg/client/testsuiteexecutions/v1" 21 testsuitesv3 "github.com/kubeshop/testkube-operator/pkg/client/testsuites/v3" 22 faketestkube "github.com/kubeshop/testkube-operator/pkg/clientset/versioned/fake" 23 "github.com/kubeshop/testkube/internal/app/api/metrics" 24 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 25 "github.com/kubeshop/testkube/pkg/configmap" 26 "github.com/kubeshop/testkube/pkg/event" 27 "github.com/kubeshop/testkube/pkg/event/bus" 28 "github.com/kubeshop/testkube/pkg/executor/client" 29 "github.com/kubeshop/testkube/pkg/featureflags" 30 "github.com/kubeshop/testkube/pkg/log" 31 logsclient "github.com/kubeshop/testkube/pkg/logs/client" 32 "github.com/kubeshop/testkube/pkg/repository/config" 33 "github.com/kubeshop/testkube/pkg/repository/result" 34 "github.com/kubeshop/testkube/pkg/repository/testresult" 35 "github.com/kubeshop/testkube/pkg/scheduler" 36 "github.com/kubeshop/testkube/pkg/secret" 37 ) 38 39 func TestService_Run(t *testing.T) { 40 t.Parallel() 41 42 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 43 defer cancel() 44 testMetrics := metrics.NewMetrics() 45 46 mockCtrl := gomock.NewController(t) 47 defer mockCtrl.Finish() 48 49 mockBus := bus.NewEventBusMock() 50 mockResultRepository := result.NewMockRepository(mockCtrl) 51 mockTestResultRepository := testresult.NewMockRepository(mockCtrl) 52 53 mockExecutorsClient := executorsclientv1.NewMockInterface(mockCtrl) 54 mockTestsClient := testsclientv3.NewMockInterface(mockCtrl) 55 mockTestSuitesClient := testsuitesv3.NewMockInterface(mockCtrl) 56 mockTestSourcesClient := testsourcesv1.NewMockInterface(mockCtrl) 57 mockSecretClient := secret.NewMockInterface(mockCtrl) 58 configMapConfig := config.NewMockRepository(mockCtrl) 59 mockConfigMapClient := configmap.NewMockInterface(mockCtrl) 60 mockTestSuiteExecutionsClient := testsuiteexecutionsv1.NewMockInterface(mockCtrl) 61 62 mockExecutor := client.NewMockExecutor(mockCtrl) 63 64 mockEventEmitter := event.NewEmitter(bus.NewEventBusMock(), "", nil) 65 66 mockTest := testsv3.Test{ 67 ObjectMeta: metav1.ObjectMeta{Namespace: "testkube", Name: "some-test"}, 68 Spec: testsv3.TestSpec{ 69 Type_: "cypress", 70 ExecutionRequest: &testsv3.ExecutionRequest{ 71 Name: "some-custom-execution", 72 Number: 1, 73 Image: "test-image", 74 }, 75 }, 76 } 77 mockTestsClient.EXPECT().Get("some-test").Return(&mockTest, nil).AnyTimes() 78 var mockNextExecutionNumber int32 = 1 79 mockResultRepository.EXPECT().GetNextExecutionNumber(gomock.Any(), "some-test").Return(mockNextExecutionNumber, nil) 80 mockExecutionResult := testkube.ExecutionResult{Status: testkube.ExecutionStatusRunning} 81 mockExecution := testkube.Execution{Name: "test-execution-1"} 82 mockExecution.ExecutionResult = &mockExecutionResult 83 mockResultRepository.EXPECT().GetByNameAndTest(gomock.Any(), "some-custom-execution", "some-test").Return(mockExecution, nil) 84 mockSecretUUID := "b524c2f6-6bcf-4178-87c1-1aa2b2abb5dc" 85 mockTestsClient.EXPECT().GetCurrentSecretUUID("some-test").Return(mockSecretUUID, nil) 86 mockExecutorTypes := "cypress" 87 mockExecutorV1 := executorv1.Executor{ 88 TypeMeta: metav1.TypeMeta{}, 89 ObjectMeta: metav1.ObjectMeta{Namespace: "testkube", Name: "cypress"}, 90 Spec: executorv1.ExecutorSpec{ 91 Types: []string{mockExecutorTypes}, 92 ExecutorType: "job", 93 URI: "", 94 Image: "cypress", 95 Args: nil, 96 Command: []string{"run"}, 97 ImagePullSecrets: nil, 98 Features: nil, 99 ContentTypes: nil, 100 JobTemplate: "", 101 JobTemplateReference: "", 102 Meta: nil, 103 UseDataDirAsWorkingDir: false, 104 }, 105 } 106 mockExecutorsClient.EXPECT().GetByType(mockExecutorTypes).Return(&mockExecutorV1, nil).AnyTimes() 107 mockResultRepository.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil) 108 mockResultRepository.EXPECT().StartExecution(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) 109 mockExecutor.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return(&mockExecutionResult, nil) 110 mockResultRepository.EXPECT().UpdateResult(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) 111 112 mockTestExecution := testkube.Execution{ 113 Id: "test-suite-execution-1", 114 ExecutionResult: &testkube.ExecutionResult{Status: testkube.ExecutionStatusPassed}, 115 } 116 mockResultRepository.EXPECT().Get(gomock.Any(), gomock.Any()).Return(mockTestExecution, nil) 117 118 testLogger := log.DefaultLogger 119 120 mockLogsStream := logsclient.NewMockStream(mockCtrl) 121 122 sched := scheduler.NewScheduler( 123 testMetrics, 124 mockExecutor, 125 mockExecutor, 126 mockResultRepository, 127 mockTestResultRepository, 128 mockExecutorsClient, 129 mockTestsClient, 130 mockTestSuitesClient, 131 mockTestSourcesClient, 132 mockSecretClient, 133 mockEventEmitter, 134 testLogger, 135 configMapConfig, 136 mockConfigMapClient, 137 mockTestSuiteExecutionsClient, 138 mockBus, 139 "", 140 featureflags.FeatureFlags{}, 141 mockLogsStream, 142 "", 143 "", 144 "", 145 ) 146 147 mockLeaseBackend := NewMockLeaseBackend(mockCtrl) 148 testClusterID := "testkube-api" 149 testIdentifier := "test-host-1" 150 mockLeaseBackend.EXPECT().TryAcquire(gomock.Any(), testIdentifier, testClusterID).Return(true, nil).AnyTimes() 151 152 fakeTestkubeClientset := faketestkube.NewSimpleClientset() 153 fakeClientset := fake.NewSimpleClientset() 154 eventBus := bus.NewEventBusMock() 155 metrics := metrics.NewMetrics() 156 s := NewService( 157 sched, 158 fakeClientset, 159 fakeTestkubeClientset, 160 mockTestSuitesClient, 161 mockTestsClient, 162 mockResultRepository, 163 mockTestResultRepository, 164 mockLeaseBackend, 165 testLogger, 166 configMapConfig, 167 mockExecutorsClient, 168 mockExecutor, 169 eventBus, 170 metrics, 171 WithClusterID(testClusterID), 172 WithIdentifier(testIdentifier), 173 WithScraperInterval(50*time.Millisecond), 174 WithLeaseCheckerInterval(50*time.Millisecond), 175 ) 176 177 s.Run(ctx) 178 179 time.Sleep(100 * time.Millisecond) 180 181 testNamespace := "testkube" 182 testTrigger := testtriggersv1.TestTrigger{ 183 ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-trigger-1"}, 184 Spec: testtriggersv1.TestTriggerSpec{ 185 Resource: "pod", 186 ResourceSelector: testtriggersv1.TestTriggerSelector{Name: "test-pod"}, 187 Event: "created", 188 Action: "run", 189 Execution: "test", 190 ConcurrencyPolicy: "allow", 191 TestSelector: testtriggersv1.TestTriggerSelector{Name: "some-test"}, 192 }, 193 } 194 createdTestTrigger, err := fakeTestkubeClientset.TestsV1().TestTriggers(testNamespace).Create(ctx, &testTrigger, metav1.CreateOptions{}) 195 assert.NotNil(t, createdTestTrigger) 196 assert.NoError(t, err) 197 198 time.Sleep(10 * time.Millisecond) 199 200 assert.Len(t, s.triggerStatus, 1) 201 key := newStatusKey(testNamespace, "test-trigger-1") 202 assert.Contains(t, s.triggerStatus, key) 203 204 testPod := corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-pod", CreationTimestamp: metav1.Now()}} 205 _, err = fakeClientset.CoreV1().Pods(testNamespace).Create(ctx, &testPod, metav1.CreateOptions{}) 206 assert.NoError(t, err) 207 208 <-ctx.Done() 209 } 210 211 func TestService_addTrigger(t *testing.T) { 212 t.Parallel() 213 214 s := Service{triggerStatus: make(map[statusKey]*triggerStatus)} 215 216 testTrigger := testtriggersv1.TestTrigger{ 217 ObjectMeta: metav1.ObjectMeta{Name: "test-trigger-1", Namespace: "testkube"}, 218 } 219 s.addTrigger(&testTrigger) 220 221 assert.Len(t, s.triggerStatus, 1) 222 key := newStatusKey("testkube", "test-trigger-1") 223 assert.NotNil(t, s.triggerStatus[key]) 224 } 225 226 func TestService_removeTrigger(t *testing.T) { 227 t.Parallel() 228 229 s := Service{triggerStatus: make(map[statusKey]*triggerStatus)} 230 231 testTrigger1 := testtriggersv1.TestTrigger{ 232 ObjectMeta: metav1.ObjectMeta{Name: "test-trigger-1", Namespace: "testkube"}, 233 } 234 testTrigger2 := testtriggersv1.TestTrigger{ 235 ObjectMeta: metav1.ObjectMeta{Name: "test-trigger-2", Namespace: "testkube"}, 236 } 237 s.addTrigger(&testTrigger1) 238 s.addTrigger(&testTrigger2) 239 240 assert.Len(t, s.triggerStatus, 2) 241 242 s.removeTrigger(&testTrigger1) 243 244 assert.Len(t, s.triggerStatus, 1) 245 key := newStatusKey("testkube", "test-trigger-2") 246 assert.NotNil(t, s.triggerStatus[key]) 247 deletedKey := newStatusKey("testkube", "test-trigger-1") 248 assert.Nil(t, s.triggerStatus[deletedKey]) 249 } 250 251 func TestService_updateTrigger(t *testing.T) { 252 t.Parallel() 253 254 s := Service{triggerStatus: make(map[statusKey]*triggerStatus)} 255 256 oldTestTrigger := testtriggersv1.TestTrigger{ 257 ObjectMeta: metav1.ObjectMeta{Namespace: "testkube", Name: "test-trigger-1"}, 258 Spec: testtriggersv1.TestTriggerSpec{Event: "created"}, 259 } 260 s.addTrigger(&oldTestTrigger) 261 262 newTestTrigger := testtriggersv1.TestTrigger{ 263 ObjectMeta: metav1.ObjectMeta{Namespace: "testkube", Name: "test-trigger-1"}, 264 Spec: testtriggersv1.TestTriggerSpec{Event: "modified"}, 265 } 266 267 s.updateTrigger(&newTestTrigger) 268 269 assert.Len(t, s.triggerStatus, 1) 270 key := newStatusKey("testkube", "test-trigger-1") 271 assert.NotNil(t, s.triggerStatus[key]) 272 }