Files
kustomize/api/krusty/component_test.go
Varsha Prasad Narsing 7911b2c001 [refactor]: Internalize loader api
This PR intends to move the loader api to
internal. Only the necessary methods which
are needed for the api have been put into
`pkg/loader.go`.

Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
2023-09-28 10:49:45 -04:00

770 lines
14 KiB
Go

// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/internal/loader"
"sigs.k8s.io/kustomize/api/konfig"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
type FileGen func(kusttest_test.Harness)
func writeC(path string, content string) FileGen {
return func(th kusttest_test.Harness) {
th.WriteC(path, content)
}
}
func writeF(path string, content string) FileGen {
return func(th kusttest_test.Harness) {
th.WriteF(path, content)
}
}
func writeK(path string, content string) FileGen {
return func(th kusttest_test.Harness) {
th.WriteK(path, content)
}
}
func writeTestBase(th kusttest_test.Harness) {
th.WriteK("base", `
resources:
- deploy.yaml
configMapGenerator:
- name: my-configmap
literals:
- testValue=purple
- otherValue=green
`)
th.WriteF("base/deploy.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
`)
}
func writeTestComponent(th kusttest_test.Harness) {
th.WriteC("comp", `
namePrefix: comp-
replicas:
- name: storefront
count: 3
resources:
- stub.yaml
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- testValue=blue
- compValue=red
`)
th.WriteF("comp/stub.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: stub
spec:
replicas: 1
`)
}
func writeOverlayProd(th kusttest_test.Harness) {
th.WriteK("prod", `
resources:
- ../base
- db
components:
- ../comp
`)
writeDB(th)
}
func writeDB(th kusttest_test.Harness) {
deployment("db", "prod/db")(th)
}
func deployment(name string, path string) FileGen {
return writeF(path, fmt.Sprintf(`
apiVersion: v1
kind: Deployment
metadata:
name: %s
spec:
type: Logical
`, name))
}
func TestComponent(t *testing.T) {
testCases := map[string]struct {
input []FileGen
runPath string
expectedOutput string
}{
// Components are inserted into the resource hierarchy as the parent of those
// resources that come before it in the resources list of the parent Kustomization.
"basic-component": {
input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd},
runPath: "prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: red
otherValue: green
testValue: blue
kind: ConfigMap
metadata:
name: comp-my-configmap-97647ckcmg
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
"multiple-components": {
input: []FileGen{writeTestBase, writeTestComponent, writeDB,
writeC("additionalcomp", `
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=orange
`),
writeK("prod", `
resources:
- ../base
- db
components:
- ../comp
- ../additionalcomp
`),
},
runPath: "prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: red
otherValue: orange
testValue: blue
kind: ConfigMap
metadata:
name: comp-my-configmap-g486mb229k
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
"nested-components": {
input: []FileGen{writeTestBase, writeTestComponent, writeDB,
writeC("additionalcomp", `
components:
- ../comp
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=orange
`),
writeK("prod", `
resources:
- ../base
- db
components:
- ../additionalcomp
`),
},
runPath: "prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: red
otherValue: orange
testValue: blue
kind: ConfigMap
metadata:
name: comp-my-configmap-g486mb229k
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
// If a component sets a name prefix on a base, then that base can also be separately included
// without being affected by the component in another branch of the resource tree
"basic-component-with-repeated-base": {
input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd,
writeK("repeated", `
resources:
- ../base
- ../prod
`),
},
runPath: "repeated",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: green
testValue: purple
kind: ConfigMap
metadata:
name: my-configmap-9cd648hm8f
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: red
otherValue: green
testValue: blue
kind: ConfigMap
metadata:
name: comp-my-configmap-97647ckcmg
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
"applying-component-directly-should-be-same-as-kustomization": {
input: []FileGen{writeTestBase, writeTestComponent,
writeC("direct-component", `
resources:
- ../base
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- compValue=red
- testValue=blue
`),
},
runPath: "direct-component",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
---
apiVersion: v1
data:
compValue: red
otherValue: green
testValue: blue
kind: ConfigMap
metadata:
name: my-configmap-97647ckcmg
`,
},
"missing-optional-component-api-version": {
input: []FileGen{writeTestBase, writeOverlayProd,
writeF("comp/"+konfig.DefaultKustomizationFileName(), `
kind: Component
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=orange
`),
},
runPath: "prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: orange
testValue: purple
kind: ConfigMap
metadata:
name: my-configmap-6hhdg8gkdg
---
apiVersion: v1
kind: Deployment
metadata:
name: db
spec:
type: Logical
`,
},
// See how nameSuffix "-b" is also added to the resources included by "comp-a" because they are in the
// accumulator when "comp-b" is accumulated. In practice we could use simple Kustomizations for this example.
"components-can-add-the-same-base-if-the-first-renames-resources": {
input: []FileGen{writeTestBase,
deployment("proxy", "comp-a/proxy.yaml"),
writeC("comp-a", `
resources:
- ../base
nameSuffix: "-a"
`),
writeC("comp-b", `
resources:
- ../base
nameSuffix: "-b"
`),
writeK("prod", `
components:
- ../comp-a
- ../comp-b`),
},
runPath: "prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront-a-b
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: green
testValue: purple
kind: ConfigMap
metadata:
name: my-configmap-a-b-9cd648hm8f
---
apiVersion: v1
kind: Deployment
metadata:
name: storefront-b
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: green
testValue: purple
kind: ConfigMap
metadata:
name: my-configmap-b-9cd648hm8f
`,
},
"multiple-bases-can-add-the-same-component-if-it-doesn-not-define-named-entities": {
input: []FileGen{
writeC("comp", `
namespace: prod
`),
writeK("base-a", `
resources:
- proxy.yaml
components:
- ../comp
`),
deployment("proxy-a", "base-a/proxy.yaml"),
writeK("base-b", `
resources:
- proxy.yaml
components:
- ../comp
`),
deployment("proxy-b", "base-b/proxy.yaml"),
writeK("prod", `
resources:
- proxy.yaml
- ../base-a
- ../base-b
`),
deployment("proxy-prod", "prod/proxy.yaml"),
},
runPath: "prod",
// Note that the namepsace has not been applied to proxy-prod because it was not in scope when the
// component was applied
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: proxy-prod
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: proxy-a
namespace: prod
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: proxy-b
namespace: prod
spec:
type: Logical
`,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
th := kusttest_test.MakeHarness(t)
for _, f := range tc.input {
f(th)
}
m := th.Run(tc.runPath, th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, tc.expectedOutput)
})
}
}
func TestComponentErrors(t *testing.T) {
testCases := map[string]struct {
input []FileGen
runPath string
expectedError string
}{
"components-cannot-be-added-to-resources": {
input: []FileGen{writeTestBase, writeTestComponent,
writeK("compinres", `
resources:
- ../base
- ../comp
`),
},
runPath: "compinres",
expectedError: "expected kind != 'Component' for path '/comp'",
},
"kustomizations-cannot-be-added-to-components": {
input: []FileGen{writeTestBase, writeTestComponent,
writeK("kustincomponents", `
components:
- ../base
- ../comp
`),
},
runPath: "kustincomponents",
expectedError: "accumulating components: accumulateDirectory: \"expected kind 'Component' for path " +
"'/base' but got 'Kustomization'",
},
"files-cannot-be-added-to-components-list": {
input: []FileGen{writeTestBase,
writeF("filesincomponents/stub.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: stub
spec:
replicas: 1
`),
writeK("filesincomponents", `
components:
- stub.yaml
- ../comp
`),
},
runPath: "filesincomponents",
expectedError: fmt.Sprintf("%s: '%s'", loader.ErrRtNotDir.Error(), "/filesincomponents/stub.yaml"),
},
"invalid-component-api-version": {
input: []FileGen{writeTestBase, writeOverlayProd,
writeF("comp/"+konfig.DefaultKustomizationFileName(), `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Component
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=orange
`),
},
runPath: "prod",
expectedError: "apiVersion for Component should be kustomize.config.k8s.io/v1alpha1",
},
"components-cannot-add-the-same-resource": {
input: []FileGen{writeTestBase,
writeC("comp-a", `
resources:
- proxy.yaml
`),
deployment("proxy", "comp-a/proxy.yaml"),
writeC("comp-b", `
resources:
- proxy.yaml
`),
deployment("proxy", "comp-b/proxy.yaml"),
writeK("prod", `
resources:
- ../base
components:
- ../comp-a
- ../comp-b`),
},
runPath: "prod",
expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/proxy.[noNs]",
},
"components-cannot-add-the-same-base": {
input: []FileGen{writeTestBase,
deployment("proxy", "comp-a/proxy.yaml"),
writeC("comp-a", `
resources:
- ../base
`),
writeC("comp-b", `
resources:
- ../base
`),
writeK("prod", `
components:
- ../comp-a
- ../comp-b`),
},
runPath: "prod",
expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/storefront.[noNs]",
},
"components-cannot-add-bases-containing-the-same-resource": {
input: []FileGen{writeTestBase,
writeC("comp-a", `
resources:
- ../base-a
`),
writeK("base-a", `
resources:
- proxy.yaml
`),
deployment("proxy", "base-a/proxy.yaml"),
writeC("comp-b", `
resources:
- ../base-b
`),
writeK("base-b", `
resources:
- proxy.yaml
`),
deployment("proxy", "base-b/proxy.yaml"),
writeK("prod", `
resources:
- ../base
components:
- ../comp-a
- ../comp-b`),
},
runPath: "prod",
expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/proxy.[noNs]",
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
th := kusttest_test.MakeHarness(t)
for _, f := range tc.input {
f(th)
}
err := th.RunWithErr(tc.runPath, th.MakeDefaultOptions())
if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
t.Fatalf("unexpected error: %s", err)
}
})
}
}
func TestOrderOfAccumulatedComponent(t *testing.T) {
tests := map[string]struct {
input []FileGen
expectedOutput string
}{
"components_using_a_generated_resource_by_configMapGenerator": {
input: []FileGen{
writeK("", `
resources:
- resource.yaml
components:
- components
configMapGenerator:
- name: generated-resource
literals:
- key=value
options:
disableNameSuffixHash: true`),
writeF("resource.yaml", `
apiVersion: v1
kind: ConfigMap
metadata:
name: config-from-resources
data:
foo: bar`),
writeC("/components", `
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
nameSuffix: -suffix
`),
},
expectedOutput: `
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: config-from-resources-suffix
---
apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
name: generated-resource-suffix
`},
"components_are_applied_before_replacements_transformer_applied": {
input: []FileGen{
writeK("", `
resources:
- resource.yaml
components:
- components
replacements:
- source:
kind: Pod
name: myapp-pod
fieldPath: metadata.namespace
targets:
- select:
kind: Pod
name: myapp-pod
fieldPaths:
- spec.containers.[name=myapp-container].env.[name=CURRENT_POD_NAMESPACE].value`),
writeF("resource.yaml", `
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
namespace: dev-assa
spec:
containers:
- image: busybox
name: myapp-container
env:
- name: CURRENT_POD_NAMESPACE
value: "$(PLACEHOLDER)"`),
writeC("/components", `
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
namespace: kustomize-namespace`),
},
expectedOutput: `
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
namespace: kustomize-namespace
spec:
containers:
- env:
- name: CURRENT_POD_NAMESPACE
value: kustomize-namespace
image: busybox
name: myapp-container
`},
}
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
th := kusttest_test.MakeHarness(t)
for _, f := range test.input {
f(th)
}
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, test.expectedOutput)
})
}
}