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  }