mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
ByteReader/Writer support for serializing ResourceList.results field
This commit is contained in:
@@ -41,6 +41,8 @@ type ByteReadWriter struct {
|
||||
|
||||
FunctionConfig *yaml.RNode
|
||||
|
||||
Results *yaml.RNode
|
||||
|
||||
WrappingAPIVersion string
|
||||
WrappingKind string
|
||||
}
|
||||
@@ -52,6 +54,7 @@ func (rw *ByteReadWriter) Read() ([]*yaml.RNode, error) {
|
||||
}
|
||||
val, err := b.Read()
|
||||
rw.FunctionConfig = b.FunctionConfig
|
||||
rw.Results = b.Results
|
||||
rw.WrappingAPIVersion = b.WrappingAPIVersion
|
||||
rw.WrappingKind = b.WrappingKind
|
||||
return val, errors.Wrap(err)
|
||||
@@ -63,6 +66,7 @@ func (rw *ByteReadWriter) Write(nodes []*yaml.RNode) error {
|
||||
KeepReaderAnnotations: rw.KeepReaderAnnotations,
|
||||
Style: rw.Style,
|
||||
FunctionConfig: rw.FunctionConfig,
|
||||
Results: rw.Results,
|
||||
WrappingAPIVersion: rw.WrappingAPIVersion,
|
||||
WrappingKind: rw.WrappingKind,
|
||||
}.Write(nodes)
|
||||
@@ -85,6 +89,8 @@ type ByteReader struct {
|
||||
|
||||
FunctionConfig *yaml.RNode
|
||||
|
||||
Results *yaml.RNode
|
||||
|
||||
// DisableUnwrapping prevents Resources in Lists and ResourceLists from being unwrapped
|
||||
DisableUnwrapping bool
|
||||
|
||||
@@ -142,10 +148,12 @@ func (r *ByteReader) Read() ([]*yaml.RNode, error) {
|
||||
r.WrappingAPIVersion = meta.APIVersion
|
||||
|
||||
// unwrap the list
|
||||
fc := node.Field("functionConfig")
|
||||
if fc != nil {
|
||||
if fc := node.Field("functionConfig"); fc != nil {
|
||||
r.FunctionConfig = fc.Value
|
||||
}
|
||||
if res := node.Field("results"); res != nil {
|
||||
r.Results = res.Value
|
||||
}
|
||||
|
||||
items := node.Field("items")
|
||||
if items != nil {
|
||||
|
||||
@@ -5,36 +5,64 @@ package kio_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
. "sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
// getByteReaderTestInput returns test input
|
||||
func getByteReaderTestInput(t *testing.T) *bytes.Buffer {
|
||||
b := &bytes.Buffer{}
|
||||
_, err := b.WriteString(`
|
||||
---
|
||||
a: b # first resource
|
||||
c: d
|
||||
---
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
---
|
||||
---
|
||||
i: j
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
assert.FailNow(t, "")
|
||||
func TestByteReader(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
input string
|
||||
err string
|
||||
expectedItems []string
|
||||
expectedFunctionConfig string
|
||||
expectedResults string
|
||||
wrappingAPIVersion string
|
||||
wrappingAPIKind string
|
||||
instance ByteReader
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func TestByteReader_Read_wrappedResourceßßList(t *testing.T) {
|
||||
r := &ByteReader{Reader: bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1
|
||||
testCases := []testCase{
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "wrapped_resource_list",
|
||||
input: `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
expectedItems: []string{
|
||||
`kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
`,
|
||||
`kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
},
|
||||
wrappingAPIVersion: ResourceListAPIVersion,
|
||||
wrappingAPIKind: ResourceListKind,
|
||||
},
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "wrapped_resource_list_function_config",
|
||||
input: `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
foo: bar
|
||||
@@ -50,109 +78,87 @@ items:
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`)}
|
||||
nodes, err := r.Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// verify the contents
|
||||
if !assert.Len(t, nodes, 2) {
|
||||
return
|
||||
}
|
||||
expected := []string{
|
||||
`kind: Deployment
|
||||
`,
|
||||
expectedItems: []string{
|
||||
`kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
`,
|
||||
`kind: Service
|
||||
`kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
}
|
||||
for i := range nodes {
|
||||
if !assert.Equal(t, expected[i], nodes[i].MustString()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// verify the function config
|
||||
assert.Equal(t, `foo: bar
|
||||
},
|
||||
expectedFunctionConfig: `foo: bar
|
||||
elems:
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
`, r.FunctionConfig.MustString())
|
||||
- c`,
|
||||
wrappingAPIVersion: ResourceListAPIVersion,
|
||||
wrappingAPIKind: ResourceListKind,
|
||||
},
|
||||
|
||||
assert.Equal(t, ResourceListKind, r.WrappingKind)
|
||||
assert.Equal(t, ResourceListAPIVersion, r.WrappingAPIVersion)
|
||||
}
|
||||
|
||||
func TestByteReader_Read_wrappedList(t *testing.T) {
|
||||
r := &ByteReader{Reader: bytes.NewBufferString(`apiVersion: v1
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "wrapped_list",
|
||||
input: `
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`)}
|
||||
nodes, err := r.Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// verify the contents
|
||||
if !assert.Len(t, nodes, 2) {
|
||||
return
|
||||
}
|
||||
expected := []string{
|
||||
`kind: Deployment
|
||||
`,
|
||||
expectedItems: []string{
|
||||
`
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
`,
|
||||
`kind: Service
|
||||
`
|
||||
kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
}
|
||||
for i := range nodes {
|
||||
if !assert.Equal(t, expected[i], nodes[i].MustString()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
wrappingAPIKind: "List",
|
||||
wrappingAPIVersion: "v1",
|
||||
},
|
||||
|
||||
// verify the function config
|
||||
assert.Nil(t, r.FunctionConfig)
|
||||
assert.Equal(t, "List", r.WrappingKind)
|
||||
assert.Equal(t, "v1", r.WrappingAPIVersion)
|
||||
}
|
||||
|
||||
// TestByteReader_Read tests the default Read behavior
|
||||
// - Resources are read into a slice
|
||||
// - ReaderAnnotations are set on the ResourceNodes
|
||||
func TestByteReader_Read(t *testing.T) {
|
||||
nodes, err := (&ByteReader{Reader: getByteReaderTestInput(t)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Len(t, nodes, 3) {
|
||||
return
|
||||
}
|
||||
expected := []string{
|
||||
`a: b # first resource
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "unwrapped_items",
|
||||
input: `
|
||||
---
|
||||
a: b # first resource
|
||||
c: d
|
||||
---
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
---
|
||||
---
|
||||
i: j
|
||||
`,
|
||||
expectedItems: []string{
|
||||
`a: b # first resource
|
||||
c: d
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
`,
|
||||
`# second resource
|
||||
`# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
@@ -160,150 +166,209 @@ metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
`,
|
||||
`i: j
|
||||
`i: j
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '2'
|
||||
`,
|
||||
}
|
||||
for i := range nodes {
|
||||
val, err := nodes[i].String()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, expected[i], val) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// TestByteReader_Read_omitReaderAnnotations tests
|
||||
// - Resources are read into a slice
|
||||
// - ReaderAnnotations are not set on the ResourceNodes
|
||||
func TestByteReader_Read_omitReaderAnnotations(t *testing.T) {
|
||||
nodes, err := (&ByteReader{
|
||||
Reader: getByteReaderTestInput(t),
|
||||
OmitReaderAnnotations: true}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// should have parsed 3 resources
|
||||
if !assert.Len(t, nodes, 3) {
|
||||
return
|
||||
}
|
||||
expected := []string{
|
||||
"a: b # first resource\nc: d\n",
|
||||
"# second resource\ne: f\ng:\n- h\n",
|
||||
"i: j\n",
|
||||
}
|
||||
for i := range nodes {
|
||||
val, err := nodes[i].String()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, expected[i], val) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestByteReader_Read_omitReaderAnnotations tests
|
||||
// - Resources are read into a slice
|
||||
// - ReaderAnnotations are NOT set on the ResourceNodes
|
||||
// - Additional annotations ARE set on the ResourceNodes
|
||||
func TestByteReader_Read_setAnnotationsOmitReaderAnnotations(t *testing.T) {
|
||||
nodes, err := (&ByteReader{
|
||||
Reader: getByteReaderTestInput(t),
|
||||
SetAnnotations: map[string]string{"foo": "bar"},
|
||||
OmitReaderAnnotations: true,
|
||||
}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Len(t, nodes, 3) {
|
||||
return
|
||||
}
|
||||
expected := []string{
|
||||
`a: b # first resource
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "omit_annotations",
|
||||
input: `
|
||||
---
|
||||
a: b # first resource
|
||||
c: d
|
||||
metadata:
|
||||
annotations:
|
||||
foo: 'bar'
|
||||
`,
|
||||
`# second resource
|
||||
---
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
metadata:
|
||||
annotations:
|
||||
foo: 'bar'
|
||||
---
|
||||
---
|
||||
i: j
|
||||
`,
|
||||
`i: j
|
||||
metadata:
|
||||
annotations:
|
||||
foo: 'bar'
|
||||
expectedItems: []string{
|
||||
`
|
||||
a: b # first resource
|
||||
c: d
|
||||
`,
|
||||
}
|
||||
for i := range nodes {
|
||||
val, err := nodes[i].String()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, expected[i], val) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
`,
|
||||
`
|
||||
i: j
|
||||
`,
|
||||
},
|
||||
instance: ByteReader{OmitReaderAnnotations: true},
|
||||
},
|
||||
|
||||
// TestByteReader_Read_omitReaderAnnotations tests
|
||||
// - Resources are read into a slice
|
||||
// - ReaderAnnotations ARE set on the ResourceNodes
|
||||
// - Additional annotations ARE set on the ResourceNodes
|
||||
func TestByteReader_Read_setAnnotations(t *testing.T) {
|
||||
nodes, err := (&ByteReader{
|
||||
Reader: getByteReaderTestInput(t),
|
||||
SetAnnotations: map[string]string{"foo": "bar"},
|
||||
}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Len(t, nodes, 3) {
|
||||
return
|
||||
}
|
||||
expected := []string{
|
||||
`a: b # first resource
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "no_omit_annotations",
|
||||
input: `
|
||||
---
|
||||
a: b # first resource
|
||||
c: d
|
||||
---
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
---
|
||||
---
|
||||
i: j
|
||||
`,
|
||||
expectedItems: []string{
|
||||
`
|
||||
a: b # first resource
|
||||
c: d
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
foo: 'bar'
|
||||
`,
|
||||
`# second resource
|
||||
`
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
foo: 'bar'
|
||||
`,
|
||||
`i: j
|
||||
`
|
||||
i: j
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '2'
|
||||
`,
|
||||
},
|
||||
instance: ByteReader{},
|
||||
},
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "set_annotation",
|
||||
input: `
|
||||
---
|
||||
a: b # first resource
|
||||
c: d
|
||||
---
|
||||
# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
---
|
||||
---
|
||||
i: j
|
||||
`,
|
||||
expectedItems: []string{
|
||||
`a: b # first resource
|
||||
c: d
|
||||
metadata:
|
||||
annotations:
|
||||
foo: 'bar'
|
||||
`,
|
||||
`# second resource
|
||||
e: f
|
||||
g:
|
||||
- h
|
||||
metadata:
|
||||
annotations:
|
||||
foo: 'bar'
|
||||
`,
|
||||
`i: j
|
||||
metadata:
|
||||
annotations:
|
||||
foo: 'bar'
|
||||
`,
|
||||
},
|
||||
instance: ByteReader{
|
||||
OmitReaderAnnotations: true,
|
||||
SetAnnotations: map[string]string{"foo": "bar"}},
|
||||
},
|
||||
}
|
||||
for i := range nodes {
|
||||
val, err := nodes[i].String()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.Equal(t, expected[i], val) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
tc := testCases[i]
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r := tc.instance
|
||||
r.Reader = bytes.NewBufferString(tc.input)
|
||||
nodes, err := r.Read()
|
||||
if tc.err != "" {
|
||||
if !assert.EqualError(t, err, tc.err) {
|
||||
t.FailNow()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// verify the contents
|
||||
if !assert.Len(t, nodes, len(tc.expectedItems)) {
|
||||
t.FailNow()
|
||||
}
|
||||
for i := range nodes {
|
||||
actual, err := nodes[i].String()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedItems[i]),
|
||||
strings.TrimSpace(actual)) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// verify the function config
|
||||
if tc.expectedFunctionConfig != "" {
|
||||
actual, err := r.FunctionConfig.String()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedFunctionConfig),
|
||||
strings.TrimSpace(actual)) {
|
||||
t.FailNow()
|
||||
}
|
||||
} else if !assert.Nil(t, r.FunctionConfig) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if tc.expectedResults != "" {
|
||||
actual, err := r.Results.String()
|
||||
actual = strings.TrimSpace(actual)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
tc.expectedResults = strings.TrimSpace(tc.expectedResults)
|
||||
if !assert.Equal(t, tc.expectedResults, actual) {
|
||||
t.FailNow()
|
||||
}
|
||||
} else if !assert.Nil(t, r.Results) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !assert.Equal(t, tc.wrappingAPIKind, r.WrappingKind) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t, tc.wrappingAPIVersion, r.WrappingAPIVersion) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
263
kyaml/kio/byteio_readwriter_test.go
Normal file
263
kyaml/kio/byteio_readwriter_test.go
Normal file
@@ -0,0 +1,263 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package kio_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
)
|
||||
|
||||
func TestByteReadWriter(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
err string
|
||||
input string
|
||||
expectedOutput string
|
||||
instance kio.ByteReadWriter
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "round_trip",
|
||||
input: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "function_config",
|
||||
input: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
functionConfig:
|
||||
a: b # something
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
functionConfig:
|
||||
a: b # something
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "results",
|
||||
input: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
results:
|
||||
a: b # something
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
results:
|
||||
a: b # something
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "drop_invalid_resource_list_field",
|
||||
input: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
foo:
|
||||
a: b # something
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "list",
|
||||
input: `
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
expectedOutput: `
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
- kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "multiple_documents",
|
||||
input: `
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
expectedOutput: `
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "keep_annotations",
|
||||
input: `
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
---
|
||||
kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
`,
|
||||
expectedOutput: `
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
---
|
||||
kind: Service
|
||||
spec:
|
||||
selectors:
|
||||
foo: bar
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
`,
|
||||
instance: kio.ByteReadWriter{KeepReaderAnnotations: true},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
tc := testCases[i]
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var in, out bytes.Buffer
|
||||
in.WriteString(tc.input)
|
||||
w := tc.instance
|
||||
w.Writer = &out
|
||||
w.Reader = &in
|
||||
|
||||
nodes, err := w.Read()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
err = w.Write(nodes)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if tc.err != "" {
|
||||
if !assert.EqualError(t, err, tc.err) {
|
||||
t.FailNow()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ type ByteWriter struct {
|
||||
// wrap the results in an ResourceList.
|
||||
FunctionConfig *yaml.RNode
|
||||
|
||||
Results *yaml.RNode
|
||||
|
||||
// WrappingKind if set will cause ByteWriter to wrap the Resources in
|
||||
// an 'items' field in this kind. e.g. if WrappingKind is 'List',
|
||||
// ByteWriter will wrap the Resources in a List .items field.
|
||||
@@ -112,6 +114,11 @@ func (w ByteWriter) Write(nodes []*yaml.RNode) error {
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Value: "functionConfig"},
|
||||
w.FunctionConfig.YNode())
|
||||
}
|
||||
if w.Results != nil {
|
||||
list.Content = append(list.Content,
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Value: "results"},
|
||||
w.Results.YNode())
|
||||
}
|
||||
doc := &yaml.Node{
|
||||
Kind: yaml.DocumentNode,
|
||||
Content: []*yaml.Node{list}}
|
||||
|
||||
@@ -1,96 +1,84 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package kio
|
||||
package kio_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
. "sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// TestByteWriter_Write_withoutAnnotations tests:
|
||||
// - Resource Config ordering is preserved if no annotations are present
|
||||
func TestByteWriter_Write_wrapped(t *testing.T) {
|
||||
node1, err := yaml.Parse(`a: b #first
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
func TestByteWriter(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
err string
|
||||
items []string
|
||||
functionConfig string
|
||||
results string
|
||||
expectedOutput string
|
||||
instance kio.ByteWriter
|
||||
}
|
||||
node2, err := yaml.Parse(`c: d # second
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node3, err := yaml.Parse(`e: f
|
||||
|
||||
testCases := []testCase{
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "wrap_resource_list",
|
||||
instance: ByteWriter{
|
||||
Sort: true,
|
||||
WrappingKind: ResourceListKind,
|
||||
WrappingAPIVersion: ResourceListAPIVersion,
|
||||
},
|
||||
items: []string{
|
||||
`a: b #first`,
|
||||
`c: d # second`,
|
||||
},
|
||||
functionConfig: `
|
||||
e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
- j
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
err = ByteWriter{
|
||||
Sort: true,
|
||||
Writer: buff,
|
||||
FunctionConfig: node3,
|
||||
WrappingKind: ResourceListKind,
|
||||
WrappingAPIVersion: ResourceListAPIVersion}.
|
||||
Write([]*yaml.RNode{node2, node1})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
- j`,
|
||||
expectedOutput: `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- c: d # second
|
||||
- a: b #first
|
||||
- c: d # second
|
||||
functionConfig:
|
||||
e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
- j
|
||||
`, buff.String())
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
// TestByteWriter_Write_withoutAnnotations tests:
|
||||
// - Resource Config ordering is preserved if no annotations are present
|
||||
func TestByteWriter_Write_withoutAnnotations(t *testing.T) {
|
||||
node1, err := yaml.Parse(`a: b #first
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node2, err := yaml.Parse(`c: d # second
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node3, err := yaml.Parse(`e: f
|
||||
//
|
||||
//
|
||||
//
|
||||
{
|
||||
name: "multiple_items",
|
||||
items: []string{
|
||||
`c: d # second`,
|
||||
`e: f
|
||||
g:
|
||||
h:
|
||||
# has a list
|
||||
- i : [i1, i2] # line comment
|
||||
# has a list 2
|
||||
- j : j1
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
err = ByteWriter{Writer: buff}.
|
||||
Write([]*yaml.RNode{node2, node3, node1})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, `c: d # second
|
||||
`,
|
||||
`a: b #first`,
|
||||
},
|
||||
expectedOutput: `
|
||||
c: d # second
|
||||
---
|
||||
e: f
|
||||
g:
|
||||
@@ -101,32 +89,23 @@ g:
|
||||
- j: j1
|
||||
---
|
||||
a: b #first
|
||||
`, buff.String())
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
// TestByteWriter_Write_withAnnotationsKeepAnnotations tests:
|
||||
// - Resource Config is sorted by annotations if present
|
||||
// - IndexAnnotations are retained
|
||||
func TestByteWriter_Write_withAnnotationsKeepAnnotations(t *testing.T) {
|
||||
node1, err := yaml.Parse(`a: b #first
|
||||
//
|
||||
// Test Case
|
||||
//
|
||||
{
|
||||
name: "sort_keep_annotation",
|
||||
instance: ByteWriter{Sort: true, KeepReaderAnnotations: true},
|
||||
items: []string{
|
||||
`a: b #first
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 0
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node2, err := yaml.Parse(`c: d # second
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 1
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node3, err := yaml.Parse(`e: f
|
||||
`,
|
||||
`e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
@@ -135,18 +114,16 @@ metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 0
|
||||
config.kubernetes.io/path: "a/b/b_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
`,
|
||||
`c: d # second
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 1
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`,
|
||||
},
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
err = ByteWriter{Sort: true, Writer: buff, KeepReaderAnnotations: true}.
|
||||
Write([]*yaml.RNode{node2, node3, node1})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, `a: b #first
|
||||
expectedOutput: `a: b #first
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 0
|
||||
@@ -167,109 +144,36 @@ metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 0
|
||||
config.kubernetes.io/path: "a/b/b_test.yaml"
|
||||
`, buff.String())
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
// TestByteWriter_Write_withAnnotations tests:
|
||||
// - Resource Config is sorted by annotations if present
|
||||
// - IndexAnnotations are pruned
|
||||
func TestByteWriter_Write_withAnnotations(t *testing.T) {
|
||||
node1, err := yaml.Parse(`a: b #first
|
||||
//
|
||||
// Test Case
|
||||
//
|
||||
{
|
||||
name: "sort_partial_annotations",
|
||||
instance: ByteWriter{Sort: true},
|
||||
items: []string{
|
||||
`a: b #first
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 0
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node2, err := yaml.Parse(`c: d # second
|
||||
`,
|
||||
`c: d # second
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 1
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node3, err := yaml.Parse(`e: f
|
||||
`,
|
||||
`e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
- j
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 0
|
||||
config.kubernetes.io/path: "a/b/b_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
err = ByteWriter{Sort: true, Writer: buff}.
|
||||
Write([]*yaml.RNode{node2, node3, node1})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, `a: b #first
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
---
|
||||
c: d # second
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
---
|
||||
e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
- j
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/path: "a/b/b_test.yaml"
|
||||
`, buff.String())
|
||||
}
|
||||
|
||||
// TestByteWriter_Write_partialValues tests:
|
||||
// - Resource Config is sorted when annotations are present on some but not all ResourceNodes
|
||||
func TestByteWriter_Write_partialAnnotations(t *testing.T) {
|
||||
node1, err := yaml.Parse(`a: b #first
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node2, err := yaml.Parse(`c: d # second
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/index: 1
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
node3, err := yaml.Parse(`e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
- j
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
rw := ByteWriter{Sort: true, Writer: buff}
|
||||
err = rw.Write([]*yaml.RNode{node2, node3, node1})
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, `e: f
|
||||
expectedOutput: `e: f
|
||||
g:
|
||||
h:
|
||||
- i # has a list
|
||||
@@ -284,5 +188,45 @@ c: d # second
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/path: "a/b/a_test.yaml"
|
||||
`, buff.String())
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
tc := testCases[i]
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual := &bytes.Buffer{}
|
||||
w := tc.instance
|
||||
w.Writer = actual
|
||||
|
||||
if tc.functionConfig != "" {
|
||||
w.FunctionConfig = yaml.MustParse(tc.functionConfig)
|
||||
}
|
||||
|
||||
if tc.results != "" {
|
||||
w.Results = yaml.MustParse(tc.results)
|
||||
}
|
||||
|
||||
var items []*yaml.RNode
|
||||
for i := range tc.items {
|
||||
items = append(items, yaml.MustParse(tc.items[i]))
|
||||
}
|
||||
err := w.Write(items)
|
||||
|
||||
if tc.err != "" {
|
||||
if !assert.EqualError(t, err, tc.err) {
|
||||
t.FailNow()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(actual.String())) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user