github.com/argoproj/argo-cd/v3@v3.2.1/util/kustomize/kustomize_test.go (about)

     1  package kustomize
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    13  	"k8s.io/apimachinery/pkg/util/intstr"
    14  
    15  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    16  	"github.com/argoproj/argo-cd/v3/util/exec"
    17  	"github.com/argoproj/argo-cd/v3/util/git"
    18  )
    19  
    20  const (
    21  	kustomization1 = "kustomization_yaml"
    22  	kustomization3 = "force_common"
    23  	kustomization4 = "custom_version"
    24  	kustomization5 = "kustomization_yaml_patches"
    25  	kustomization6 = "kustomization_yaml_components"
    26  	kustomization7 = "label_without_selector"
    27  	kustomization8 = "kustomization_yaml_patches_empty"
    28  	kustomization9 = "kustomization_yaml_components_monorepo"
    29  )
    30  
    31  func testDataDir(tb testing.TB, testData string) (string, error) {
    32  	tb.Helper()
    33  	res := tb.TempDir()
    34  	_, err := exec.RunCommand("cp", exec.CmdOpts{}, "-r", "./testdata/"+testData, filepath.Join(res, "testdata"))
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  	return path.Join(res, "testdata"), nil
    39  }
    40  
    41  func TestKustomizeBuild(t *testing.T) {
    42  	appPath, err := testDataDir(t, kustomization1)
    43  	require.NoError(t, err)
    44  	namePrefix := "namePrefix-"
    45  	nameSuffix := "-nameSuffix"
    46  	namespace := "custom-namespace"
    47  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
    48  	env := &v1alpha1.Env{
    49  		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: "argo-cd-tests"},
    50  	}
    51  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
    52  		NamePrefix: namePrefix,
    53  		NameSuffix: nameSuffix,
    54  		Images:     v1alpha1.KustomizeImages{"nginx:1.15.5"},
    55  		CommonLabels: map[string]string{
    56  			"app.kubernetes.io/managed-by": "argo-cd",
    57  			"app.kubernetes.io/part-of":    "${ARGOCD_APP_NAME}",
    58  		},
    59  		CommonAnnotations: map[string]string{
    60  			"app.kubernetes.io/managed-by": "argo-cd",
    61  			"app.kubernetes.io/part-of":    "${ARGOCD_APP_NAME}",
    62  		},
    63  		Namespace:                 namespace,
    64  		CommonAnnotationsEnvsubst: true,
    65  		Replicas: []v1alpha1.KustomizeReplica{
    66  			{
    67  				Name:  "nginx-deployment",
    68  				Count: intstr.FromInt32(2),
    69  			},
    70  			{
    71  				Name:  "web",
    72  				Count: intstr.FromString("4"),
    73  			},
    74  		},
    75  	}
    76  	objs, images, _, err := kustomize.Build(&kustomizeSource, nil, env, &BuildOpts{
    77  		KubeVersion: "1.27", APIVersions: []string{"foo", "bar"},
    78  	})
    79  	require.NoError(t, err)
    80  	if err != nil {
    81  		assert.Len(t, objs, 2)
    82  		assert.Len(t, images, 2)
    83  	}
    84  	for _, obj := range objs {
    85  		fmt.Println(obj.GetAnnotations())
    86  		switch obj.GetKind() {
    87  		case "StatefulSet":
    88  			assert.Equal(t, namePrefix+"web"+nameSuffix, obj.GetName())
    89  			assert.Equal(t, map[string]string{
    90  				"app.kubernetes.io/managed-by": "argo-cd",
    91  				"app.kubernetes.io/part-of":    "argo-cd-tests",
    92  			}, obj.GetLabels())
    93  			assert.Equal(t, map[string]string{
    94  				"app.kubernetes.io/managed-by": "argo-cd",
    95  				"app.kubernetes.io/part-of":    "argo-cd-tests",
    96  			}, obj.GetAnnotations())
    97  			replicas, ok, err := unstructured.NestedInt64(obj.Object, "spec", "replicas")
    98  			require.NoError(t, err)
    99  			require.True(t, ok)
   100  			assert.Equal(t, int64(4), replicas)
   101  			assert.Equal(t, namespace, obj.GetNamespace())
   102  		case "Deployment":
   103  			assert.Equal(t, namePrefix+"nginx-deployment"+nameSuffix, obj.GetName())
   104  			assert.Equal(t, map[string]string{
   105  				"app":                          "nginx",
   106  				"app.kubernetes.io/managed-by": "argo-cd",
   107  				"app.kubernetes.io/part-of":    "argo-cd-tests",
   108  			}, obj.GetLabels())
   109  			assert.Equal(t, map[string]string{
   110  				"app.kubernetes.io/managed-by": "argo-cd",
   111  				"app.kubernetes.io/part-of":    "argo-cd-tests",
   112  			}, obj.GetAnnotations())
   113  			replicas, ok, err := unstructured.NestedInt64(obj.Object, "spec", "replicas")
   114  			require.NoError(t, err)
   115  			require.True(t, ok)
   116  			assert.Equal(t, int64(2), replicas)
   117  			assert.Equal(t, namespace, obj.GetNamespace())
   118  		}
   119  	}
   120  
   121  	for _, image := range images {
   122  		if image == "nginx" {
   123  			assert.Equal(t, "1.15.5", image)
   124  		}
   125  	}
   126  }
   127  
   128  func TestFailKustomizeBuild(t *testing.T) {
   129  	appPath, err := testDataDir(t, kustomization1)
   130  	require.NoError(t, err)
   131  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   132  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   133  		Replicas: []v1alpha1.KustomizeReplica{
   134  			{
   135  				Name:  "nginx-deployment",
   136  				Count: intstr.Parse("garbage"),
   137  			},
   138  		},
   139  	}
   140  	_, _, _, err = kustomize.Build(&kustomizeSource, nil, nil, nil)
   141  	assert.EqualError(t, err, "expected integer value for count. Received: garbage")
   142  }
   143  
   144  func TestIsKustomization(t *testing.T) {
   145  	assert.True(t, IsKustomization("kustomization.yaml"))
   146  	assert.True(t, IsKustomization("kustomization.yml"))
   147  	assert.True(t, IsKustomization("Kustomization"))
   148  	assert.False(t, IsKustomization("rubbish.yml"))
   149  }
   150  
   151  func TestParseKustomizeBuildOptions(t *testing.T) {
   152  	built := parseKustomizeBuildOptions(&kustomize{path: "guestbook"}, "-v 6 --logtostderr", &BuildOpts{
   153  		KubeVersion: "1.27", APIVersions: []string{"foo", "bar"},
   154  	})
   155  	// Helm is not enabled so helm options are not in the params
   156  	assert.Equal(t, []string{"build", "guestbook", "-v", "6", "--logtostderr"}, built)
   157  }
   158  
   159  func TestParseKustomizeBuildHelmOptions(t *testing.T) {
   160  	built := parseKustomizeBuildOptions(&kustomize{path: "guestbook"}, "-v 6 --logtostderr --enable-helm", &BuildOpts{
   161  		KubeVersion: "1.27",
   162  		APIVersions: []string{"foo", "bar"},
   163  	})
   164  	assert.Equal(t, []string{
   165  		"build", "guestbook",
   166  		"-v", "6", "--logtostderr", "--enable-helm",
   167  		"--helm-kube-version", "1.27",
   168  		"--helm-api-versions", "foo", "--helm-api-versions", "bar",
   169  	}, built)
   170  }
   171  
   172  func TestVersion(t *testing.T) {
   173  	ver, err := Version()
   174  	require.NoError(t, err)
   175  	assert.NotEmpty(t, ver)
   176  }
   177  
   178  func TestVersionWithBinaryPath(t *testing.T) {
   179  	ver, err := versionWithBinaryPath(&kustomize{binaryPath: "kustomize"})
   180  	require.NoError(t, err)
   181  	assert.NotEmpty(t, ver)
   182  }
   183  
   184  func TestGetSemver(t *testing.T) {
   185  	ver, err := getSemver(&kustomize{})
   186  	require.NoError(t, err)
   187  	assert.NotEmpty(t, ver)
   188  }
   189  
   190  func TestKustomizeBuildForceCommonLabels(t *testing.T) {
   191  	type testCase struct {
   192  		TestData        string
   193  		KustomizeSource v1alpha1.ApplicationSourceKustomize
   194  		ExpectedLabels  map[string]string
   195  		ExpectErr       bool
   196  		Env             *v1alpha1.Env
   197  	}
   198  	testCases := []testCase{
   199  		{
   200  			TestData: kustomization3,
   201  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   202  				ForceCommonLabels: true,
   203  				CommonLabels: map[string]string{
   204  					"foo":  "edited",
   205  					"test": "${ARGOCD_APP_NAME}",
   206  				},
   207  			},
   208  			ExpectedLabels: map[string]string{
   209  				"app":  "nginx",
   210  				"foo":  "edited",
   211  				"test": "argo-cd-tests",
   212  			},
   213  			Env: &v1alpha1.Env{
   214  				&v1alpha1.EnvEntry{
   215  					Name:  "ARGOCD_APP_NAME",
   216  					Value: "argo-cd-tests",
   217  				},
   218  			},
   219  		},
   220  		{
   221  			TestData: kustomization3,
   222  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   223  				ForceCommonLabels: false,
   224  				CommonLabels: map[string]string{
   225  					"foo": "edited",
   226  				},
   227  			},
   228  			ExpectErr: true,
   229  			Env: &v1alpha1.Env{
   230  				&v1alpha1.EnvEntry{
   231  					Name:  "ARGOCD_APP_NAME",
   232  					Value: "argo-cd-tests",
   233  				},
   234  			},
   235  		},
   236  	}
   237  	for _, tc := range testCases {
   238  		appPath, err := testDataDir(t, tc.TestData)
   239  		require.NoError(t, err)
   240  		kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   241  		objs, _, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env, nil)
   242  		switch tc.ExpectErr {
   243  		case true:
   244  			require.Error(t, err)
   245  		default:
   246  			require.NoError(t, err)
   247  			if assert.Len(t, objs, 1) {
   248  				assert.Equal(t, tc.ExpectedLabels, objs[0].GetLabels())
   249  			}
   250  		}
   251  	}
   252  }
   253  
   254  func TestKustomizeBuildForceCommonAnnotations(t *testing.T) {
   255  	type testCase struct {
   256  		TestData            string
   257  		KustomizeSource     v1alpha1.ApplicationSourceKustomize
   258  		ExpectedAnnotations map[string]string
   259  		ExpectErr           bool
   260  		Env                 *v1alpha1.Env
   261  	}
   262  	testCases := []testCase{
   263  		{
   264  			TestData: kustomization3,
   265  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   266  				ForceCommonAnnotations: true,
   267  				CommonAnnotations: map[string]string{
   268  					"one":   "edited",
   269  					"two":   "${test}",
   270  					"three": "$ARGOCD_APP_NAME",
   271  				},
   272  				CommonAnnotationsEnvsubst: false,
   273  			},
   274  			ExpectedAnnotations: map[string]string{
   275  				"baz":   "quux",
   276  				"one":   "edited",
   277  				"two":   "${test}",
   278  				"three": "$ARGOCD_APP_NAME",
   279  			},
   280  			Env: &v1alpha1.Env{
   281  				&v1alpha1.EnvEntry{
   282  					Name:  "ARGOCD_APP_NAME",
   283  					Value: "argo-cd-tests",
   284  				},
   285  			},
   286  		},
   287  		{
   288  			TestData: kustomization3,
   289  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   290  				ForceCommonAnnotations: true,
   291  				CommonAnnotations: map[string]string{
   292  					"one":   "edited",
   293  					"two":   "${test}",
   294  					"three": "$ARGOCD_APP_NAME",
   295  				},
   296  				CommonAnnotationsEnvsubst: true,
   297  			},
   298  			ExpectedAnnotations: map[string]string{
   299  				"baz":   "quux",
   300  				"one":   "edited",
   301  				"two":   "",
   302  				"three": "argo-cd-tests",
   303  			},
   304  			Env: &v1alpha1.Env{
   305  				&v1alpha1.EnvEntry{
   306  					Name:  "ARGOCD_APP_NAME",
   307  					Value: "argo-cd-tests",
   308  				},
   309  			},
   310  		},
   311  		{
   312  			TestData: kustomization3,
   313  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   314  				ForceCommonAnnotations: false,
   315  				CommonAnnotations: map[string]string{
   316  					"one": "edited",
   317  				},
   318  				CommonAnnotationsEnvsubst: true,
   319  			},
   320  			ExpectErr: true,
   321  			Env: &v1alpha1.Env{
   322  				&v1alpha1.EnvEntry{
   323  					Name:  "ARGOCD_APP_NAME",
   324  					Value: "argo-cd-tests",
   325  				},
   326  			},
   327  		},
   328  	}
   329  	for _, tc := range testCases {
   330  		appPath, err := testDataDir(t, tc.TestData)
   331  		require.NoError(t, err)
   332  		kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   333  		objs, _, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env, nil)
   334  		switch tc.ExpectErr {
   335  		case true:
   336  			require.Error(t, err)
   337  		default:
   338  			require.NoError(t, err)
   339  			if assert.Len(t, objs, 1) {
   340  				assert.Equal(t, tc.ExpectedAnnotations, objs[0].GetAnnotations())
   341  			}
   342  		}
   343  	}
   344  }
   345  
   346  func TestKustomizeLabelWithoutSelector(t *testing.T) {
   347  	type testCase struct {
   348  		TestData               string
   349  		KustomizeSource        v1alpha1.ApplicationSourceKustomize
   350  		ExpectedMetadataLabels map[string]string
   351  		ExpectedSelectorLabels map[string]string
   352  		ExpectedTemplateLabels map[string]string
   353  		ExpectErr              bool
   354  		Env                    *v1alpha1.Env
   355  	}
   356  	testCases := []testCase{
   357  		{
   358  			TestData: kustomization7,
   359  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   360  				CommonLabels: map[string]string{
   361  					"foo": "bar",
   362  				},
   363  				LabelWithoutSelector: true,
   364  			},
   365  			ExpectedMetadataLabels: map[string]string{"app": "nginx", "managed-by": "helm", "foo": "bar"},
   366  			ExpectedSelectorLabels: map[string]string{"app": "nginx"},
   367  			ExpectedTemplateLabels: map[string]string{"app": "nginx"},
   368  			Env: &v1alpha1.Env{
   369  				&v1alpha1.EnvEntry{
   370  					Name:  "ARGOCD_APP_NAME",
   371  					Value: "argo-cd-tests",
   372  				},
   373  			},
   374  		},
   375  		{
   376  			TestData: kustomization7,
   377  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   378  				CommonLabels: map[string]string{
   379  					"managed-by": "argocd",
   380  				},
   381  				LabelWithoutSelector: true,
   382  				ForceCommonLabels:    true,
   383  			},
   384  			ExpectedMetadataLabels: map[string]string{"app": "nginx", "managed-by": "argocd"},
   385  			ExpectedSelectorLabels: map[string]string{"app": "nginx"},
   386  			ExpectedTemplateLabels: map[string]string{"app": "nginx"},
   387  			Env: &v1alpha1.Env{
   388  				&v1alpha1.EnvEntry{
   389  					Name:  "ARGOCD_APP_NAME",
   390  					Value: "argo-cd-tests",
   391  				},
   392  			},
   393  		},
   394  		{
   395  			TestData: kustomization7,
   396  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   397  				CommonLabels: map[string]string{
   398  					"foo": "bar",
   399  				},
   400  				LabelWithoutSelector:  true,
   401  				LabelIncludeTemplates: true,
   402  			},
   403  			ExpectedMetadataLabels: map[string]string{"app": "nginx", "managed-by": "helm", "foo": "bar"},
   404  			ExpectedSelectorLabels: map[string]string{"app": "nginx"},
   405  			ExpectedTemplateLabels: map[string]string{"app": "nginx", "foo": "bar"},
   406  			Env: &v1alpha1.Env{
   407  				&v1alpha1.EnvEntry{
   408  					Name:  "ARGOCD_APP_NAME",
   409  					Value: "argo-cd-tests",
   410  				},
   411  			},
   412  		},
   413  		{
   414  			TestData: kustomization7,
   415  			KustomizeSource: v1alpha1.ApplicationSourceKustomize{
   416  				CommonLabels: map[string]string{
   417  					"managed-by": "argocd",
   418  				},
   419  				LabelWithoutSelector:  true,
   420  				LabelIncludeTemplates: true,
   421  				ForceCommonLabels:     true,
   422  			},
   423  			ExpectedMetadataLabels: map[string]string{"app": "nginx", "managed-by": "argocd"},
   424  			ExpectedSelectorLabels: map[string]string{"app": "nginx"},
   425  			ExpectedTemplateLabels: map[string]string{"app": "nginx", "managed-by": "argocd"},
   426  			Env: &v1alpha1.Env{
   427  				&v1alpha1.EnvEntry{
   428  					Name:  "ARGOCD_APP_NAME",
   429  					Value: "argo-cd-tests",
   430  				},
   431  			},
   432  		},
   433  	}
   434  
   435  	for _, tc := range testCases {
   436  		appPath, err := testDataDir(t, tc.TestData)
   437  		require.NoError(t, err)
   438  		kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   439  		objs, _, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env, nil)
   440  
   441  		switch tc.ExpectErr {
   442  		case true:
   443  			require.Error(t, err)
   444  		default:
   445  			require.NoError(t, err)
   446  			if assert.Len(t, objs, 1) {
   447  				obj := objs[0]
   448  				sl, found, err := unstructured.NestedStringMap(obj.Object, "spec", "selector", "matchLabels")
   449  				require.NoError(t, err)
   450  				assert.True(t, found)
   451  				tl, found, err := unstructured.NestedStringMap(obj.Object, "spec", "template", "metadata", "labels")
   452  				require.NoError(t, err)
   453  				assert.True(t, found)
   454  				assert.Equal(t, tc.ExpectedMetadataLabels, obj.GetLabels())
   455  				assert.Equal(t, tc.ExpectedSelectorLabels, sl)
   456  				assert.Equal(t, tc.ExpectedTemplateLabels, tl)
   457  			}
   458  		}
   459  	}
   460  }
   461  
   462  func TestKustomizeCustomVersion(t *testing.T) {
   463  	appPath, err := testDataDir(t, kustomization1)
   464  	require.NoError(t, err)
   465  	kustomizePath, err := testDataDir(t, kustomization4)
   466  	require.NoError(t, err)
   467  	envOutputFile := kustomizePath + "/env_output"
   468  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", kustomizePath+"/kustomize.special", "", "")
   469  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   470  		Version: "special",
   471  	}
   472  	env := &v1alpha1.Env{
   473  		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: "argo-cd-tests"},
   474  	}
   475  	objs, images, _, err := kustomize.Build(&kustomizeSource, nil, env, nil)
   476  	require.NoError(t, err)
   477  	if err != nil {
   478  		assert.Len(t, objs, 2)
   479  		assert.Len(t, images, 2)
   480  	}
   481  
   482  	content, err := os.ReadFile(envOutputFile)
   483  	require.NoError(t, err)
   484  	assert.Equal(t, "ARGOCD_APP_NAME=argo-cd-tests\n", string(content))
   485  }
   486  
   487  func TestKustomizeBuildComponents(t *testing.T) {
   488  	appPath, err := testDataDir(t, kustomization6)
   489  	require.NoError(t, err)
   490  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   491  
   492  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   493  		Components:              []string{"./components", "./missing-components"},
   494  		IgnoreMissingComponents: false,
   495  	}
   496  	_, _, _, err = kustomize.Build(&kustomizeSource, nil, nil, nil)
   497  	require.Error(t, err)
   498  
   499  	kustomizeSource = v1alpha1.ApplicationSourceKustomize{
   500  		Components:              []string{"./components", "./missing-components"},
   501  		IgnoreMissingComponents: true,
   502  	}
   503  	objs, _, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
   504  	require.NoError(t, err)
   505  	obj := objs[0]
   506  	assert.Equal(t, "nginx-deployment", obj.GetName())
   507  	assert.Equal(t, map[string]string{
   508  		"app": "nginx",
   509  	}, obj.GetLabels())
   510  	replicas, ok, err := unstructured.NestedInt64(obj.Object, "spec", "replicas")
   511  	require.NoError(t, err)
   512  	require.True(t, ok)
   513  	assert.Equal(t, int64(3), replicas)
   514  }
   515  
   516  func TestKustomizeBuildComponentsMonoRepo(t *testing.T) {
   517  	rootPath, err := testDataDir(t, kustomization9)
   518  	require.NoError(t, err)
   519  	appPath := path.Join(rootPath, "envs/inseng-pdx-egert-sandbox/namespaces/inst-system/apps/hello-world")
   520  	kustomize := NewKustomizeApp(rootPath, appPath, git.NopCreds{}, "", "", "", "")
   521  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   522  		Components:              []string{"../../../../../../kustomize/components/all"},
   523  		IgnoreMissingComponents: true,
   524  	}
   525  	objs, _, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
   526  	require.NoError(t, err)
   527  	obj := objs[2]
   528  	require.Equal(t, "hello-world-kustomize", obj.GetName())
   529  	require.Equal(t, map[string]string{
   530  		"app.kubernetes.io/name":  "hello-world-kustomize",
   531  		"app.kubernetes.io/owner": "fire-team",
   532  	}, obj.GetLabels())
   533  	replicas, ok, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "tolerations")
   534  	require.NoError(t, err)
   535  	require.True(t, ok)
   536  	require.Len(t, replicas, 1)
   537  	require.Equal(t, "my-special-toleration", replicas[0].(map[string]any)["key"])
   538  	require.Equal(t, "Exists", replicas[0].(map[string]any)["operator"])
   539  }
   540  
   541  func TestKustomizeBuildPatches(t *testing.T) {
   542  	appPath, err := testDataDir(t, kustomization5)
   543  	require.NoError(t, err)
   544  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   545  
   546  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   547  		Patches: []v1alpha1.KustomizePatch{
   548  			{
   549  				Patch: `[ { "op": "replace", "path": "/spec/template/spec/containers/0/ports/0/containerPort", "value": 443 },  { "op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "test" }]`,
   550  				Target: &v1alpha1.KustomizeSelector{
   551  					KustomizeResId: v1alpha1.KustomizeResId{
   552  						KustomizeGvk: v1alpha1.KustomizeGvk{
   553  							Kind: "Deployment",
   554  						},
   555  						Name: "nginx-deployment",
   556  					},
   557  				},
   558  			},
   559  		},
   560  	}
   561  	objs, _, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
   562  	require.NoError(t, err)
   563  	obj := objs[0]
   564  	containers, found, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "containers")
   565  	require.NoError(t, err)
   566  	assert.True(t, found)
   567  
   568  	ports, found, err := unstructured.NestedSlice(
   569  		containers[0].(map[string]any),
   570  		"ports",
   571  	)
   572  	assert.True(t, found)
   573  	require.NoError(t, err)
   574  
   575  	port, found, err := unstructured.NestedInt64(
   576  		ports[0].(map[string]any),
   577  		"containerPort",
   578  	)
   579  
   580  	assert.True(t, found)
   581  	require.NoError(t, err)
   582  	assert.Equal(t, int64(443), port)
   583  
   584  	name, found, err := unstructured.NestedString(
   585  		containers[0].(map[string]any),
   586  		"name",
   587  	)
   588  	assert.True(t, found)
   589  	require.NoError(t, err)
   590  	assert.Equal(t, "test", name)
   591  }
   592  
   593  func TestFailKustomizeBuildPatches(t *testing.T) {
   594  	appPath, err := testDataDir(t, kustomization8)
   595  	require.NoError(t, err)
   596  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   597  
   598  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   599  		Patches: []v1alpha1.KustomizePatch{
   600  			{
   601  				Patch: `[ { "op": "replace", "path": "/spec/template/spec/containers/0/ports/0/containerPort", "value": 443 },  { "op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "test" }]`,
   602  				Target: &v1alpha1.KustomizeSelector{
   603  					KustomizeResId: v1alpha1.KustomizeResId{
   604  						KustomizeGvk: v1alpha1.KustomizeGvk{
   605  							Kind: "Deployment",
   606  						},
   607  						Name: "nginx-deployment",
   608  					},
   609  				},
   610  			},
   611  		},
   612  	}
   613  
   614  	_, _, _, err = kustomize.Build(&kustomizeSource, nil, nil, nil)
   615  	require.EqualError(t, err, "kustomization file not found in the path")
   616  }
   617  
   618  func TestKustomizeBuildComponentsNoFoundComponents(t *testing.T) {
   619  	appPath, err := testDataDir(t, kustomization6)
   620  	require.NoError(t, err)
   621  	kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
   622  
   623  	// Test with non-existent components and IgnoreMissingComponents = true
   624  	// This should result in foundComponents being empty, so no "edit add component" command should be executed
   625  	kustomizeSource := v1alpha1.ApplicationSourceKustomize{
   626  		Components:              []string{"./non-existent-component1", "./non-existent-component2"},
   627  		IgnoreMissingComponents: true,
   628  	}
   629  	_, _, commands, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
   630  	require.NoError(t, err)
   631  
   632  	// Verify that no "edit add component" command was executed
   633  	for _, cmd := range commands {
   634  		assert.NotContains(t, cmd, "edit add component", "kustomize edit add component should not be invoked when foundComponents is empty")
   635  	}
   636  }
   637  
   638  func Test_getImageParameters_sorted(t *testing.T) {
   639  	apps := []*unstructured.Unstructured{
   640  		{
   641  			Object: map[string]any{
   642  				"kind": "Deployment",
   643  				"spec": map[string]any{
   644  					"template": map[string]any{
   645  						"spec": map[string]any{
   646  							"containers": []any{
   647  								map[string]any{
   648  									"name":  "nginx",
   649  									"image": "nginx:1.15.6",
   650  								},
   651  							},
   652  						},
   653  					},
   654  				},
   655  			},
   656  		},
   657  		{
   658  			Object: map[string]any{
   659  				"kind": "Deployment",
   660  				"spec": map[string]any{
   661  					"template": map[string]any{
   662  						"spec": map[string]any{
   663  							"containers": []any{
   664  								map[string]any{
   665  									"name":  "nginx",
   666  									"image": "nginx:1.15.5",
   667  								},
   668  							},
   669  						},
   670  					},
   671  				},
   672  			},
   673  		},
   674  	}
   675  	params := getImageParameters(apps)
   676  	assert.Equal(t, []string{"nginx:1.15.5", "nginx:1.15.6"}, params)
   677  }