...

Source file src/sigs.k8s.io/kustomize/api/internal/localizer/localizer_test.go

Documentation: sigs.k8s.io/kustomize/api/internal/localizer

     1  // Copyright 2022 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package localizer_test
     5  
     6  import (
     7  	"fmt"
     8  	"io/fs"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  	. "sigs.k8s.io/kustomize/api/internal/localizer"
    15  	"sigs.k8s.io/kustomize/kyaml/filesys"
    16  )
    17  
    18  const (
    19  	podConfiguration = `apiVersion: v1
    20  kind: Pod
    21  metadata:
    22    name: pod
    23  spec:
    24    containers:
    25    - name: nginx
    26      image: nginx:1.14.2
    27      ports:
    28      - containerPort: 80`
    29  
    30  	replacementTransformerWithPath = `apiVersion: builtin
    31  kind: ReplacementTransformer
    32  metadata:
    33    name: replacement
    34  replacements:
    35  - path: replacement.yaml
    36  - source:
    37      fieldPath: metadata.[name=my-pod]
    38      group: apps
    39      namespace: test
    40      version: v1
    41    targets:
    42    - fieldPaths:
    43      - spec.containers.0.name
    44      select:
    45        name: another-pod
    46  `
    47  
    48  	replacements = `
    49  - source:
    50      name: src
    51      fieldPath: path
    52      options:
    53        delimiter: '='
    54        index: 1
    55    targets:
    56    - select:
    57        kind: Pod
    58      reject:
    59        version: v1
    60      fieldPaths:
    61      - metadata.annotations.config\.kubernetes\.io/local-config
    62      - sequence.*
    63  - source:
    64      kind: Deployment
    65      fieldPath: sequence.-
    66    targets:
    67    - select:
    68        namespace: my
    69      fieldPaths:
    70      - path
    71      options:
    72        delimiter: '='
    73        index: 0
    74  `
    75  
    76  	valuesFile = `minecraftServer:
    77    difficulty: peaceful
    78  `
    79  )
    80  
    81  func makeMemoryFs(t *testing.T) filesys.FileSystem {
    82  	t.Helper()
    83  	req := require.New(t)
    84  
    85  	fSys := filesys.MakeFsInMemory()
    86  	req.NoError(fSys.MkdirAll("/a/b"))
    87  	req.NoError(fSys.WriteFile("/a/pod.yaml", []byte(podConfiguration)))
    88  
    89  	dirChain := "/alpha/beta/gamma/delta"
    90  	req.NoError(fSys.MkdirAll(dirChain))
    91  	req.NoError(fSys.WriteFile(filepath.Join(dirChain, "deployment.yaml"), []byte("deployment configuration")))
    92  	req.NoError(fSys.Mkdir("/alpha/beta/say"))
    93  	return fSys
    94  }
    95  
    96  func addFiles(t *testing.T, fSys filesys.FileSystem, parentDir string, files map[string]string) {
    97  	t.Helper()
    98  
    99  	// in-memory file system makes all necessary dirs when writing files
   100  	for file, content := range files {
   101  		require.NoError(t, fSys.WriteFile(filepath.Join(parentDir, file), []byte(content)))
   102  	}
   103  }
   104  
   105  func checkRun(t *testing.T, fSys filesys.FileSystem, target, scope, dst string) {
   106  	t.Helper()
   107  
   108  	actualDst, err := Run(target, scope, dst, fSys)
   109  	require.NoError(t, err)
   110  	require.Equal(t, dst, actualDst)
   111  }
   112  
   113  func makeFileSystems(t *testing.T, target string, files map[string]string) (expected filesys.FileSystem, actual filesys.FileSystem) {
   114  	t.Helper()
   115  
   116  	copies := make([]filesys.FileSystem, 2)
   117  	for i := range copies {
   118  		copies[i] = makeMemoryFs(t)
   119  		addFiles(t, copies[i], target, files)
   120  	}
   121  	return copies[0], copies[1]
   122  }
   123  
   124  func checkFSys(t *testing.T, fSysExpected filesys.FileSystem, fSysActual filesys.FileSystem) {
   125  	t.Helper()
   126  
   127  	assert.Equal(t, fSysExpected, fSysActual)
   128  	if t.Failed() {
   129  		reportFSysDiff(t, fSysExpected, fSysActual)
   130  	}
   131  }
   132  
   133  func reportFSysDiff(t *testing.T, fSysExpected filesys.FileSystem, fSysActual filesys.FileSystem) {
   134  	t.Helper()
   135  
   136  	visited := make(map[string]struct{})
   137  	err := fSysActual.Walk("/", func(path string, info fs.FileInfo, err error) error {
   138  		require.NoError(t, err)
   139  		visited[path] = struct{}{}
   140  
   141  		if info.IsDir() {
   142  			assert.Truef(t, fSysExpected.IsDir(path), "unexpected directory %q", path)
   143  		} else {
   144  			actualContent, readErr := fSysActual.ReadFile(path)
   145  			require.NoError(t, readErr)
   146  			expectedContent, findErr := fSysExpected.ReadFile(path)
   147  			require.NoErrorf(t, findErr, "unexpected file %q", path)
   148  			if findErr == nil {
   149  				assert.Equal(t, string(expectedContent), string(actualContent))
   150  			}
   151  		}
   152  		return nil
   153  	})
   154  	require.NoError(t, err)
   155  
   156  	err = fSysExpected.Walk("/", func(path string, info fs.FileInfo, err error) error {
   157  		require.NoError(t, err)
   158  
   159  		_, exists := visited[path]
   160  		assert.Truef(t, exists, "expected path %q not found", path)
   161  		return nil
   162  	})
   163  	require.NoError(t, err)
   164  }
   165  
   166  func checkLocalizeInTargetSuccess(t *testing.T, files map[string]string) {
   167  	t.Helper()
   168  
   169  	fSys := makeMemoryFs(t)
   170  	addFiles(t, fSys, "/a", files)
   171  
   172  	checkRun(t, fSys, "/a", "/", "/dst")
   173  	fSysExpected := makeMemoryFs(t)
   174  	addFiles(t, fSysExpected, "/a", files)
   175  	addFiles(t, fSysExpected, "/dst/a", files)
   176  	checkFSys(t, fSysExpected, fSys)
   177  }
   178  
   179  func TestTargetIsScope(t *testing.T) {
   180  	kustomization := map[string]string{
   181  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   182  kind: Kustomization
   183  namePrefix: my-
   184  `,
   185  	}
   186  	fSysExpected, fSysActual := makeFileSystems(t, "/a", kustomization)
   187  
   188  	checkRun(t, fSysActual, "/a", "/a", "/a/b/dst")
   189  	addFiles(t, fSysExpected, "/a/b/dst", kustomization)
   190  	checkFSys(t, fSysExpected, fSysActual)
   191  }
   192  
   193  func TestTargetNestedInScope(t *testing.T) {
   194  	kustomization := map[string]string{
   195  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   196  kind: Kustomization
   197  patches:
   198  - patch: |-
   199      - op: replace
   200        path: /some/existing/path
   201        value: new value
   202    target:
   203      kind: Deployment
   204      labelSelector: env=dev
   205  `,
   206  	}
   207  	fSysExpected, fSysActual := makeFileSystems(t, "/a/b", kustomization)
   208  
   209  	checkRun(t, fSysActual, "/a/b", "/", "/a/b/dst")
   210  	addFiles(t, fSysExpected, "/a/b/dst/a/b", kustomization)
   211  	checkFSys(t, fSysExpected, fSysActual)
   212  }
   213  
   214  func TestLoadKustomizationName(t *testing.T) {
   215  	kustomization := map[string]string{
   216  		"Kustomization": `apiVersion: kustomize.config.k8s.io/v1beta1
   217  kind: Kustomization
   218  labels:
   219  - pairs:
   220      label-one: value-one
   221      label-two: value-two
   222  `,
   223  	}
   224  	checkLocalizeInTargetSuccess(t, kustomization)
   225  }
   226  
   227  func TestLoadGVKNN(t *testing.T) {
   228  	for name, kustomization := range map[string]string{
   229  		"missing": `namePrefix: my-
   230  `,
   231  		"wrong": `kind: NotChecked
   232  `,
   233  	} {
   234  		t.Run(name, func(t *testing.T) {
   235  			files := map[string]string{
   236  				"kustomization.yaml": kustomization,
   237  			}
   238  			checkLocalizeInTargetSuccess(t, files)
   239  		})
   240  	}
   241  }
   242  
   243  func TestLoadLegacyFields(t *testing.T) {
   244  	kustomization := map[string]string{
   245  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   246  commonLabels:
   247    app: bingo
   248  imageTags:
   249  - name: postgres
   250    newName: my-registry/my-postgres
   251    newTag: v1
   252  kind: Kustomization
   253  `,
   254  	}
   255  	checkLocalizeInTargetSuccess(t, kustomization)
   256  }
   257  
   258  func TestLoadUnknownKustFields(t *testing.T) {
   259  	fSysExpected, fSysTest := makeFileSystems(t, "/a", map[string]string{
   260  		"kustomization.yaml": `namePrefix: valid
   261  suffix: invalid`,
   262  	})
   263  
   264  	_, err := Run("/a", "", "", fSysTest)
   265  	require.EqualError(t, err,
   266  		`unable to localize target "/a": invalid Kustomization: json: unknown field "suffix"`)
   267  
   268  	checkFSys(t, fSysExpected, fSysTest)
   269  }
   270  
   271  func TestLocalizeFileName(t *testing.T) {
   272  	for name, path := range map[string]string{
   273  		"nested_directories":                  "a/b/c/d/patch.yaml",
   274  		"localize_dir_name_when_no_remote":    LocalizeDir,
   275  		"in_localize_dir_name_when_no_remote": fmt.Sprintf("%s/patch.yaml", LocalizeDir),
   276  		"no_file_extension":                   "patch",
   277  		"kustomization_name":                  "a/kustomization.yaml",
   278  	} {
   279  		t.Run(name, func(t *testing.T) {
   280  			kustAndPatch := map[string]string{
   281  				"kustomization.yaml": fmt.Sprintf(`apiVersion: kustomize.config.k8s.io/v1beta1
   282  kind: Kustomization
   283  patches:
   284  - path: %s
   285  `, path),
   286  				path: podConfiguration,
   287  			}
   288  			checkLocalizeInTargetSuccess(t, kustAndPatch)
   289  		})
   290  	}
   291  }
   292  
   293  func TestLocalizeFileCleaned(t *testing.T) {
   294  	kustAndPatch := map[string]string{
   295  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   296  kind: Kustomization
   297  patches:
   298  - path: ../gamma/../../../alpha/beta/./gamma/patch.yaml
   299  `,
   300  		"patch.yaml": podConfiguration,
   301  	}
   302  	expected, actual := makeFileSystems(t, "/alpha/beta/gamma", kustAndPatch)
   303  
   304  	checkRun(t, actual, "/alpha/beta/gamma", "/", "/localized-gamma")
   305  	addFiles(t, expected, "/localized-gamma/alpha/beta/gamma", map[string]string{
   306  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   307  kind: Kustomization
   308  patches:
   309  - path: patch.yaml
   310  `,
   311  		"patch.yaml": podConfiguration,
   312  	})
   313  	checkFSys(t, expected, actual)
   314  }
   315  
   316  func TestLocalizeUnreferencedIgnored(t *testing.T) {
   317  	targetAndUnreferenced := map[string]string{
   318  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   319  configMapGenerator:
   320  - envs:
   321    - env
   322    name: referenced-file
   323  kind: Kustomization
   324  `,
   325  		"env":               "APPLE=orange",
   326  		"env.properties":    "USERNAME=password",
   327  		"dir/resource.yaml": podConfiguration,
   328  	}
   329  	expected, actual := makeFileSystems(t, "/alpha/beta", targetAndUnreferenced)
   330  
   331  	checkRun(t, actual, "/alpha/beta", "/alpha", "/beta")
   332  	addFiles(t, expected, "/beta/beta", map[string]string{
   333  		"kustomization.yaml": targetAndUnreferenced["kustomization.yaml"],
   334  		"env":                targetAndUnreferenced["env"],
   335  	})
   336  	checkFSys(t, expected, actual)
   337  }
   338  
   339  func TestLocalizePatches(t *testing.T) {
   340  	kustAndPatch := map[string]string{
   341  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   342  kind: Kustomization
   343  patches:
   344  - patch: |-
   345      apiVersion: v1
   346      kind: Deployment
   347      metadata:
   348        labels:
   349          app.kubernetes.io/version: 1.21.0
   350        name: dummy-app
   351    target:
   352      labelSelector: app.kubernetes.io/name=nginx
   353  - options:
   354      allowNameChange: true
   355    path: patch.yaml
   356  `,
   357  		"patch.yaml": podConfiguration,
   358  	}
   359  	checkLocalizeInTargetSuccess(t, kustAndPatch)
   360  }
   361  
   362  func TestLocalizeOpenAPI(t *testing.T) {
   363  	type testCase struct {
   364  		name  string
   365  		files map[string]string
   366  	}
   367  	for _, test := range []testCase{
   368  		{
   369  			name: "no_path",
   370  			files: map[string]string{
   371  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   372  kind: Kustomization
   373  openapi:
   374    version: v1.20.4
   375  `,
   376  			},
   377  		},
   378  		{
   379  			name: "path",
   380  			files: map[string]string{
   381  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   382  kind: Kustomization
   383  openapi:
   384    path: openapi.json
   385  `,
   386  				"openapi.json": `{
   387    "definitions": {
   388      "io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": {
   389        "properties": {
   390          "name": {
   391            "type": "string"
   392          }
   393        },
   394        "type": "object"
   395      }
   396    }
   397  }`,
   398  			},
   399  		},
   400  	} {
   401  		t.Run(test.name, func(t *testing.T) {
   402  			checkLocalizeInTargetSuccess(t, test.files)
   403  		})
   404  	}
   405  }
   406  
   407  func TestLocalizeConfigurations(t *testing.T) {
   408  	kustAndConfigs := map[string]string{
   409  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   410  configurations:
   411  - commonLabels.yaml
   412  - namePrefix.yaml
   413  kind: Kustomization
   414  `,
   415  		"commonLabels.yaml": `commonLabels:
   416  - path: new/path
   417    create: true`,
   418  		"namePrefix.yaml": `namePrefix:
   419  - version: v1
   420    path: metadata/name
   421  - group: custom
   422    path: metadata/name`,
   423  	}
   424  	checkLocalizeInTargetSuccess(t, kustAndConfigs)
   425  }
   426  
   427  func TestLocalizeCrds(t *testing.T) {
   428  	kustAndCrds := map[string]string{
   429  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   430  crds:
   431  - crd1.yaml
   432  - crd2.yaml
   433  kind: Kustomization
   434  `,
   435  		"crd1.yaml": `apiVersion: apiextensions.k8s.io/v1
   436  kind: CustomResourceDefinition
   437  metadata:
   438    name: controller.stable.example.com`,
   439  		"crd2.yaml": `apiVersion: apiextensions.k8s.io/v1
   440  kind: CustomResourceDefinition
   441  metadata:
   442    name: crontabs.stable.example.com
   443  scope: Cluster`,
   444  	}
   445  	checkLocalizeInTargetSuccess(t, kustAndCrds)
   446  }
   447  
   448  func TestLocalizePatchesJson(t *testing.T) {
   449  	kustAndPatches := map[string]string{
   450  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   451  kind: Kustomization
   452  patchesJson6902:
   453  - path: patch.yaml
   454    target:
   455      annotationSelector: zone=west
   456      name: pod
   457      version: v1
   458  - patch: '[{"op": "add", "path": "/new/path", "value": "value"}]'
   459    target:
   460      group: apps
   461      kind: Pod
   462  - path: patch.json
   463    target:
   464      namespace: my
   465  `,
   466  		"patch.yaml": `- op: add
   467    path: /some/new/path
   468    value: value
   469  - op: replace
   470    path: /some/existing/path
   471    value: new value`,
   472  		"patch.json": ` [
   473     {"op": "copy", "from": "/here", "path": "/there"},
   474     {"op": "remove", "path": "/some/existing/path"},
   475   ]`,
   476  	}
   477  	checkLocalizeInTargetSuccess(t, kustAndPatches)
   478  }
   479  
   480  func TestLocalizePatchesSM(t *testing.T) {
   481  	kustAndPatches := map[string]string{
   482  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   483  kind: Kustomization
   484  patchesStrategicMerge:
   485  - |-
   486    apiVersion: v1
   487    kind: ConfigMap
   488    metadata:
   489      name: map
   490    data:
   491    - APPLE: orange
   492  - patch.yaml
   493  `,
   494  		"patch.yaml": podConfiguration,
   495  	}
   496  	checkLocalizeInTargetSuccess(t, kustAndPatches)
   497  }
   498  
   499  func TestLocalizeReplacements(t *testing.T) {
   500  	kustAndReplacement := map[string]string{
   501  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   502  kind: Kustomization
   503  replacements:
   504  - path: replacement.yaml
   505  - source:
   506      fieldPath: path.0
   507      name: map
   508    targets:
   509    - fieldPaths:
   510      - path
   511      select:
   512        name: my-map
   513  `,
   514  		"replacement.yaml": replacements,
   515  	}
   516  	checkLocalizeInTargetSuccess(t, kustAndReplacement)
   517  }
   518  
   519  func TestLocalizeConfigMapGenerator(t *testing.T) {
   520  	kustAndData := map[string]string{
   521  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   522  configMapGenerator:
   523  - env: single.env
   524    envs:
   525    - standard.env
   526    namespace: my
   527    options:
   528      immutable: true
   529  - behavior: merge
   530    files:
   531    - key.properties
   532    literals:
   533    - PEAR=pineapple
   534  kind: Kustomization
   535  metadata:
   536    name: test
   537  `,
   538  		"single.env": `MAY=contain
   539  MORE=than
   540  ONE=pair`,
   541  		"standard.env": `SIZE=0.1
   542  IS_GLOBAL=true`,
   543  		"key.properties": "value",
   544  	}
   545  	checkLocalizeInTargetSuccess(t, kustAndData)
   546  }
   547  
   548  func TestLocalizeSecretGenerator(t *testing.T) {
   549  	kustAndData := map[string]string{
   550  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   551  kind: Kustomization
   552  secretGenerator:
   553  - behavior: create
   554    files:
   555    - key=b/value.properties
   556    - b/value
   557    name: secret
   558  - envs:
   559    - crt
   560    - key
   561    type: kubernetes.io/tls
   562  - literals:
   563    - APPLE=orange
   564    - PLUM=pluot
   565    name: no-files
   566  - env: more-fruit
   567  `,
   568  		"crt":                "tls.crt=LS0tLS1CRUd...0tLQo=",
   569  		"key":                "tls.key=LS0tLS1CRUd...0tLQo=",
   570  		"more-fruit":         "GRAPE=lime",
   571  		"b/value.properties": "value",
   572  		"b/value":            "value",
   573  	}
   574  	checkLocalizeInTargetSuccess(t, kustAndData)
   575  }
   576  
   577  func TestLocalizeFileNoFile(t *testing.T) {
   578  	kustAndPatch := map[string]string{
   579  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   580  kind: Kustomization
   581  patches:
   582  - path: name-DNE.yaml
   583  `,
   584  	}
   585  	expected, actual := makeFileSystems(t, "/a/b", kustAndPatch)
   586  
   587  	_, err := Run("/a/b", "", "/dst", actual)
   588  	require.EqualError(t, err, `unable to localize target "/a/b": unable to localize patches: invalid file reference: '/a/b/name-DNE.yaml' doesn't exist`)
   589  
   590  	checkFSys(t, expected, actual)
   591  }
   592  
   593  func TestLocalizePluginsInlineAndFile(t *testing.T) {
   594  	for _, test := range []struct {
   595  		name  string
   596  		files map[string]string
   597  	}{
   598  		{
   599  			name: "generators",
   600  			files: map[string]string{
   601  				"kustomization.yaml": `generators:
   602  - generator.yaml
   603  - |
   604    apiVersion: builtin
   605    env: second.properties
   606    kind: ConfigMapGenerator
   607    metadata:
   608      name: inline
   609  `,
   610  				"generator.yaml": `apiVersion: builtin
   611  env: first.properties
   612  kind: ConfigMapGenerator
   613  metadata:
   614    name: file
   615  `,
   616  				"first.properties":  "APPLE=orange",
   617  				"second.properties": "BANANA=pear",
   618  			},
   619  		},
   620  		{
   621  			name: "transformers",
   622  			files: map[string]string{
   623  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   624  kind: Kustomization
   625  transformers:
   626  - |
   627    apiVersion: builtin
   628    kind: PatchTransformer
   629    metadata:
   630      name: inline
   631    path: patchSM-one.yaml
   632  - patch.yaml
   633  `,
   634  				"patch.yaml": `apiVersion: builtin
   635  kind: PatchTransformer
   636  metadata:
   637    name: file
   638  path: patchSM-two.yaml
   639  `,
   640  				"patchSM-one.yaml": podConfiguration,
   641  				"patchSM-two.yaml": podConfiguration,
   642  			},
   643  		},
   644  		{
   645  			name: "validators",
   646  			files: map[string]string{
   647  				"kustomization.yaml": `validators:
   648  - |
   649    apiVersion: builtin
   650    kind: ReplacementTransformer
   651    metadata:
   652      name: inline
   653    replacements:
   654    - path: first.yaml
   655  - second.yaml
   656  `,
   657  				"first.yaml":       replacementTransformerWithPath,
   658  				"second.yaml":      replacementTransformerWithPath,
   659  				"replacement.yaml": replacements,
   660  			},
   661  		},
   662  	} {
   663  		t.Run(test.name, func(t *testing.T) {
   664  			checkLocalizeInTargetSuccess(t, test.files)
   665  		})
   666  	}
   667  }
   668  
   669  func TestLocalizeMultiplePluginsInEntry(t *testing.T) {
   670  	kustAndPlugins := map[string]string{
   671  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   672  kind: Kustomization
   673  transformers:
   674  - |
   675    apiVersion: builtin
   676    kind: PatchTransformer
   677    metadata:
   678      name: one
   679    path: patchSM-one.yaml
   680    ---
   681    apiVersion: builtin
   682    kind: PatchTransformer
   683    metadata:
   684      name: two
   685    path: patchSM-two.yaml
   686  `,
   687  		"patchSM-one.yaml": podConfiguration,
   688  		"patchSM-two.yaml": podConfiguration,
   689  	}
   690  	checkLocalizeInTargetSuccess(t, kustAndPlugins)
   691  }
   692  
   693  func TestLocalizeCleanedPathInPath(t *testing.T) {
   694  	const patchf = `apiVersion: builtin
   695  kind: PatchTransformer
   696  metadata:
   697    name: cleaned-path
   698  path: %s
   699  `
   700  	kustAndPlugins := map[string]string{
   701  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   702  kind: Kustomization
   703  transformers:
   704  - patch.yaml
   705  `,
   706  		"patch.yaml":   fmt.Sprintf(patchf, "../a/patchSM.yaml"),
   707  		"patchSM.yaml": podConfiguration,
   708  	}
   709  	expected, actual := makeFileSystems(t, "/a", kustAndPlugins)
   710  
   711  	checkRun(t, actual, "/a", "/a", "/dst")
   712  	addFiles(t, expected, "/dst", map[string]string{
   713  		"kustomization.yaml": kustAndPlugins["kustomization.yaml"],
   714  		"patch.yaml":         fmt.Sprintf(patchf, "patchSM.yaml"),
   715  		"patchSM.yaml":       kustAndPlugins["patchSM.yaml"],
   716  	})
   717  	checkFSys(t, expected, actual)
   718  }
   719  
   720  func TestLocalizeGeneratorsConfigMap(t *testing.T) {
   721  	files := map[string]string{
   722  		"kustomization.yaml": `generators:
   723  - configMapGenerator
   724  `,
   725  		"configMapGenerator": `apiVersion: builtin
   726  behavior: create
   727  env: one.env
   728  envs:
   729  - two.env
   730  - three.env
   731  files:
   732  - four.properties
   733  - key=five.properties
   734  kind: ConfigMapGenerator
   735  metadata:
   736    name: custom-generator
   737  options:
   738    disableNameSuffix: true
   739  `,
   740  		"one.env":         "key1=value1",
   741  		"two.env":         "key2=value2",
   742  		"three.env":       "key3=value3",
   743  		"four.properties": "key4=value4",
   744  		"five.properties": "key5=value5",
   745  	}
   746  	checkLocalizeInTargetSuccess(t, files)
   747  }
   748  
   749  func TestLocalizeGeneratorsSecret(t *testing.T) {
   750  	files := map[string]string{
   751  		"kustomization.yaml": `generators:
   752  - secretGenerator
   753  `,
   754  		"secretGenerator": `apiVersion: builtin
   755  env: one.env
   756  envs:
   757  - two.env
   758  - three.env
   759  files:
   760  - four.properties
   761  - key=five.properties
   762  kind: SecretGenerator
   763  literals:
   764  - key6=value6
   765  metadata:
   766    name: custom-generator
   767  `,
   768  		"one.env":         "key1=value1",
   769  		"two.env":         "key2=value2",
   770  		"three.env":       "key3=value3",
   771  		"four.properties": "key4=value4",
   772  		"five.properties": "key5=value5",
   773  	}
   774  	checkLocalizeInTargetSuccess(t, files)
   775  }
   776  
   777  func TestLocalizeTransformersPatch(t *testing.T) {
   778  	kustAndPatches := map[string]string{
   779  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   780  kind: Kustomization
   781  transformers:
   782  - |
   783    apiVersion: builtin
   784    kind: PatchTransformer
   785    metadata:
   786      name: no-path
   787    patch: '[{"op": "add", "path": "/path", "value": "value"}]'
   788    target:
   789      name: pod
   790  - patch.yaml
   791  `,
   792  		"patch.yaml": `apiVersion: builtin
   793  kind: PatchTransformer
   794  metadata:
   795    name: path
   796  path: patchSM.yaml
   797  `,
   798  		"patchSM.yaml": podConfiguration,
   799  	}
   800  	checkLocalizeInTargetSuccess(t, kustAndPatches)
   801  }
   802  
   803  func TestLocalizeTransformersPatchJson(t *testing.T) {
   804  	kustAndPatches := map[string]string{
   805  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   806  kind: Kustomization
   807  transformers:
   808  - patch.yaml
   809  `,
   810  		"patch.yaml": `apiVersion: builtin
   811  kind: PatchJson6902Transformer
   812  metadata:
   813    name: path
   814  path: nested-patch.yaml
   815  target:
   816    name: pod
   817    namespace: test
   818  ---
   819  apiVersion: builtin
   820  jsonOp: |-
   821    op: replace
   822    path: /path
   823    value: new value
   824  kind: PatchJson6902Transformer
   825  metadata:
   826    name: patch6902
   827  target:
   828    name: deployment
   829  `,
   830  		"nested-patch.yaml": ` [
   831     {"op": "copy", "from": "/existing/path", "path": "/another/path"},
   832   ]
   833  `,
   834  	}
   835  	checkLocalizeInTargetSuccess(t, kustAndPatches)
   836  }
   837  
   838  func TestLocalizeTransformersPatchSM(t *testing.T) {
   839  	kustAndPatches := map[string]string{
   840  		"kustomization.yaml": `transformers:
   841  - patch.yaml
   842  `,
   843  		"patch.yaml": `apiVersion: builtin
   844  kind: PatchStrategicMergeTransformer
   845  metadata:
   846    name: path
   847  paths:
   848  - nested-patch.yaml
   849  - |-
   850    apiVersion: v1
   851    kind: Pod
   852    metadata:
   853      name: my-pod
   854  `,
   855  		"nested-patch.yaml": podConfiguration,
   856  	}
   857  	checkLocalizeInTargetSuccess(t, kustAndPatches)
   858  }
   859  
   860  func TestLocalizeTransformersReplacement(t *testing.T) {
   861  	kustAndReplacements := map[string]string{
   862  		"kustomization.yaml": `transformers:
   863  - replacement-transformer.yaml
   864  `,
   865  		"replacement-transformer.yaml": replacementTransformerWithPath,
   866  		"replacement.yaml":             replacements,
   867  	}
   868  	checkLocalizeInTargetSuccess(t, kustAndReplacements)
   869  }
   870  
   871  func TestLocalizePluginsNoPaths(t *testing.T) {
   872  	kustAndPlugins := map[string]string{
   873  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   874  kind: Kustomization
   875  transformers:
   876  - |
   877    apiVersion: different
   878    kind: MyTransformer
   879    metadata:
   880      name: still-copied
   881    path: /nothing/special
   882  - prefix.yaml
   883  `,
   884  		"prefix.yaml": `apiVersion: builtin
   885  kind: PrefixTransformer
   886  metadata:
   887    name: other-built-ins-still-copied
   888  prefix: copy
   889  `,
   890  	}
   891  	checkLocalizeInTargetSuccess(t, kustAndPlugins)
   892  }
   893  
   894  func TestLocalizeValidators(t *testing.T) {
   895  	kustAndPlugin := map[string]string{
   896  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   897  kind: Kustomization
   898  validators:
   899  - replacement-no-change.yaml
   900  `,
   901  		"replacement-no-change.yaml": replacementTransformerWithPath,
   902  		"replacement.yaml":           replacements,
   903  	}
   904  	checkLocalizeInTargetSuccess(t, kustAndPlugin)
   905  }
   906  
   907  func TestLocalizeBuiltinPlugins_SequenceScalarEquivalence(t *testing.T) {
   908  	kustomization := map[string]string{
   909  		"kustomization.yaml": `transformers:
   910  - |
   911    apiVersion: builtin
   912    kind: PatchTransformer
   913    metadata:
   914      name: path-should-be-scalar-but-accept-sequence
   915    path:
   916    - patchSM.yaml
   917  `,
   918  		"patchSM.yaml": podConfiguration,
   919  	}
   920  	checkLocalizeInTargetSuccess(t, kustomization)
   921  }
   922  
   923  func TestLocalizeBuiltinPlugins_NotResource(t *testing.T) {
   924  	type testCase struct {
   925  		name         string
   926  		files        map[string]string
   927  		errPrefix    string
   928  		inlineErrMsg string
   929  		fileErrMsg   string
   930  	}
   931  	for _, test := range []testCase{
   932  		{
   933  			name: "bad_inline_resource",
   934  			files: map[string]string{
   935  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   936  generators:
   937  - |
   938    apiVersion: builtin
   939    kind: ConfigMapGenerator
   940  kind: Kustomization
   941  `,
   942  			},
   943  			errPrefix:    `unable to load generators entry: unable to load resource entry "apiVersion: builtin\nkind: ConfigMapGenerator\n"`,
   944  			inlineErrMsg: `missing metadata.name in object {{builtin ConfigMapGenerator} {{ } map[] map[]}}`,
   945  			fileErrMsg: `invalid file reference: '/apiVersion: builtin
   946  kind: ConfigMapGenerator
   947  ' doesn't exist`,
   948  		},
   949  		{
   950  			name: "bad_file_resource",
   951  			files: map[string]string{
   952  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
   953  kind: Kustomization
   954  transformers:
   955  - plugin.yaml
   956  `,
   957  				"plugin.yaml": `apiVersion: builtin
   958  metadata:
   959    name: PatchTransformer
   960  `,
   961  			},
   962  			errPrefix:    `unable to load transformers entry: unable to load resource entry "plugin.yaml"`,
   963  			inlineErrMsg: `missing Resource metadata`,
   964  			fileErrMsg:   `missing kind in object {{builtin } {{PatchTransformer } map[] map[]}}`,
   965  		},
   966  	} {
   967  		t.Run(test.name, func(t *testing.T) {
   968  			expected, actual := makeFileSystems(t, "/", test.files)
   969  
   970  			_, err := Run("/", "", "/dst", actual)
   971  
   972  			var actualErr ResourceLoadError
   973  			require.ErrorAs(t, err, &actualErr)
   974  			require.EqualError(t, actualErr.InlineError, test.inlineErrMsg)
   975  			require.EqualError(t, actualErr.FileError, test.fileErrMsg)
   976  
   977  			require.EqualError(t, err, fmt.Sprintf(`unable to localize target "/": %s: when parsing as inline received error: %s
   978  when parsing as filepath received error: %s`, test.errPrefix, test.inlineErrMsg, test.fileErrMsg))
   979  
   980  			checkFSys(t, expected, actual)
   981  		})
   982  	}
   983  }
   984  
   985  func TestLocalizeBuiltinPlugins_Errors(t *testing.T) {
   986  	for name, test := range map[string]struct {
   987  		files        map[string]string
   988  		fieldSpecErr string
   989  		locErr       string
   990  	}{
   991  		"file_dne": {
   992  			files: map[string]string{
   993  				"kustomization.yaml": `transformers:
   994  - |
   995    apiVersion: builtin
   996    kind: PatchTransformer
   997    metadata:
   998      name: file-does-not-exist
   999    path: patchSM.yaml
  1000  `,
  1001  			},
  1002  			fieldSpecErr: "considering field 'path' of object PatchTransformer.builtin.[noGrp]/file-does-not-exist.[noNs]",
  1003  			locErr:       "invalid file reference: '/a/patchSM.yaml' doesn't exist",
  1004  		},
  1005  		"not_sequence_or_scalar": {
  1006  			files: map[string]string{
  1007  				"kustomization.yaml": `transformers:
  1008  - |
  1009    apiVersion: builtin
  1010    kind: PatchTransformer
  1011    metadata:
  1012      name: path-node-has-wrong-kind
  1013    path:
  1014      mappingNode: patchSM.yaml
  1015  `,
  1016  				"patchSM.yaml": podConfiguration,
  1017  			},
  1018  			fieldSpecErr: "considering field 'path' of object PatchTransformer.builtin.[noGrp]/path-node-has-wrong-kind.[noNs]",
  1019  			locErr:       "expected sequence or scalar node",
  1020  		},
  1021  	} {
  1022  		t.Run(name, func(t *testing.T) {
  1023  			expected, actual := makeFileSystems(t, "/a", test.files)
  1024  			_, err := Run("/a", "", "/dst", actual)
  1025  			const errPrefix = `unable to localize target "/a"`
  1026  			require.EqualError(t, err, fmt.Sprintf(
  1027  				"%s: %s: %s", errPrefix, test.fieldSpecErr, test.locErr))
  1028  			checkFSys(t, expected, actual)
  1029  		})
  1030  	}
  1031  }
  1032  
  1033  func TestLocalizeDirInTarget(t *testing.T) {
  1034  	type testCase struct {
  1035  		name  string
  1036  		files map[string]string
  1037  	}
  1038  	for _, tc := range []testCase{
  1039  		{
  1040  			name: "multi_nested_child",
  1041  			files: map[string]string{
  1042  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1043  components:
  1044  - delta/epsilon
  1045  kind: Kustomization
  1046  `,
  1047  				"delta/epsilon/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1048  kind: Component
  1049  namespace: kustomize-namespace
  1050  `,
  1051  			},
  1052  		},
  1053  		{
  1054  			name: "recursive",
  1055  			files: map[string]string{
  1056  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1057  components:
  1058  - delta
  1059  kind: Kustomization
  1060  `,
  1061  				"delta/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1062  components:
  1063  - epsilon
  1064  kind: Component
  1065  `,
  1066  				"delta/epsilon/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1067  kind: Component
  1068  namespace: kustomize-namespace
  1069  `,
  1070  			},
  1071  		},
  1072  		{
  1073  			name: "file_in_dir",
  1074  			files: map[string]string{
  1075  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1076  components:
  1077  - delta
  1078  kind: Kustomization
  1079  `,
  1080  				"delta/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1081  kind: Component
  1082  patches:
  1083  - path: patch.yaml
  1084  `,
  1085  				"delta/patch.yaml": podConfiguration,
  1086  			},
  1087  		},
  1088  		{
  1089  			name: "multiple_calls",
  1090  			files: map[string]string{
  1091  				"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1092  components:
  1093  - delta
  1094  - delta/epsilon
  1095  kind: Kustomization
  1096  `,
  1097  				"delta/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1098  kind: Component
  1099  namespace: kustomize-namespace
  1100  `,
  1101  				"delta/epsilon/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1102  buildMetadata:
  1103  - managedByLabel
  1104  kind: Component
  1105  `,
  1106  			},
  1107  		},
  1108  		{
  1109  			name: "localize_directory_name_when_no_remote",
  1110  			files: map[string]string{
  1111  				"kustomization.yaml": fmt.Sprintf(`apiVersion: kustomize.config.k8s.io/v1beta1
  1112  components:
  1113  - %s
  1114  kind: Kustomization
  1115  `, LocalizeDir),
  1116  				fmt.Sprintf("%s/kustomization.yaml", LocalizeDir): `apiVersion: kustomize.config.k8s.io/v1alpha1
  1117  kind: Component
  1118  namespace: kustomize-namespace
  1119  `,
  1120  			},
  1121  		},
  1122  	} {
  1123  		t.Run(tc.name, func(t *testing.T) {
  1124  			checkLocalizeInTargetSuccess(t, tc.files)
  1125  		})
  1126  	}
  1127  }
  1128  
  1129  func TestLocalizeDirCleanedSibling(t *testing.T) {
  1130  	kustAndComponents := map[string]string{
  1131  		// This test checks that winding paths that might traverse through directories
  1132  		// outside of scope, which will not be present at destination, are cleaned.
  1133  		"beta/gamma/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1134  components:
  1135  - delta/../../../../a/b/../../alpha/beta/sibling
  1136  kind: Kustomization`,
  1137  		"beta/sibling/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1138  kind: Component
  1139  namespace: kustomize-namespace
  1140  `,
  1141  	}
  1142  	expected, actual := makeFileSystems(t, "/alpha", kustAndComponents)
  1143  
  1144  	checkRun(t, actual, "/alpha/beta/gamma", "/alpha", "/alpha/beta/dst")
  1145  	cleanedFiles := map[string]string{
  1146  		"beta/gamma/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1147  components:
  1148  - ../sibling
  1149  kind: Kustomization
  1150  `,
  1151  		"beta/sibling/kustomization.yaml": kustAndComponents["beta/sibling/kustomization.yaml"],
  1152  	}
  1153  	addFiles(t, expected, "/alpha/beta/dst", cleanedFiles)
  1154  	checkFSys(t, expected, actual)
  1155  }
  1156  
  1157  func TestLocalizeBases(t *testing.T) {
  1158  	kustAndBases := map[string]string{
  1159  		"kustomization.yaml": `bases:
  1160  - b
  1161  - c/d
  1162  `,
  1163  		"b/kustomization.yaml": `kind: Kustomization
  1164  `,
  1165  		"c/d/kustomization.yaml": `kind: Kustomization
  1166  `,
  1167  	}
  1168  	checkLocalizeInTargetSuccess(t, kustAndBases)
  1169  }
  1170  
  1171  func TestLocalizeComponents(t *testing.T) {
  1172  	kustAndComponents := map[string]string{
  1173  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1174  components:
  1175  - a
  1176  - alpha
  1177  kind: Kustomization
  1178  `,
  1179  		"a/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1180  kind: Component
  1181  namePrefix: my-
  1182  `,
  1183  		"alpha/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1alpha1
  1184  kind: Component
  1185  nameSuffix: -test
  1186  `,
  1187  	}
  1188  	checkLocalizeInTargetSuccess(t, kustAndComponents)
  1189  }
  1190  
  1191  func TestLocalizeResources(t *testing.T) {
  1192  	kustAndResources := map[string]string{
  1193  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1194  kind: Kustomization
  1195  resources:
  1196  - pod.yaml
  1197  - ../../alpha
  1198  `,
  1199  		"pod.yaml": podConfiguration,
  1200  		"../../alpha/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1201  kind: Kustomization
  1202  namePrefix: my-
  1203  `,
  1204  	}
  1205  	expected, actual := makeFileSystems(t, "/a/b", kustAndResources)
  1206  
  1207  	checkRun(t, actual, "/a/b", "/", "/localized-b")
  1208  	addFiles(t, expected, "/localized-b/a/b", kustAndResources)
  1209  	checkFSys(t, expected, actual)
  1210  }
  1211  
  1212  func TestLocalizePathError(t *testing.T) {
  1213  	kustAndResources := map[string]string{
  1214  		"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1215  kind: Kustomization
  1216  resources:
  1217  - b
  1218  `,
  1219  	}
  1220  	expected, actual := makeFileSystems(t, "/a", kustAndResources)
  1221  
  1222  	_, err := Run("/a", "/", "", actual)
  1223  
  1224  	const expectedFileErr = `invalid file reference: '/a/b' must resolve to a file`
  1225  	const expectedRootErr = `unable to localize root "b": unable to find one of 'kustomization.yaml', 'kustomization.yml' or 'Kustomization' in directory '/a/b'`
  1226  	var actualErr PathLocalizeError
  1227  	require.ErrorAs(t, err, &actualErr)
  1228  	require.Equal(t, "b", actualErr.Path)
  1229  	require.EqualError(t, actualErr.FileError, expectedFileErr)
  1230  	require.EqualError(t, actualErr.RootError, expectedRootErr)
  1231  
  1232  	const expectedErrPrefix = `unable to localize target "/a": unable to localize resources entry`
  1233  	require.EqualError(t, err, fmt.Sprintf(`%s: could not localize path "b" as file: %s; could not localize path "b" as directory: %s`,
  1234  		expectedErrPrefix, expectedFileErr, expectedRootErr))
  1235  
  1236  	checkFSys(t, expected, actual)
  1237  }
  1238  
  1239  func TestLocalizeHelmChartInflationGenerator(t *testing.T) {
  1240  	helmKust := map[string]string{
  1241  		"kustomization.yaml": `helmChartInflationGenerator:
  1242  - chartName: nothing-to-localize
  1243    chartRepoUrl: https://itzg.github.io/warcraft-server-charts
  1244    releaseName: moria
  1245  - chartName: localize-values
  1246    values: minecraftValues.yaml
  1247    valuesLocal:
  1248      minecraftServer:
  1249        eula: true
  1250    valuesMerge: replace
  1251  - chartHome: home
  1252    chartName: copy-chartHome
  1253  `,
  1254  		"minecraftValues.yaml":               valuesFile,
  1255  		"charts/localize-values/values.yaml": valuesFile,
  1256  		"home/copy-chartHome/values.yaml":    valuesFile,
  1257  	}
  1258  	checkLocalizeInTargetSuccess(t, helmKust)
  1259  }
  1260  
  1261  func TestLocalizeHelmCharts(t *testing.T) {
  1262  	for _, test := range []struct {
  1263  		name  string
  1264  		files map[string]string
  1265  	}{
  1266  		{
  1267  			name: "charts_only",
  1268  			files: map[string]string{
  1269  				"kustomization.yaml": `helmCharts:
  1270  - name: nothing-to-localize
  1271    repo: https://helm.releases.hashicorp.com
  1272    version: 1.0.0
  1273  - includeCRDs: true
  1274    name: localize-valuesFile
  1275    valuesFile: file
  1276  - additionalValuesFiles:
  1277    - another
  1278    - third
  1279  `,
  1280  				"file":                                   valuesFile,
  1281  				"another":                                valuesFile,
  1282  				"third":                                  valuesFile,
  1283  				"charts/nothing-to-localize/values.yaml": valuesFile,
  1284  				"charts/localize-valuesFile/values.yaml": valuesFile,
  1285  			},
  1286  		},
  1287  		{
  1288  			name: "charts_globals_no_home",
  1289  			files: map[string]string{
  1290  				"kustomization.yaml": `helmCharts:
  1291  - name: default
  1292  helmGlobals:
  1293    configHome: .
  1294  `,
  1295  				"charts/default/values.yaml": valuesFile,
  1296  			},
  1297  		},
  1298  		{
  1299  			name: "home_only",
  1300  			files: map[string]string{
  1301  				"kustomization.yaml": `helmGlobals:
  1302    chartHome: home
  1303  `,
  1304  				"home/name/values.yaml": valuesFile,
  1305  			},
  1306  		},
  1307  	} {
  1308  		t.Run(test.name, func(t *testing.T) {
  1309  			checkLocalizeInTargetSuccess(t, test.files)
  1310  		})
  1311  	}
  1312  }
  1313  
  1314  func TestLocalizeHelmChartsNoDefault(t *testing.T) {
  1315  	files := map[string]string{
  1316  		"kustomization.yaml": `helmGlobals:
  1317    chartHome: home
  1318  `,
  1319  		"home/name/values.yaml":   valuesFile,
  1320  		"charts/name/values.yaml": valuesFile,
  1321  	}
  1322  	expected, actual := makeFileSystems(t, "/a", files)
  1323  
  1324  	checkRun(t, actual, "/a", "/a", "/dst")
  1325  	addFiles(t, expected, "/dst", map[string]string{
  1326  		"kustomization.yaml":    files["kustomization.yaml"],
  1327  		"home/name/values.yaml": valuesFile,
  1328  	})
  1329  	checkFSys(t, expected, actual)
  1330  }
  1331  
  1332  func TestCopyChartHomeSimple(t *testing.T) {
  1333  	for _, test := range []struct {
  1334  		name  string
  1335  		files map[string]string
  1336  	}{
  1337  		{
  1338  			name: "does_not_exist",
  1339  			files: map[string]string{
  1340  				"kustomization.yaml": `helmGlobals:
  1341    chartHome: untar-dir
  1342  `,
  1343  			},
  1344  		},
  1345  		{
  1346  			name: "chart_home_structure",
  1347  			files: map[string]string{
  1348  				"kustomization.yaml": `helmGlobals:
  1349    chartHome: home
  1350  `,
  1351  				"home/minecraft-3.1.3.tgz": "blah",
  1352  				"home/terraform-1.0.0.tgz": "la",
  1353  				"home/minecraft/Chart.yaml": `annotations:
  1354    artifacthub.io/links: |
  1355    - name: source
  1356      url: https://minecraft.net/
  1357  `,
  1358  				"home/terraform/Chart.yaml": `description: Minecraft server
  1359  `,
  1360  			},
  1361  		},
  1362  	} {
  1363  		t.Run(test.name, func(t *testing.T) {
  1364  			checkLocalizeInTargetSuccess(t, test.files)
  1365  		})
  1366  	}
  1367  }
  1368  
  1369  func TestCopyChartHomeChanges(t *testing.T) {
  1370  	for name, test := range map[string]struct {
  1371  		files       map[string]string
  1372  		copiedFiles map[string]string
  1373  	}{
  1374  		"clean_does_not_exist": {
  1375  			files: map[string]string{
  1376  				"kustomization.yaml": `helmGlobals:
  1377    chartHome: ../b/home
  1378  `,
  1379  			},
  1380  			copiedFiles: map[string]string{
  1381  				"kustomization.yaml": `helmGlobals:
  1382    chartHome: home
  1383  `,
  1384  			},
  1385  		},
  1386  		"clean_default": {
  1387  			files: map[string]string{
  1388  				"kustomization.yaml": `helmGlobals:
  1389    chartHome: ../b/charts
  1390  `,
  1391  				"charts/name/values.yaml": valuesFile,
  1392  			},
  1393  			copiedFiles: map[string]string{
  1394  				"kustomization.yaml": `helmGlobals:
  1395    chartHome: charts
  1396  `,
  1397  				"charts/name/values.yaml": valuesFile,
  1398  			},
  1399  		},
  1400  		"not_copied": {
  1401  			files: map[string]string{
  1402  				"kustomization.yaml": `helmCharts:
  1403  - name: name
  1404    valuesFile: home/name/values.yaml
  1405  helmGlobals:
  1406    chartHome: home
  1407  `,
  1408  				"home/name/values.yaml":      valuesFile,
  1409  				"home/name/many-other-files": "other contents",
  1410  			},
  1411  			copiedFiles: map[string]string{
  1412  				"kustomization.yaml": `helmCharts:
  1413  - name: name
  1414    valuesFile: home/name/values.yaml
  1415  helmGlobals:
  1416    chartHome: home
  1417  `,
  1418  				"home/name/values.yaml": valuesFile,
  1419  			},
  1420  		},
  1421  		"does_not_exist_exits_scope": {
  1422  			files: map[string]string{
  1423  				"kustomization.yaml": `helmGlobals:
  1424    chartHome: ../home
  1425  `,
  1426  				"../../home/will-exist-at-dst/values.yaml": valuesFile,
  1427  			},
  1428  			copiedFiles: map[string]string{
  1429  				"kustomization.yaml": `helmGlobals:
  1430    chartHome: ../home
  1431  `,
  1432  			},
  1433  		},
  1434  	} {
  1435  		t.Run(name, func(t *testing.T) {
  1436  			expected, actual := makeFileSystems(t, "/a/b", test.files)
  1437  
  1438  			checkRun(t, actual, "/a/b", "/a/b", "/dst")
  1439  			addFiles(t, expected, "/dst", test.copiedFiles)
  1440  			checkFSys(t, expected, actual)
  1441  		})
  1442  	}
  1443  }
  1444  
  1445  func TestCopyChartHomeEmpty(t *testing.T) {
  1446  	kustomization := map[string]string{
  1447  		"kustomization.yaml": `helmGlobals:
  1448    chartHome: home
  1449  `,
  1450  	}
  1451  	expected, actual := makeFileSystems(t, "/a", kustomization)
  1452  	require.NoError(t, actual.Mkdir("/a/home"))
  1453  	require.NoError(t, expected.Mkdir("/a/home"))
  1454  
  1455  	checkRun(t, actual, "/a", "/a", "/dst")
  1456  	addFiles(t, expected, "/dst", kustomization)
  1457  	require.NoError(t, expected.Mkdir("/dst/home"))
  1458  	checkFSys(t, expected, actual)
  1459  }
  1460  
  1461  func TestCopyChartHomeError(t *testing.T) {
  1462  	for name, test := range map[string]struct {
  1463  		err   string
  1464  		files map[string]string
  1465  	}{
  1466  		"absolute": {
  1467  			err: `unable to copy helmGlobals: absolute path "/a/b/home" not handled in alpha`,
  1468  			files: map[string]string{
  1469  				"a/b/kustomization.yaml": `helmGlobals:
  1470    chartHome: /a/b/home
  1471  `,
  1472  				"a/b/home/name/values.yaml": valuesFile,
  1473  			},
  1474  		},
  1475  		"file": {
  1476  			err: `unable to copy helmGlobals: unable to copy home "home": invalid chart home: invalid root reference: must build at directory: '/a/b/home': file is not directory`,
  1477  			files: map[string]string{
  1478  				"a/b/kustomization.yaml": `helmGlobals:
  1479    chartHome: home
  1480  `,
  1481  				"a/b/home": valuesFile,
  1482  			},
  1483  		},
  1484  		"scope": {
  1485  			err: `unable to copy helmGlobals: unable to copy home "../../alpha/home": invalid chart home: root "/alpha/home" outside localize scope "/a"`,
  1486  			files: map[string]string{
  1487  				"a/b/kustomization.yaml": `helmGlobals:
  1488    chartHome: ../../alpha/home
  1489  `,
  1490  				"alpha/home/values.yaml": valuesFile,
  1491  			},
  1492  		},
  1493  	} {
  1494  		t.Run(name, func(t *testing.T) {
  1495  			expected, actual := makeFileSystems(t, "/", test.files)
  1496  
  1497  			_, err := Run("/a/b", "/a", "/dst", actual)
  1498  			const prefix = `unable to localize target "/a/b"`
  1499  			require.EqualError(t, err, fmt.Sprintf("%s: %s", prefix, test.err))
  1500  
  1501  			checkFSys(t, expected, actual)
  1502  		})
  1503  	}
  1504  }
  1505  
  1506  func TestLocalizeGeneratorsHelm(t *testing.T) {
  1507  	files := map[string]string{
  1508  		"kustomization.yaml": `generators:
  1509  - default.yaml
  1510  - explicit.yaml
  1511  `,
  1512  		"default.yaml": `apiVersion: builtin
  1513  kind: HelmChartInflationGenerator
  1514  metadata:
  1515    name: no-explicit-references
  1516  name: minecraft
  1517  releaseName: moria
  1518  repo: https://itzg.github.io/minecraft-server-charts
  1519  version: 3.1.3
  1520  `,
  1521  		"explicit.yaml": `additionalValuesFiles:
  1522  - time.yaml
  1523  - life.yaml
  1524  - light.yaml
  1525  apiVersion: builtin
  1526  chartHome: home
  1527  kind: HelmChartInflationGenerator
  1528  metadata:
  1529    name: explicit-references
  1530  name: mapleStory
  1531  valuesFile: mapleValues.yaml
  1532  `,
  1533  		"time.yaml":                    valuesFile,
  1534  		"life.yaml":                    valuesFile,
  1535  		"light.yaml":                   valuesFile,
  1536  		"mapleValues.yaml":             valuesFile,
  1537  		"home/mapleStory/values.yaml":  valuesFile,
  1538  		"charts/minecraft/values.yaml": valuesFile,
  1539  	}
  1540  	checkLocalizeInTargetSuccess(t, files)
  1541  }
  1542  
  1543  func TestLocalizeGeneratorsNoHelm(t *testing.T) {
  1544  	files := map[string]string{
  1545  		"kustomization.yaml": `generators:
  1546  - configMap.yaml
  1547  `,
  1548  		"configMap.yaml": `apiVersion: builtin
  1549  kind: ConfigMapGenerator
  1550  literals:
  1551  - APPLE=orange
  1552  metadata:
  1553    name: not-helm-shouldn't-copy-default-helm-chart-home
  1554  `,
  1555  		"charts/minecraft/values.yaml": valuesFile,
  1556  	}
  1557  	expected, actual := makeFileSystems(t, "/a", files)
  1558  
  1559  	checkRun(t, actual, "/a", "/a", "/dst")
  1560  	addFiles(t, expected, "/dst", map[string]string{
  1561  		"kustomization.yaml": files["kustomization.yaml"],
  1562  		"configMap.yaml":     files["configMap.yaml"],
  1563  	})
  1564  	checkFSys(t, expected, actual)
  1565  }
  1566  
  1567  func TestLocalizeEmpty(t *testing.T) {
  1568  	for name, kustomization := range map[string]string{
  1569  		"file": `configurations:
  1570  - ""
  1571  `,
  1572  		"root": `bases:
  1573  - ""
  1574  `,
  1575  		"resource": `resources:
  1576  - ""
  1577  `,
  1578  		"generator_file_src": `configMapGenerator:
  1579  - files:
  1580    - ""
  1581  `,
  1582  		"patchesStrategicMerge": `patchesStrategicMerge:
  1583  - ""
  1584  `,
  1585  		"custom_transformers": `transformers:
  1586  - ""
  1587  `,
  1588  		"custom_transformer_field": `transformers:
  1589  - |
  1590    apiVersion: builtin
  1591    kind: PatchStrategicMergeTransformer
  1592    metadata:
  1593      name: empty
  1594    paths:
  1595    - ""
  1596  `,
  1597  	} {
  1598  		t.Run(name, func(t *testing.T) {
  1599  			checkLocalizeInTargetSuccess(t, map[string]string{
  1600  				"kustomization.yaml": kustomization,
  1601  			})
  1602  		})
  1603  	}
  1604  }
  1605  

View as plain text