github.com/kubeshop/testkube@v1.17.23/pkg/tcl/mapperstcl/testworkflows/mappers_test.go (about) 1 // Copyright 2024 Testkube. 2 // 3 // Licensed as a Testkube Pro file under the Testkube Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt 8 9 package testworkflows 10 11 import ( 12 "testing" 13 14 "github.com/stretchr/testify/assert" 15 corev1 "k8s.io/api/core/v1" 16 "k8s.io/apimachinery/pkg/api/resource" 17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 "k8s.io/apimachinery/pkg/util/intstr" 19 20 testworkflowsv1 "github.com/kubeshop/testkube-operator/api/testworkflows/v1" 21 "github.com/kubeshop/testkube/internal/common" 22 ) 23 24 var ( 25 container = testworkflowsv1.ContainerConfig{ 26 WorkingDir: common.Ptr("/wd"), 27 Image: "some-image", 28 ImagePullPolicy: "IfNotPresent", 29 Env: []corev1.EnvVar{ 30 {Name: "some-naaame", Value: "some-value"}, 31 {Name: "some-naaame", ValueFrom: &corev1.EnvVarSource{ 32 FieldRef: &corev1.ObjectFieldSelector{ 33 APIVersion: "api.value.1", 34 FieldPath: "the.field.pa", 35 }, 36 ResourceFieldRef: &corev1.ResourceFieldSelector{ 37 ContainerName: "con-name", 38 Resource: "anc", 39 }, 40 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 41 LocalObjectReference: corev1.LocalObjectReference{Name: "cfg-name"}, 42 Key: "cfg-key", 43 }, 44 SecretKeyRef: &corev1.SecretKeySelector{ 45 LocalObjectReference: corev1.LocalObjectReference{Name: "some-sec"}, 46 Key: "sec-key", 47 }, 48 }}, 49 }, 50 EnvFrom: []corev1.EnvFromSource{ 51 { 52 Prefix: "some-prefix", 53 ConfigMapRef: &corev1.ConfigMapEnvSource{ 54 LocalObjectReference: corev1.LocalObjectReference{ 55 Name: "some-name", 56 }, 57 }, 58 SecretRef: &corev1.SecretEnvSource{ 59 LocalObjectReference: corev1.LocalObjectReference{ 60 Name: "some-sec", 61 }, 62 Optional: common.Ptr(true), 63 }, 64 }, 65 }, 66 Command: common.Ptr([]string{"c", "d"}), 67 Args: common.Ptr([]string{"ar", "gs"}), 68 Resources: &testworkflowsv1.Resources{ 69 Limits: map[corev1.ResourceName]intstr.IntOrString{ 70 corev1.ResourceCPU: {Type: intstr.String, StrVal: "300m"}, 71 corev1.ResourceMemory: {Type: intstr.Int, IntVal: 1024}, 72 }, 73 Requests: map[corev1.ResourceName]intstr.IntOrString{ 74 corev1.ResourceCPU: {Type: intstr.String, StrVal: "3800m"}, 75 corev1.ResourceMemory: {Type: intstr.Int, IntVal: 10204}, 76 }, 77 }, 78 SecurityContext: &corev1.SecurityContext{ 79 RunAsUser: common.Ptr(int64(334)), 80 RunAsGroup: common.Ptr(int64(11)), 81 RunAsNonRoot: common.Ptr(true), 82 ReadOnlyRootFilesystem: common.Ptr(false), 83 AllowPrivilegeEscalation: nil, 84 }, 85 } 86 content = testworkflowsv1.Content{ 87 Git: &testworkflowsv1.ContentGit{ 88 Uri: "some-uri", 89 Revision: "some-revision", 90 Username: "some-username", 91 UsernameFrom: &corev1.EnvVarSource{ 92 FieldRef: &corev1.ObjectFieldSelector{ 93 APIVersion: "testworkflows.dummy.io/v1", 94 FieldPath: "the.field.path", 95 }, 96 ResourceFieldRef: &corev1.ResourceFieldSelector{ 97 ContainerName: "container.name", 98 Resource: "the.resource", 99 Divisor: resource.MustParse("300"), 100 }, 101 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 102 LocalObjectReference: corev1.LocalObjectReference{Name: "the-name-config"}, 103 Key: "the-key", 104 Optional: common.Ptr(true), 105 }, 106 SecretKeyRef: &corev1.SecretKeySelector{ 107 LocalObjectReference: corev1.LocalObjectReference{Name: "the-name-secret"}, 108 Key: "the-key-secret", 109 Optional: nil, 110 }, 111 }, 112 Token: "the-token", 113 TokenFrom: &corev1.EnvVarSource{ 114 FieldRef: &corev1.ObjectFieldSelector{ 115 APIVersion: "some.dummy.api/v1", 116 FieldPath: "some.field", 117 }, 118 ResourceFieldRef: &corev1.ResourceFieldSelector{ 119 ContainerName: "some-container-name", 120 Resource: "some-resource", 121 Divisor: resource.MustParse("200"), 122 }, 123 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 124 LocalObjectReference: corev1.LocalObjectReference{Name: "the-name"}, 125 Key: "the-abc", 126 Optional: nil, 127 }, 128 SecretKeyRef: &corev1.SecretKeySelector{ 129 LocalObjectReference: corev1.LocalObjectReference{Name: "xyz"}, 130 Key: "222", 131 Optional: nil, 132 }, 133 }, 134 AuthType: "basic", 135 MountPath: "/some/output/path", 136 Paths: []string{"a", "b", "c"}, 137 }, 138 Files: []testworkflowsv1.ContentFile{ 139 { 140 Path: "some-path", 141 Content: "some-content", 142 ContentFrom: &corev1.EnvVarSource{ 143 FieldRef: &corev1.ObjectFieldSelector{ 144 APIVersion: "api.version.abc", 145 FieldPath: "field.path", 146 }, 147 }, 148 Mode: common.Ptr(int32(0777)), 149 }, 150 }, 151 } 152 stepBase = testworkflowsv1.StepBase{ 153 Name: "some-name", 154 Condition: "some-condition", 155 Negative: true, 156 Optional: false, 157 Retry: &testworkflowsv1.RetryPolicy{ 158 Count: 444, 159 Until: "abc", 160 }, 161 Timeout: "3h15m", 162 Delay: "2m40s", 163 Content: &testworkflowsv1.Content{ 164 Git: &testworkflowsv1.ContentGit{ 165 Uri: "some-url", 166 Revision: "another-rev", 167 Username: "some-username", 168 UsernameFrom: &corev1.EnvVarSource{ 169 FieldRef: &corev1.ObjectFieldSelector{ 170 APIVersion: "dummy.api", 171 FieldPath: "field.path.there", 172 }, 173 ResourceFieldRef: &corev1.ResourceFieldSelector{ 174 ContainerName: "con-name", 175 Resource: "abc1", 176 }, 177 }, 178 Token: "", 179 TokenFrom: &corev1.EnvVarSource{ 180 FieldRef: &corev1.ObjectFieldSelector{ 181 APIVersion: "test.v1", 182 FieldPath: "abc.there", 183 }, 184 }, 185 AuthType: "basic", 186 MountPath: "/a/b/c", 187 Paths: []string{"p", "a", "th"}, 188 }, 189 Files: []testworkflowsv1.ContentFile{ 190 {Path: "abc", Content: "some-content"}, 191 }, 192 }, 193 Shell: "shell-to-run", 194 Run: &testworkflowsv1.StepRun{ 195 ContainerConfig: testworkflowsv1.ContainerConfig{ 196 WorkingDir: common.Ptr("/abc"), 197 Image: "im-g", 198 ImagePullPolicy: "IfNotPresent", 199 Env: []corev1.EnvVar{ 200 {Name: "abc", Value: "230"}, 201 }, 202 EnvFrom: []corev1.EnvFromSource{ 203 {Prefix: "abc"}, 204 }, 205 Command: common.Ptr([]string{"c", "m", "d"}), 206 Args: common.Ptr([]string{"arg", "s", "d"}), 207 Resources: &testworkflowsv1.Resources{ 208 Limits: map[corev1.ResourceName]intstr.IntOrString{ 209 corev1.ResourceCPU: {Type: intstr.Int, IntVal: 444}, 210 }, 211 }, 212 SecurityContext: &corev1.SecurityContext{ 213 RunAsUser: common.Ptr(int64(444)), 214 RunAsGroup: nil, 215 RunAsNonRoot: common.Ptr(true), 216 ReadOnlyRootFilesystem: nil, 217 AllowPrivilegeEscalation: nil, 218 }, 219 }, 220 }, 221 WorkingDir: common.Ptr("/ssss"), 222 Container: &testworkflowsv1.ContainerConfig{ 223 WorkingDir: common.Ptr("/aaaa"), 224 Image: "ssss", 225 ImagePullPolicy: "Never", 226 Env: []corev1.EnvVar{{Name: "xyz", Value: "bar"}}, 227 Command: common.Ptr([]string{"ab"}), 228 Args: common.Ptr([]string{"abrgs"}), 229 Resources: &testworkflowsv1.Resources{ 230 Requests: map[corev1.ResourceName]intstr.IntOrString{ 231 corev1.ResourceMemory: {Type: intstr.String, StrVal: "300m"}, 232 }, 233 }, 234 SecurityContext: &corev1.SecurityContext{ 235 Privileged: common.Ptr(true), 236 RunAsUser: common.Ptr(int64(33)), 237 }, 238 }, 239 Execute: &testworkflowsv1.StepExecute{ 240 Parallelism: 880, 241 Async: false, 242 Tests: []testworkflowsv1.StepExecuteTest{{Name: "some-name-test"}}, 243 Workflows: []testworkflowsv1.StepExecuteWorkflow{{Name: "some-workflow", Config: map[string]intstr.IntOrString{ 244 "id": {Type: intstr.String, StrVal: "xyzz"}, 245 }}}, 246 }, 247 Artifacts: &testworkflowsv1.StepArtifacts{ 248 Compress: &testworkflowsv1.ArtifactCompression{ 249 Name: "some-artifact.tar.gz", 250 }, 251 Paths: []string{"/get", "/from/there"}, 252 }, 253 } 254 step = testworkflowsv1.Step{ 255 StepBase: stepBase, 256 Use: []testworkflowsv1.TemplateRef{ 257 {Name: "/abc", Config: map[string]intstr.IntOrString{ 258 "xxx": {Type: intstr.Int, IntVal: 322}, 259 }}, 260 }, 261 Template: &testworkflowsv1.TemplateRef{ 262 Name: "other-one", 263 Config: map[string]intstr.IntOrString{ 264 "foo": {Type: intstr.String, StrVal: "bar"}, 265 }, 266 }, 267 Steps: []testworkflowsv1.Step{ 268 {StepBase: testworkflowsv1.StepBase{Name: "xyz"}}, 269 }, 270 } 271 independentStep = testworkflowsv1.IndependentStep{ 272 StepBase: stepBase, 273 Steps: []testworkflowsv1.IndependentStep{ 274 {StepBase: testworkflowsv1.StepBase{Name: "xyz"}}, 275 }, 276 } 277 workflowSpecBase = testworkflowsv1.TestWorkflowSpecBase{ 278 Config: map[string]testworkflowsv1.ParameterSchema{ 279 "some-key": { 280 Description: "some-description", 281 Type: "integer", 282 Enum: []string{"en", "um"}, 283 Example: &intstr.IntOrString{ 284 Type: intstr.String, 285 StrVal: "some-vale", 286 }, 287 Default: &intstr.IntOrString{ 288 Type: intstr.Int, 289 IntVal: 233, 290 }, 291 ParameterStringSchema: testworkflowsv1.ParameterStringSchema{ 292 Format: "url", 293 Pattern: "^abc$", 294 MinLength: common.Ptr(int64(1)), 295 MaxLength: common.Ptr(int64(2)), 296 }, 297 ParameterNumberSchema: testworkflowsv1.ParameterNumberSchema{ 298 Minimum: common.Ptr(int64(3)), 299 Maximum: common.Ptr(int64(4)), 300 ExclusiveMinimum: common.Ptr(int64(5)), 301 ExclusiveMaximum: common.Ptr(int64(7)), 302 MultipleOf: common.Ptr(int64(8)), 303 }, 304 }, 305 }, 306 Content: &content, 307 Container: &container, 308 Job: &testworkflowsv1.JobConfig{ 309 Labels: map[string]string{"some-key": "some-value"}, 310 Annotations: map[string]string{"some-key=2": "some-value-2"}, 311 }, 312 Pod: &testworkflowsv1.PodConfig{ 313 ServiceAccountName: "some-name", 314 ImagePullSecrets: []corev1.LocalObjectReference{{Name: "v1"}, {Name: "v2"}}, 315 NodeSelector: map[string]string{"some-key-3": "some-value"}, 316 Labels: map[string]string{"some-key-4": "some-value"}, 317 Annotations: map[string]string{"some-key=5": "some-value-2"}, 318 }, 319 Events: []testworkflowsv1.Event{ 320 { 321 Cronjob: &testworkflowsv1.CronJobConfig{ 322 Cron: "* * * * *", 323 Labels: map[string]string{"some-key": "some-value"}, 324 Annotations: map[string]string{"some-key=2": "some-value-2"}, 325 }, 326 }, 327 }, 328 } 329 ) 330 331 func TestMapTestWorkflowBackAndForth(t *testing.T) { 332 want := testworkflowsv1.TestWorkflow{ 333 TypeMeta: metav1.TypeMeta{ 334 Kind: "TestWorkflow", 335 APIVersion: "testworkflows.testkube.io/v1", 336 }, 337 ObjectMeta: metav1.ObjectMeta{ 338 Name: "dummy", 339 Namespace: "dummy-namespace", 340 }, 341 Spec: testworkflowsv1.TestWorkflowSpec{ 342 Use: []testworkflowsv1.TemplateRef{ 343 { 344 Name: "some-name", 345 Config: map[string]intstr.IntOrString{ 346 "some-key": {Type: intstr.String, StrVal: "some-value"}, 347 "some-key-2": {Type: intstr.Int, IntVal: 444}, 348 }, 349 }, 350 }, 351 TestWorkflowSpecBase: workflowSpecBase, 352 Setup: []testworkflowsv1.Step{step}, 353 Steps: []testworkflowsv1.Step{step, step}, 354 After: []testworkflowsv1.Step{step, step, step, step}, 355 }, 356 } 357 got := MapTestWorkflowAPIToKube(MapTestWorkflowKubeToAPI(*want.DeepCopy())) 358 assert.Equal(t, want, got) 359 } 360 361 func TestMapEmptyTestWorkflowBackAndForth(t *testing.T) { 362 want := testworkflowsv1.TestWorkflow{ 363 TypeMeta: metav1.TypeMeta{ 364 Kind: "TestWorkflow", 365 APIVersion: "testworkflows.testkube.io/v1", 366 }, 367 ObjectMeta: metav1.ObjectMeta{ 368 Name: "dummy", 369 Namespace: "dummy-namespace", 370 }, 371 Spec: testworkflowsv1.TestWorkflowSpec{}, 372 } 373 got := MapTestWorkflowAPIToKube(MapTestWorkflowKubeToAPI(*want.DeepCopy())) 374 assert.Equal(t, want, got) 375 } 376 377 func TestMapTestWorkflowTemplateBackAndForth(t *testing.T) { 378 want := testworkflowsv1.TestWorkflowTemplate{ 379 TypeMeta: metav1.TypeMeta{ 380 Kind: "TestWorkflowTemplate", 381 APIVersion: "testworkflows.testkube.io/v1", 382 }, 383 ObjectMeta: metav1.ObjectMeta{ 384 Name: "dummy", 385 Namespace: "dummy-namespace", 386 }, 387 Spec: testworkflowsv1.TestWorkflowTemplateSpec{ 388 TestWorkflowSpecBase: workflowSpecBase, 389 Setup: []testworkflowsv1.IndependentStep{independentStep}, 390 Steps: []testworkflowsv1.IndependentStep{independentStep, independentStep}, 391 After: []testworkflowsv1.IndependentStep{independentStep, independentStep, independentStep, independentStep}, 392 }, 393 } 394 got := MapTestWorkflowTemplateAPIToKube(MapTestWorkflowTemplateKubeToAPI(*want.DeepCopy())) 395 assert.Equal(t, want, got) 396 } 397 398 func TestMapEmptyTestWorkflowTemplateBackAndForth(t *testing.T) { 399 want := testworkflowsv1.TestWorkflowTemplate{ 400 TypeMeta: metav1.TypeMeta{ 401 Kind: "TestWorkflowTemplate", 402 APIVersion: "testworkflows.testkube.io/v1", 403 }, 404 ObjectMeta: metav1.ObjectMeta{ 405 Name: "dummy", 406 Namespace: "dummy-namespace", 407 }, 408 Spec: testworkflowsv1.TestWorkflowTemplateSpec{}, 409 } 410 got := MapTestWorkflowTemplateAPIToKube(MapTestWorkflowTemplateKubeToAPI(*want.DeepCopy())) 411 assert.Equal(t, want, got) 412 }