mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Assert keeps going after failure, but require immediately fails the tests, making it easier to find the output related to the test failure, rather than having to comb through a bunch of subsequent assertion failures. For equality tests, we may or may not want to continue, but for error checks we almost always want to immediately fail the test. Exceptions can be changed as-needed.
707 lines
14 KiB
Go
707 lines
14 KiB
Go
// Copyright 2019 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package kioutil_test
|
|
|
|
import (
|
|
"bytes"
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
)
|
|
|
|
func TestSortNodes_moreThan10(t *testing.T) {
|
|
input := `
|
|
a: b
|
|
---
|
|
c: d
|
|
---
|
|
e: f
|
|
---
|
|
g: h
|
|
---
|
|
i: j
|
|
---
|
|
k: l
|
|
---
|
|
m: n
|
|
---
|
|
o: p
|
|
---
|
|
q: r
|
|
---
|
|
s: t
|
|
---
|
|
u: v
|
|
---
|
|
w: x
|
|
---
|
|
y: z
|
|
`
|
|
actual := &bytes.Buffer{}
|
|
rw := kio.ByteReadWriter{Reader: bytes.NewBufferString(input), Writer: actual}
|
|
nodes, err := rw.Read()
|
|
if !assert.NoError(t, err) {
|
|
t.Fail()
|
|
}
|
|
|
|
// randomize the list
|
|
rand.Seed(time.Now().UnixNano())
|
|
rand.Shuffle(len(nodes), func(i, j int) { nodes[i], nodes[j] = nodes[j], nodes[i] })
|
|
|
|
// sort them back into their original order
|
|
if !assert.NoError(t, kioutil.SortNodes(nodes)) {
|
|
t.Fail()
|
|
}
|
|
|
|
// check the sorted values
|
|
expected := strings.Split(input, "---")
|
|
for i := range nodes {
|
|
a := strings.TrimSpace(nodes[i].MustString())
|
|
b := strings.TrimSpace(expected[i])
|
|
if !assert.Contains(t, a, b) {
|
|
t.Fail()
|
|
}
|
|
}
|
|
|
|
if !assert.NoError(t, rw.Write(nodes)) {
|
|
t.Fail()
|
|
}
|
|
|
|
assert.Equal(t, strings.TrimSpace(input), strings.TrimSpace(actual.String()))
|
|
}
|
|
|
|
func TestDefaultPathAnnotation(t *testing.T) {
|
|
var tests = []struct {
|
|
dir string
|
|
input string // input
|
|
expected string // expected result
|
|
name string
|
|
}{
|
|
{
|
|
`foo`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'foo/b/bar_a.yaml'
|
|
config.kubernetes.io/path: 'foo/b/bar_a.yaml'
|
|
`, `with namespace`},
|
|
{
|
|
`foo`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'foo/bar_a.yaml'
|
|
config.kubernetes.io/path: 'foo/bar_a.yaml'
|
|
`, `without namespace`},
|
|
|
|
{
|
|
``,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'b/bar_a.yaml'
|
|
config.kubernetes.io/path: 'b/bar_a.yaml'
|
|
`, `without dir`},
|
|
{
|
|
``,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
`, `skip`},
|
|
}
|
|
|
|
for _, s := range tests {
|
|
n := yaml.MustParse(s.input)
|
|
err := kioutil.DefaultPathAnnotation(s.dir, []*yaml.RNode{n})
|
|
if !assert.NoError(t, err, s.name) {
|
|
t.FailNow()
|
|
}
|
|
if !assert.Equal(t, s.expected, n.MustString(), s.name) {
|
|
t.FailNow()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultPathAndIndexAnnotation(t *testing.T) {
|
|
var tests = []struct {
|
|
dir string
|
|
input string // input
|
|
expected string // expected result
|
|
name string
|
|
}{
|
|
{
|
|
`foo`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'foo/b/bar_a.yaml'
|
|
config.kubernetes.io/path: 'foo/b/bar_a.yaml'
|
|
internal.config.kubernetes.io/index: '0'
|
|
config.kubernetes.io/index: '0'
|
|
`, `with namespace`},
|
|
{
|
|
`foo`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'foo/bar_a.yaml'
|
|
config.kubernetes.io/path: 'foo/bar_a.yaml'
|
|
internal.config.kubernetes.io/index: '0'
|
|
config.kubernetes.io/index: '0'
|
|
`, `without namespace`},
|
|
|
|
{
|
|
``,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'b/bar_a.yaml'
|
|
config.kubernetes.io/path: 'b/bar_a.yaml'
|
|
internal.config.kubernetes.io/index: '0'
|
|
config.kubernetes.io/index: '0'
|
|
`, `without dir`},
|
|
{
|
|
``,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
config.kubernetes.io/index: '5'
|
|
`,
|
|
`apiVersion: v1
|
|
kind: Bar
|
|
metadata:
|
|
name: a
|
|
namespace: b
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
config.kubernetes.io/index: '5'
|
|
`, `skip`},
|
|
}
|
|
|
|
for _, s := range tests {
|
|
out := &bytes.Buffer{}
|
|
r := kio.ByteReadWriter{
|
|
Reader: bytes.NewBufferString(s.input),
|
|
Writer: out,
|
|
KeepReaderAnnotations: true,
|
|
OmitReaderAnnotations: true,
|
|
}
|
|
n, err := r.Read()
|
|
if !assert.NoError(t, err, s.name) {
|
|
t.FailNow()
|
|
}
|
|
if !assert.NoError(t, kioutil.DefaultPathAndIndexAnnotation(s.dir, n), s.name) {
|
|
t.FailNow()
|
|
}
|
|
if !assert.NoError(t, r.Write(n), s.name) {
|
|
t.FailNow()
|
|
}
|
|
if !assert.Equal(t, s.expected, out.String(), s.name) {
|
|
t.FailNow()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCreatePathAnnotationValue(t *testing.T) {
|
|
var tests = []struct {
|
|
dir string
|
|
meta yaml.ResourceMeta // input
|
|
expected string // expected result
|
|
name string
|
|
}{
|
|
{
|
|
`dir`,
|
|
yaml.ResourceMeta{
|
|
TypeMeta: yaml.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
Kind: "foo",
|
|
},
|
|
ObjectMeta: yaml.ObjectMeta{
|
|
NameMeta: yaml.NameMeta{
|
|
Name: "bar", Namespace: "baz",
|
|
},
|
|
},
|
|
},
|
|
`dir/baz/foo_bar.yaml`, `with namespace`,
|
|
},
|
|
{
|
|
``,
|
|
yaml.ResourceMeta{
|
|
TypeMeta: yaml.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
Kind: "foo",
|
|
},
|
|
ObjectMeta: yaml.ObjectMeta{
|
|
NameMeta: yaml.NameMeta{
|
|
Name: "bar", Namespace: "baz",
|
|
},
|
|
},
|
|
},
|
|
`baz/foo_bar.yaml`, `without dir`,
|
|
},
|
|
{
|
|
`dir`,
|
|
yaml.ResourceMeta{
|
|
TypeMeta: yaml.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
Kind: "foo",
|
|
},
|
|
ObjectMeta: yaml.ObjectMeta{
|
|
NameMeta: yaml.NameMeta{Name: "bar"},
|
|
},
|
|
},
|
|
`dir/foo_bar.yaml`, `without namespace`,
|
|
},
|
|
{
|
|
``,
|
|
yaml.ResourceMeta{
|
|
TypeMeta: yaml.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
Kind: "foo",
|
|
},
|
|
ObjectMeta: yaml.ObjectMeta{
|
|
NameMeta: yaml.NameMeta{Name: "bar"},
|
|
},
|
|
},
|
|
`foo_bar.yaml`, `without namespace or dir`,
|
|
},
|
|
{
|
|
``,
|
|
yaml.ResourceMeta{
|
|
TypeMeta: yaml.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
Kind: "foo",
|
|
},
|
|
ObjectMeta: yaml.ObjectMeta{},
|
|
},
|
|
`foo_.yaml`, `without namespace, dir or name`,
|
|
},
|
|
{
|
|
``,
|
|
yaml.ResourceMeta{
|
|
TypeMeta: yaml.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
},
|
|
ObjectMeta: yaml.ObjectMeta{},
|
|
},
|
|
`_.yaml`, `without any`,
|
|
},
|
|
}
|
|
|
|
for _, s := range tests {
|
|
p := kioutil.CreatePathAnnotationValue(s.dir, s.meta)
|
|
if !assert.Equal(t, s.expected, p, s.name) {
|
|
t.FailNow()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCopyLegacyAnnotations(t *testing.T) {
|
|
var tests = []struct {
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/index: '5'
|
|
`,
|
|
expected: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
`,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
`,
|
|
expected: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/index: '5'
|
|
`,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/path: 'c/d.yaml'
|
|
`,
|
|
expected: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
config.kubernetes.io/path: 'c/d.yaml'
|
|
`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
rw := kio.ByteReadWriter{
|
|
Reader: bytes.NewBufferString(tc.input),
|
|
OmitReaderAnnotations: true,
|
|
}
|
|
nodes, err := rw.Read()
|
|
require.NoError(t, err)
|
|
require.NoError(t, kioutil.CopyLegacyAnnotations(nodes[0]))
|
|
assert.Equal(t, tc.expected, nodes[0].MustString())
|
|
}
|
|
}
|
|
|
|
func TestCopyInternalAnnotations(t *testing.T) {
|
|
var tests = []struct {
|
|
input string
|
|
exclusions []kioutil.AnnotationKey
|
|
expected string
|
|
}{
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: src
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/foo: 'bar'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: dst
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
`,
|
|
expected: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: dst
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/foo: 'bar'
|
|
`,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: src
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/foo: 'bar-src'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: dst
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
internal.config.kubernetes.io/foo: 'bar-dst'
|
|
`,
|
|
exclusions: []kioutil.AnnotationKey{
|
|
kioutil.PathAnnotation,
|
|
kioutil.IndexAnnotation,
|
|
},
|
|
expected: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: dst
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
internal.config.kubernetes.io/foo: 'bar-src'
|
|
`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
rw := kio.ByteReadWriter{
|
|
Reader: bytes.NewBufferString(tc.input),
|
|
OmitReaderAnnotations: true,
|
|
}
|
|
nodes, err := rw.Read()
|
|
require.NoError(t, err)
|
|
require.NoError(t, kioutil.CopyInternalAnnotations(nodes[0], nodes[1], tc.exclusions...))
|
|
assert.Equal(t, tc.expected, nodes[1].MustString())
|
|
}
|
|
}
|
|
|
|
func TestConfirmInternalAnnotationUnchanged(t *testing.T) {
|
|
var tests = []struct {
|
|
input string
|
|
exclusions []kioutil.AnnotationKey
|
|
expectedErr string
|
|
}{
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-1
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-2
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
`,
|
|
expectedErr: `internal annotations differ: internal.config.kubernetes.io/index, internal.config.kubernetes.io/path`,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-1
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-2
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
`,
|
|
exclusions: []kioutil.AnnotationKey{
|
|
kioutil.PathAnnotation,
|
|
kioutil.IndexAnnotation,
|
|
},
|
|
expectedErr: ``,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-1
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/foo: 'bar-1'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-2
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
internal.config.kubernetes.io/foo: 'bar-2'
|
|
`,
|
|
exclusions: []kioutil.AnnotationKey{
|
|
kioutil.PathAnnotation,
|
|
kioutil.IndexAnnotation,
|
|
},
|
|
expectedErr: `internal annotations differ: internal.config.kubernetes.io/foo`,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-1
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/foo: 'bar-1'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-2
|
|
annotations:
|
|
internal.config.kubernetes.io/path: 'c/d.yaml'
|
|
internal.config.kubernetes.io/index: '10'
|
|
internal.config.kubernetes.io/foo: 'bar-1'
|
|
`,
|
|
expectedErr: `internal annotations differ: internal.config.kubernetes.io/index, internal.config.kubernetes.io/path`,
|
|
},
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-1
|
|
annotations:
|
|
internal.config.kubernetes.io/a: 'b'
|
|
internal.config.kubernetes.io/c: 'd'
|
|
---
|
|
apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foo-2
|
|
annotations:
|
|
internal.config.kubernetes.io/e: 'f'
|
|
internal.config.kubernetes.io/g: 'h'
|
|
`,
|
|
expectedErr: `internal annotations differ: ` +
|
|
`internal.config.kubernetes.io/a, internal.config.kubernetes.io/c, ` +
|
|
`internal.config.kubernetes.io/e, internal.config.kubernetes.io/g`,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
rw := kio.ByteReadWriter{
|
|
Reader: bytes.NewBufferString(tc.input),
|
|
OmitReaderAnnotations: true,
|
|
}
|
|
nodes, err := rw.Read()
|
|
require.NoError(t, err)
|
|
err = kioutil.ConfirmInternalAnnotationUnchanged(nodes[0], nodes[1], tc.exclusions...)
|
|
if tc.expectedErr == "" {
|
|
require.NoError(t, err)
|
|
} else {
|
|
if err == nil {
|
|
t.Fatalf("expected error: %s\n", tc.expectedErr)
|
|
}
|
|
assert.Equal(t, tc.expectedErr, err.Error())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetInternalAnnotations(t *testing.T) {
|
|
var tests = []struct {
|
|
input string
|
|
expected map[string]string
|
|
}{
|
|
{
|
|
input: `apiVersion: v1
|
|
kind: Foo
|
|
metadata:
|
|
name: foobar
|
|
annotations:
|
|
foo: bar
|
|
internal.config.kubernetes.io/path: 'a/b.yaml'
|
|
internal.config.kubernetes.io/index: '5'
|
|
internal.config.kubernetes.io/foo: 'bar'
|
|
`,
|
|
expected: map[string]string{
|
|
"internal.config.kubernetes.io/path": "a/b.yaml",
|
|
"internal.config.kubernetes.io/index": "5",
|
|
"internal.config.kubernetes.io/foo": "bar",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
rw := kio.ByteReadWriter{
|
|
Reader: bytes.NewBufferString(tc.input),
|
|
OmitReaderAnnotations: true,
|
|
}
|
|
nodes, err := rw.Read()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, tc.expected, kioutil.GetInternalAnnotations(nodes[0]))
|
|
}
|
|
}
|