mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
* update go 1.24.6 * fix non-constant format string error * update golang.org/x/tools@v0.36.0 and github.com/golangci/golangci-lint@v1.64.8 to pass execute golangci-lint * add a verpose diff output to prow test * remove pluginator binary version from generated files
1629 lines
34 KiB
Go
1629 lines
34 KiB
Go
// Copyright 2020 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package resource_test
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sigs.k8s.io/kustomize/api/internal/utils"
|
|
"sigs.k8s.io/kustomize/api/provider"
|
|
. "sigs.k8s.io/kustomize/api/resource"
|
|
"sigs.k8s.io/kustomize/api/types"
|
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
|
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
|
)
|
|
|
|
var factory = provider.NewDefaultDepProvider().GetResourceFactory()
|
|
|
|
func createTestConfigMap() (*Resource, error) {
|
|
res, err := factory.FromMap(
|
|
map[string]interface{}{
|
|
"apiVersion": "v1",
|
|
"kind": "ConfigMap",
|
|
"metadata": map[string]interface{}{
|
|
"name": "winnie",
|
|
"namespace": "hundred-acre-wood",
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create test config: %w", err)
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
const configMapAsString = `{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"winnie","namespace":"hundred-acre-wood"}}`
|
|
|
|
func createTestDeployment() (*Resource, error) {
|
|
res, err := factory.FromMap(
|
|
map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "Deployment",
|
|
"metadata": map[string]interface{}{
|
|
"name": "pooh",
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create Deployment: %w", err)
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
const deploymentAsString = `{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"pooh"}}`
|
|
|
|
func TestAsYAML(t *testing.T) {
|
|
expected := `apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: pooh
|
|
`
|
|
td, err := createTestDeployment()
|
|
if err != nil {
|
|
t.Fatalf("failed to create test deployment: %s", err)
|
|
}
|
|
yaml, err := td.AsYAML()
|
|
if err != nil {
|
|
t.Fatalf("failed to get yaml: %s", err)
|
|
}
|
|
if string(yaml) != expected {
|
|
t.Fatalf("--- expected\n%s\n--- got\n%s\n", expected, string(yaml))
|
|
}
|
|
}
|
|
|
|
func TestResourceString(t *testing.T) {
|
|
td, err := createTestDeployment()
|
|
if err != nil {
|
|
t.Fatalf("failed to create test deployment: %v", err)
|
|
}
|
|
tc, err := createTestConfigMap()
|
|
if err != nil {
|
|
t.Fatalf("failed to create test config: %v", err)
|
|
}
|
|
tests := []struct {
|
|
in *Resource
|
|
s string
|
|
}{
|
|
{
|
|
in: tc,
|
|
s: configMapAsString,
|
|
},
|
|
{
|
|
in: td,
|
|
s: deploymentAsString,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
assert.Equal(t, test.in.String(), test.s)
|
|
}
|
|
}
|
|
|
|
func TestResourceId(t *testing.T) {
|
|
td, err := createTestDeployment()
|
|
if err != nil {
|
|
t.Fatalf("failed to create test deployment: %v", err)
|
|
}
|
|
tc, err := createTestConfigMap()
|
|
if err != nil {
|
|
t.Fatalf("failed to create test config: %v", err)
|
|
}
|
|
tests := []struct {
|
|
in *Resource
|
|
id resid.ResId
|
|
}{
|
|
{
|
|
in: tc,
|
|
id: resid.NewResIdWithNamespace(
|
|
resid.NewGvk("", "v1", "ConfigMap"),
|
|
"winnie", "hundred-acre-wood"),
|
|
},
|
|
{
|
|
in: td,
|
|
id: resid.NewResId(
|
|
resid.NewGvk("apps", "v1", "Deployment"), "pooh"),
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
if test.in.OrgId() != test.id {
|
|
t.Fatalf("Expected %v, but got %v\n", test.id, test.in.OrgId())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDeepCopy(t *testing.T) {
|
|
r, err := factory.FromMap(
|
|
map[string]interface{}{
|
|
"apiVersion": "apps/v1",
|
|
"kind": "Deployment",
|
|
"metadata": map[string]interface{}{
|
|
"name": "pooh",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to create test config: %v", err)
|
|
}
|
|
r.AppendRefBy(resid.NewResId(resid.Gvk{Group: "somegroup", Kind: "MyKind"}, "random"))
|
|
|
|
var1 := types.Var{
|
|
Name: "SERVICE_ONE",
|
|
ObjRef: types.Target{
|
|
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
|
|
Name: "backendOne"},
|
|
}
|
|
r.AppendRefVarName(var1)
|
|
|
|
cr := r.DeepCopy()
|
|
if !reflect.DeepEqual(r, cr) {
|
|
t.Errorf("expected %v\nbut got%v", r, cr)
|
|
}
|
|
}
|
|
|
|
func TestApplySmPatch_1(t *testing.T) {
|
|
resource, err := factory.FromBytes([]byte(`
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
annotations:
|
|
baseAnno: This is a base annotation
|
|
labels:
|
|
app: mungebot
|
|
foo: bar
|
|
name: bingo
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
foo: bar
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: mungebot
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: foo
|
|
value: bar
|
|
image: nginx
|
|
name: nginx
|
|
ports:
|
|
- containerPort: 80
|
|
`))
|
|
require.NoError(t, err)
|
|
patch, err := factory.FromBytes([]byte(`
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: baseprefix-mungebot
|
|
spec:
|
|
template:
|
|
spec:
|
|
containers:
|
|
- image: nginx
|
|
name: nginx
|
|
ports:
|
|
- containerPort: 777
|
|
`))
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, resource.ApplySmPatch(patch))
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, `apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
annotations:
|
|
baseAnno: This is a base annotation
|
|
labels:
|
|
app: mungebot
|
|
foo: bar
|
|
name: bingo
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
foo: bar
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: mungebot
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: foo
|
|
value: bar
|
|
image: nginx
|
|
name: nginx
|
|
ports:
|
|
- containerPort: 777
|
|
- containerPort: 80
|
|
`, string(bytes))
|
|
}
|
|
|
|
func TestApplySmPatch_2(t *testing.T) {
|
|
resource, err := factory.FromBytes([]byte(`
|
|
apiVersion: example.com/v1
|
|
kind: Foo
|
|
metadata:
|
|
name: my-foo
|
|
spec:
|
|
bar:
|
|
A: X
|
|
B: Y
|
|
`))
|
|
require.NoError(t, err)
|
|
patch, err := factory.FromBytes([]byte(`
|
|
apiVersion: example.com/v1
|
|
kind: Foo
|
|
metadata:
|
|
name: my-foo
|
|
spec:
|
|
bar:
|
|
B:
|
|
C: Z
|
|
D: W
|
|
baz:
|
|
hello: world
|
|
`))
|
|
require.NoError(t, err)
|
|
require.NoError(t, resource.ApplySmPatch(patch))
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, `apiVersion: example.com/v1
|
|
kind: Foo
|
|
metadata:
|
|
name: my-foo
|
|
spec:
|
|
bar:
|
|
A: X
|
|
C: Z
|
|
D: W
|
|
baz:
|
|
hello: world
|
|
`, string(bytes))
|
|
}
|
|
|
|
func TestApplySmPatch_3(t *testing.T) {
|
|
resource, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`))
|
|
require.NoError(t, err)
|
|
patch, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 999
|
|
`))
|
|
require.NoError(t, err)
|
|
require.NoError(t, resource.ApplySmPatch(patch))
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 999
|
|
`, string(bytes))
|
|
}
|
|
|
|
// regression test for https://github.com/kubernetes-sigs/kustomize/issues/5031
|
|
func TestApplySmPatch_Idempotency(t *testing.T) {
|
|
// an arbitrary number of times to apply the patch
|
|
patchApplyCount := 4
|
|
resourceYaml := `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
creationTimestamp: null
|
|
labels: null
|
|
name: my-deployment
|
|
`
|
|
resource, err := factory.FromBytes([]byte(resourceYaml))
|
|
require.NoError(t, err)
|
|
|
|
noOpPatch, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: my-deployment
|
|
`))
|
|
require.NoError(t, err)
|
|
|
|
for i := 0; i < patchApplyCount; i++ {
|
|
require.NoError(t, resource.ApplySmPatch(noOpPatch))
|
|
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(
|
|
t,
|
|
resourceYaml,
|
|
string(bytes),
|
|
"resource should be unchanged after re-application of patch",
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestApplySmPatchShouldOutputListItemsInCorrectOrder(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
skip bool
|
|
patch string
|
|
expectedOutput string
|
|
}{
|
|
{
|
|
name: "Order should not change when patch has foo only",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: foo
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: foo
|
|
- name: bar
|
|
`,
|
|
},
|
|
{
|
|
name: "Order changes when patch has bar only",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: bar
|
|
`,
|
|
// This test records current behavior, but this behavior might be undesirable.
|
|
// If so, feel free to change the test to pass with some improved algorithm.
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: bar
|
|
- name: foo
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should not change and should include a new item at the beginning when patch has a new list item",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: baz
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: baz
|
|
- name: foo
|
|
- name: bar
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should not change when patch has foo and bar in same order",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: foo
|
|
- name: bar
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: foo
|
|
- name: bar
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should change when patch has foo and bar in different order",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: bar
|
|
- name: foo
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: bar
|
|
- name: foo
|
|
`,
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if tc.skip {
|
|
t.Skip()
|
|
}
|
|
|
|
resource, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
spec:
|
|
initContainers:
|
|
- name: foo
|
|
- name: bar
|
|
`))
|
|
require.NoError(t, err)
|
|
|
|
patch, err := factory.FromBytes([]byte(tc.patch))
|
|
require.NoError(t, err)
|
|
require.NoError(t, resource.ApplySmPatch(patch))
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tc.expectedOutput, string(bytes))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestApplySmPatchShouldOutputPrimitiveListItemsInCorrectOrder(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
skip bool
|
|
patch string
|
|
expectedOutput string
|
|
}{
|
|
{
|
|
name: "Order should not change when patch has foo only",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
finalizers: ["foo"]
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
finalizers:
|
|
- foo
|
|
- bar
|
|
name: test
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should not change when patch has bar only",
|
|
skip: true, // TODO: This test should pass but fails currently. Fix the problem and unskip this test
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
finalizers: ["bar"]
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
finalizers:
|
|
- foo
|
|
- bar
|
|
name: test
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should not change and should include a new item at the beginning when patch has a new list item",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
finalizers: ["baz"]
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
finalizers:
|
|
- baz
|
|
- foo
|
|
- bar
|
|
name: test
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should not change when patch has foo and bar in same order",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
finalizers: ["foo", "bar"]
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
finalizers:
|
|
- foo
|
|
- bar
|
|
name: test
|
|
`,
|
|
},
|
|
{
|
|
name: "Order should change when patch has foo and bar in different order",
|
|
patch: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
finalizers: ["bar", "foo"]
|
|
`,
|
|
expectedOutput: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
finalizers:
|
|
- bar
|
|
- foo
|
|
name: test
|
|
`,
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if tc.skip {
|
|
t.Skip()
|
|
}
|
|
|
|
resource, err := factory.FromBytes([]byte(`
|
|
kind: Pod
|
|
metadata:
|
|
name: test
|
|
finalizers: ["foo", "bar"]
|
|
`))
|
|
require.NoError(t, err)
|
|
|
|
patch, err := factory.FromBytes([]byte(tc.patch))
|
|
require.NoError(t, err)
|
|
require.NoError(t, resource.ApplySmPatch(patch))
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tc.expectedOutput, string(bytes))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMergeDataMapFrom(t *testing.T) {
|
|
resource, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: BlahBlah
|
|
metadata:
|
|
name: clown
|
|
data:
|
|
fruit: pear
|
|
`))
|
|
if !assert.NoError(t, err) {
|
|
t.FailNow()
|
|
}
|
|
patch, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Whatever
|
|
metadata:
|
|
name: spaceship
|
|
data:
|
|
spaceship: enterprise
|
|
`))
|
|
if !assert.NoError(t, err) {
|
|
t.FailNow()
|
|
}
|
|
resource.MergeDataMapFrom(patch)
|
|
bytes, err := resource.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, `apiVersion: v1
|
|
data:
|
|
fruit: pear
|
|
spaceship: enterprise
|
|
kind: BlahBlah
|
|
metadata:
|
|
name: clown
|
|
`, string(bytes))
|
|
}
|
|
|
|
func TestApplySmPatch_SwapOrder(t *testing.T) {
|
|
s1 := `
|
|
apiVersion: example.com/v1
|
|
kind: Foo
|
|
metadata:
|
|
name: my-foo
|
|
spec:
|
|
bar:
|
|
B:
|
|
C: Z
|
|
`
|
|
s2 := `
|
|
apiVersion: example.com/v1
|
|
kind: Foo
|
|
metadata:
|
|
name: my-foo
|
|
spec:
|
|
bar:
|
|
C: Z
|
|
D: W
|
|
baz:
|
|
hello: world
|
|
`
|
|
expected := `apiVersion: example.com/v1
|
|
kind: Foo
|
|
metadata:
|
|
name: my-foo
|
|
spec:
|
|
bar:
|
|
C: Z
|
|
D: W
|
|
baz:
|
|
hello: world
|
|
`
|
|
r1, err := factory.FromBytes([]byte(s1))
|
|
require.NoError(t, err)
|
|
r2, err := factory.FromBytes([]byte(s2))
|
|
require.NoError(t, err)
|
|
require.NoError(t, r1.ApplySmPatch(r2))
|
|
bytes, err := r1.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, expected, string(bytes))
|
|
|
|
r1, _ = factory.FromBytes([]byte(s1))
|
|
r2, _ = factory.FromBytes([]byte(s2))
|
|
require.NoError(t, r2.ApplySmPatch(r1))
|
|
bytes, err = r2.AsYAML()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, expected, string(bytes))
|
|
}
|
|
|
|
func TestApplySmPatch(t *testing.T) {
|
|
const (
|
|
myDeployment = "Deployment"
|
|
myCRD = "myCRD"
|
|
)
|
|
|
|
tests := map[string]struct {
|
|
base string
|
|
patch []string
|
|
expected string
|
|
errorExpected bool
|
|
errorMsg string
|
|
}{
|
|
"withschema-label-image-container": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
addLabelAndEnvPatch(myDeployment),
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
addContainerAndEnvPatch(myDeployment),
|
|
},
|
|
errorExpected: false,
|
|
expected: expectedResultMultiPatch(myDeployment, false),
|
|
},
|
|
"withschema-image-container-label": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
addContainerAndEnvPatch(myDeployment),
|
|
addLabelAndEnvPatch(myDeployment),
|
|
},
|
|
errorExpected: false,
|
|
expected: expectedResultMultiPatch(myDeployment, true),
|
|
},
|
|
"withschema-container-label-image": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
addContainerAndEnvPatch(myDeployment),
|
|
addLabelAndEnvPatch(myDeployment),
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
},
|
|
errorExpected: false,
|
|
expected: expectedResultMultiPatch(myDeployment, true),
|
|
},
|
|
"noschema-label-image-container": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
addLabelAndEnvPatch(myCRD),
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
addContainerAndEnvPatch(myCRD),
|
|
},
|
|
// Might be better if this complained about patch conflict.
|
|
// See plugin/builtin/patchstrategicmergetransformer/psmt_test.go
|
|
expected: `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: ANOTHERENV
|
|
value: ANOTHERVALUE
|
|
name: nginx
|
|
- image: anotherimage
|
|
name: anothercontainer
|
|
`,
|
|
},
|
|
"noschema-image-container-label": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
addContainerAndEnvPatch(myCRD),
|
|
addLabelAndEnvPatch(myCRD),
|
|
},
|
|
// Might be better if this complained about patch conflict.
|
|
expected: `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE
|
|
name: nginx
|
|
`,
|
|
},
|
|
"noschema-container-label-image": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
addContainerAndEnvPatch(myCRD),
|
|
addLabelAndEnvPatch(myCRD),
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
},
|
|
// Might be better if this complained about patch conflict.
|
|
expected: `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- image: nginx:latest
|
|
name: nginx
|
|
`,
|
|
},
|
|
|
|
"withschema-label-latest-someV-01": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
addLabelAndEnvPatch(myDeployment),
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
changeImagePatch(myDeployment, "nginx:1.7.9"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE
|
|
image: nginx:1.7.9
|
|
name: nginx
|
|
`,
|
|
},
|
|
"withschema-latest-label-someV-02": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
addLabelAndEnvPatch(myDeployment),
|
|
changeImagePatch(myDeployment, "nginx:1.7.9"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE
|
|
image: nginx:1.7.9
|
|
name: nginx
|
|
`,
|
|
},
|
|
"withschema-latest-label-someV-03": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
changeImagePatch(myDeployment, "nginx:1.7.9"),
|
|
addLabelAndEnvPatch(myDeployment),
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE
|
|
image: nginx:latest
|
|
name: nginx
|
|
`,
|
|
},
|
|
"withschema-latest-label-someV-04": {
|
|
base: baseResource(myDeployment),
|
|
patch: []string{
|
|
changeImagePatch(myDeployment, "nginx:1.7.9"),
|
|
changeImagePatch(myDeployment, "nginx:latest"),
|
|
addLabelAndEnvPatch(myDeployment),
|
|
changeImagePatch(myDeployment, "nginx:nginx"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE
|
|
image: nginx:nginx
|
|
name: nginx
|
|
`,
|
|
},
|
|
"noschema-latest-label-someV-01": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
addLabelAndEnvPatch(myCRD),
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
changeImagePatch(myCRD, "nginx:1.7.9"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
`,
|
|
},
|
|
"noschema-latest-label-someV-02": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
addLabelAndEnvPatch(myCRD),
|
|
changeImagePatch(myCRD, "nginx:1.7.9"),
|
|
},
|
|
expected: expectedResultJMP("nginx:1.7.9"),
|
|
},
|
|
"noschema-latest-label-someV-03": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
changeImagePatch(myCRD, "nginx:1.7.9"),
|
|
addLabelAndEnvPatch(myCRD),
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- image: nginx:latest
|
|
name: nginx
|
|
`,
|
|
},
|
|
"noschema-latest-label-someV-04": {
|
|
base: baseResource(myCRD),
|
|
patch: []string{
|
|
changeImagePatch(myCRD, "nginx:1.7.9"),
|
|
changeImagePatch(myCRD, "nginx:latest"),
|
|
addLabelAndEnvPatch(myCRD),
|
|
changeImagePatch(myCRD, "nginx:nginx"),
|
|
},
|
|
expected: `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- image: nginx:nginx
|
|
name: nginx
|
|
`,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
resource, err := factory.FromBytes([]byte(test.base))
|
|
require.NoError(t, err)
|
|
for _, p := range test.patch {
|
|
patch, err := factory.FromBytes([]byte(p))
|
|
require.NoError(t, err, name)
|
|
require.NoError(t, resource.ApplySmPatch(patch), name)
|
|
}
|
|
bytes, err := resource.AsYAML()
|
|
if test.errorExpected {
|
|
require.Error(t, err, name)
|
|
} else {
|
|
require.NoError(t, err, name)
|
|
assert.Equal(t, test.expected, string(bytes), name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResourceStorePreviousId(t *testing.T) {
|
|
tests := map[string]struct {
|
|
input string
|
|
newName string
|
|
newNs string
|
|
expected string
|
|
}{
|
|
"default namespace, first previous name": {
|
|
input: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
name: oldName
|
|
`,
|
|
newName: "newName",
|
|
newNs: "",
|
|
expected: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret
|
|
internal.config.kubernetes.io/previousNames: oldName
|
|
internal.config.kubernetes.io/previousNamespaces: default
|
|
name: newName
|
|
`,
|
|
},
|
|
|
|
"default namespace, second previous name": {
|
|
input: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret
|
|
internal.config.kubernetes.io/previousNames: oldName
|
|
internal.config.kubernetes.io/previousNamespaces: default
|
|
name: oldName2
|
|
`,
|
|
newName: "newName",
|
|
newNs: "",
|
|
expected: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret,Secret
|
|
internal.config.kubernetes.io/previousNames: oldName,oldName2
|
|
internal.config.kubernetes.io/previousNamespaces: default,default
|
|
name: newName
|
|
`,
|
|
},
|
|
|
|
"non-default namespace": {
|
|
input: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret
|
|
internal.config.kubernetes.io/previousNames: oldName
|
|
internal.config.kubernetes.io/previousNamespaces: default
|
|
name: oldName2
|
|
namespace: oldNamespace
|
|
`,
|
|
newName: "newName",
|
|
newNs: "newNamespace",
|
|
expected: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret,Secret
|
|
internal.config.kubernetes.io/previousNames: oldName,oldName2
|
|
internal.config.kubernetes.io/previousNamespaces: default,oldNamespace
|
|
name: newName
|
|
namespace: newNamespace
|
|
`,
|
|
},
|
|
}
|
|
factory := provider.NewDefaultDepProvider().GetResourceFactory()
|
|
for i := range tests {
|
|
test := tests[i]
|
|
t.Run(i, func(t *testing.T) {
|
|
resources, err := factory.SliceFromBytes([]byte(test.input))
|
|
if !assert.NoError(t, err) || len(resources) == 0 {
|
|
t.FailNow()
|
|
}
|
|
r := resources[0]
|
|
r.StorePreviousId()
|
|
r.SetName(test.newName)
|
|
if test.newNs != "" {
|
|
r.SetNamespace(test.newNs)
|
|
}
|
|
bytes, err := r.AsYAML()
|
|
if !assert.NoError(t, err) {
|
|
t.FailNow()
|
|
}
|
|
assert.Equal(t, test.expected, string(bytes))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResource_PrevIds(t *testing.T) {
|
|
tests := map[string]struct {
|
|
input string
|
|
expected []resid.ResId
|
|
}{
|
|
"no previous IDs": {
|
|
input: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
name: name
|
|
`,
|
|
expected: nil,
|
|
},
|
|
|
|
"one previous ID": {
|
|
input: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret
|
|
internal.config.kubernetes.io/previousNames: oldName
|
|
internal.config.kubernetes.io/previousNamespaces: default
|
|
name: newName
|
|
`,
|
|
expected: []resid.ResId{
|
|
{
|
|
Gvk: resid.Gvk{Group: "apps", Version: "v1", Kind: "Secret"},
|
|
Name: "oldName",
|
|
Namespace: resid.DefaultNamespace,
|
|
},
|
|
},
|
|
},
|
|
|
|
"two ids": {
|
|
input: `apiVersion: apps/v1
|
|
kind: Secret
|
|
metadata:
|
|
annotations:
|
|
internal.config.kubernetes.io/previousKinds: Secret,Secret
|
|
internal.config.kubernetes.io/previousNames: oldName,oldName2
|
|
internal.config.kubernetes.io/previousNamespaces: default,oldNamespace
|
|
name: newName
|
|
namespace: newNamespace
|
|
`,
|
|
expected: []resid.ResId{
|
|
{
|
|
Gvk: resid.Gvk{Group: "apps", Version: "v1", Kind: "Secret"},
|
|
Name: "oldName",
|
|
Namespace: resid.DefaultNamespace,
|
|
},
|
|
{
|
|
Gvk: resid.Gvk{Group: "apps", Version: "v1", Kind: "Secret"},
|
|
Name: "oldName2",
|
|
Namespace: "oldNamespace",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
factory := provider.NewDefaultDepProvider().GetResourceFactory()
|
|
for i := range tests {
|
|
test := tests[i]
|
|
t.Run(i, func(t *testing.T) {
|
|
resources, err := factory.SliceFromBytes([]byte(test.input))
|
|
if !assert.NoError(t, err) || len(resources) == 0 {
|
|
t.FailNow()
|
|
}
|
|
r := resources[0]
|
|
assert.Equal(t, test.expected, r.PrevIds())
|
|
})
|
|
}
|
|
}
|
|
|
|
// baseResource produces a base object which used to test
|
|
// patch transformation
|
|
// Also the structure is matching the Deployment syntax
|
|
// the kind can be replaced to allow testing using CRD
|
|
// without access to the schema
|
|
func baseResource(kind string) string {
|
|
res := `
|
|
apiVersion: apps/v1
|
|
kind: %s
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
spec:
|
|
containers:
|
|
- name: nginx
|
|
image: nginx`
|
|
return fmt.Sprintf(res, kind)
|
|
}
|
|
|
|
// addContainerAndEnvPatch produces a patch object which adds
|
|
// an entry in the env slice of the first/nginx container
|
|
// as well as adding a label in the metadata
|
|
// Note that for SMP/WithSchema merge, the name:nginx entry
|
|
// is mandatory
|
|
func addLabelAndEnvPatch(kind string) string {
|
|
return fmt.Sprintf(`
|
|
apiVersion: apps/v1
|
|
kind: %s
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- name: nginx
|
|
env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE`, kind)
|
|
}
|
|
|
|
// addContainerAndEnvPatch produces a patch object which adds
|
|
// an entry in the env slice of the first/nginx container
|
|
// as well as adding a second container in the container list
|
|
// Note that for SMP/WithSchema merge, the name:nginx entry
|
|
// is mandatory
|
|
func addContainerAndEnvPatch(kind string) string {
|
|
return fmt.Sprintf(`
|
|
apiVersion: apps/v1
|
|
kind: %s
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
spec:
|
|
containers:
|
|
- name: nginx
|
|
env:
|
|
- name: ANOTHERENV
|
|
value: ANOTHERVALUE
|
|
- name: anothercontainer
|
|
image: anotherimage`, kind)
|
|
}
|
|
|
|
// addContainerAndEnvPatch produces a patch object which replaces
|
|
// the value of the image field in the first/nginx container
|
|
// Note that for SMP/WithSchema merge, the name:nginx entry
|
|
// is mandatory
|
|
func changeImagePatch(kind string, newImage string) string {
|
|
return fmt.Sprintf(`
|
|
apiVersion: apps/v1
|
|
kind: %s
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
spec:
|
|
containers:
|
|
- name: nginx
|
|
image: %s`, kind, newImage)
|
|
}
|
|
|
|
// utility method to build the expected result of a multipatch
|
|
// the order of the patches still have influence especially
|
|
// in the insertion location within arrays.
|
|
func expectedResultMultiPatch(kind string, reversed bool) string {
|
|
pattern := `apiVersion: apps/v1
|
|
kind: %s
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
%s
|
|
image: nginx:latest
|
|
name: nginx
|
|
- image: anotherimage
|
|
name: anothercontainer
|
|
`
|
|
if reversed {
|
|
return fmt.Sprintf(pattern, kind, `- name: SOMEENV
|
|
value: SOMEVALUE
|
|
- name: ANOTHERENV
|
|
value: ANOTHERVALUE`)
|
|
}
|
|
return fmt.Sprintf(pattern, kind, `- name: ANOTHERENV
|
|
value: ANOTHERVALUE
|
|
- name: SOMEENV
|
|
value: SOMEVALUE`)
|
|
}
|
|
|
|
// utility method building the expected output of a JMP.
|
|
// imagename parameter allows to build a result consistent
|
|
// with the JMP behavior which basically overrides the
|
|
// entire "containers" list.
|
|
func expectedResultJMP(imagename string) string {
|
|
if imagename == "" {
|
|
return `apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: SOMEENV
|
|
value: SOMEVALUE
|
|
name: nginx
|
|
`
|
|
}
|
|
return fmt.Sprintf(`apiVersion: apps/v1
|
|
kind: myCRD
|
|
metadata:
|
|
name: deploy1
|
|
spec:
|
|
template:
|
|
metadata:
|
|
labels:
|
|
old-label: old-value
|
|
some-label: some-value
|
|
spec:
|
|
containers:
|
|
- image: %s
|
|
name: nginx
|
|
`, imagename)
|
|
}
|
|
|
|
func TestSameEndingSubarray(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
a []string
|
|
b []string
|
|
expected bool
|
|
}{
|
|
"both nil": {
|
|
expected: true,
|
|
},
|
|
"one nil": {
|
|
b: []string{},
|
|
expected: true,
|
|
},
|
|
"both empty": {
|
|
a: []string{},
|
|
b: []string{},
|
|
expected: true,
|
|
},
|
|
"no1": {
|
|
a: []string{"a"},
|
|
b: []string{},
|
|
expected: false,
|
|
},
|
|
"no2": {
|
|
a: []string{"b", "a"},
|
|
b: []string{"b"},
|
|
expected: false,
|
|
},
|
|
"yes1": {
|
|
a: []string{"a", "b"},
|
|
b: []string{"b"},
|
|
expected: true,
|
|
},
|
|
"yes2": {
|
|
a: []string{"a", "b", "c"},
|
|
b: []string{"b", "c"},
|
|
expected: true,
|
|
},
|
|
"yes3": {
|
|
a: []string{"a", "b", "c", "d", "e", "f"},
|
|
b: []string{"f"},
|
|
expected: true,
|
|
},
|
|
}
|
|
for n := range testCases {
|
|
tc := testCases[n]
|
|
t.Run(n, func(t *testing.T) {
|
|
assert.Equal(t, tc.expected, utils.SameEndingSubSlice(tc.a, tc.b))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetGvk(t *testing.T) {
|
|
r, err := factory.FromBytes([]byte(`
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`))
|
|
require.NoError(t, err)
|
|
|
|
gvk := r.GetGvk()
|
|
expected := "apps"
|
|
actual := gvk.Group
|
|
if expected != actual {
|
|
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
|
}
|
|
expected = "v1"
|
|
actual = gvk.Version
|
|
if expected != actual {
|
|
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
|
}
|
|
expected = "Deployment"
|
|
actual = gvk.Kind
|
|
if expected != actual {
|
|
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
|
}
|
|
}
|
|
func TestSetGvk(t *testing.T) {
|
|
r, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`))
|
|
require.NoError(t, err)
|
|
r.SetGvk(resid.GvkFromString("knd.ver.grp"))
|
|
gvk := r.GetGvk()
|
|
if expected, actual := "grp", gvk.Group; expected != actual {
|
|
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
|
}
|
|
if expected, actual := "ver", gvk.Version; expected != actual {
|
|
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
|
}
|
|
if expected, actual := "knd", gvk.Kind; expected != actual {
|
|
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestRefBy(t *testing.T) {
|
|
r, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`))
|
|
require.NoError(t, err)
|
|
r.AppendRefBy(resid.FromString("knd1.ver1.gr1/name1.ns1"))
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
annotations:
|
|
internal.config.kubernetes.io/refBy: 'knd1.ver1.gr1/name1.ns1'
|
|
spec:
|
|
numReplicas: 1
|
|
`, r.RNode.MustString())
|
|
assert.Equal(t, r.GetRefBy(), []resid.ResId{resid.FromString("knd1.ver1.gr1/name1.ns1")})
|
|
|
|
r.AppendRefBy(resid.FromString("knd2.ver2.gr2/name2.ns2"))
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
annotations:
|
|
internal.config.kubernetes.io/refBy: 'knd1.ver1.gr1/name1.ns1,knd2.ver2.gr2/name2.ns2'
|
|
spec:
|
|
numReplicas: 1
|
|
`, r.RNode.MustString())
|
|
assert.Equal(t, []resid.ResId{
|
|
resid.FromString("knd1.ver1.gr1/name1.ns1"),
|
|
resid.FromString("knd2.ver2.gr2/name2.ns2"),
|
|
}, r.GetRefBy())
|
|
}
|
|
|
|
func TestOrigin(t *testing.T) {
|
|
r, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`))
|
|
require.NoError(t, err)
|
|
origin := &Origin{
|
|
Path: "deployment.yaml",
|
|
Repo: "github.com/myrepo",
|
|
Ref: "master",
|
|
}
|
|
require.NoError(t, r.SetOrigin(origin))
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
annotations:
|
|
config.kubernetes.io/origin: |
|
|
path: deployment.yaml
|
|
repo: github.com/myrepo
|
|
ref: master
|
|
spec:
|
|
numReplicas: 1
|
|
`, r.MustString())
|
|
or, err := r.GetOrigin()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, origin, or)
|
|
}
|
|
|
|
func TestTransformations(t *testing.T) {
|
|
r, err := factory.FromBytes([]byte(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`))
|
|
require.NoError(t, err)
|
|
origin1 := &Origin{
|
|
Repo: "github.com/myrepo",
|
|
Ref: "master",
|
|
ConfiguredIn: "config.yaml",
|
|
ConfiguredBy: kyaml.ResourceIdentifier{
|
|
TypeMeta: kyaml.TypeMeta{
|
|
APIVersion: "builtin",
|
|
Kind: "Generator",
|
|
},
|
|
NameMeta: kyaml.NameMeta{
|
|
Name: "my-name",
|
|
Namespace: "my-namespace",
|
|
},
|
|
},
|
|
}
|
|
origin2 := &Origin{
|
|
ConfiguredIn: "../base/config.yaml",
|
|
ConfiguredBy: kyaml.ResourceIdentifier{
|
|
TypeMeta: kyaml.TypeMeta{
|
|
APIVersion: "builtin",
|
|
Kind: "Generator",
|
|
},
|
|
NameMeta: kyaml.NameMeta{
|
|
Name: "my-name",
|
|
Namespace: "my-namespace",
|
|
},
|
|
},
|
|
}
|
|
require.NoError(t, r.AddTransformation(origin1))
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
annotations:
|
|
alpha.config.kubernetes.io/transformations: |
|
|
- repo: github.com/myrepo
|
|
ref: master
|
|
configuredIn: config.yaml
|
|
configuredBy:
|
|
apiVersion: builtin
|
|
kind: Generator
|
|
name: my-name
|
|
namespace: my-namespace
|
|
spec:
|
|
numReplicas: 1
|
|
`, r.MustString())
|
|
require.NoError(t, r.AddTransformation(origin2))
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
annotations:
|
|
alpha.config.kubernetes.io/transformations: |
|
|
- repo: github.com/myrepo
|
|
ref: master
|
|
configuredIn: config.yaml
|
|
configuredBy:
|
|
apiVersion: builtin
|
|
kind: Generator
|
|
name: my-name
|
|
namespace: my-namespace
|
|
- configuredIn: ../base/config.yaml
|
|
configuredBy:
|
|
apiVersion: builtin
|
|
kind: Generator
|
|
name: my-name
|
|
namespace: my-namespace
|
|
spec:
|
|
numReplicas: 1
|
|
`, r.MustString())
|
|
transformations, err := r.GetTransformations()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, Transformations{origin1, origin2}, transformations)
|
|
require.NoError(t, r.ClearTransformations())
|
|
assert.Equal(t, `apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: clown
|
|
spec:
|
|
numReplicas: 1
|
|
`, r.MustString())
|
|
}
|