2022-08-29 08:30:20 -04:00
|
|
|
package kubernetes
|
2022-03-25 05:19:29 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
k8s "k8s.io/api/core/v1"
|
|
|
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestMarshalK8SResources(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
2022-04-28 04:28:28 -04:00
|
|
|
resources any
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr bool
|
|
|
|
wantYAML string
|
2022-03-25 05:19:29 -04:00
|
|
|
}{
|
|
|
|
"ConfigMap as only field can be marshaled": {
|
|
|
|
resources: &struct {
|
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
}{
|
|
|
|
ConfigMap: k8s.ConfigMap{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string]string{
|
|
|
|
"key": "value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantYAML: `apiVersion: v1
|
2022-03-25 05:19:29 -04:00
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"Multiple fields are correctly encoded": {
|
|
|
|
resources: &struct {
|
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
Secret k8s.Secret
|
|
|
|
}{
|
|
|
|
ConfigMap: k8s.ConfigMap{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string]string{
|
|
|
|
"key": "value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Secret: k8s.Secret{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "Secret",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
|
|
"key": []byte("value"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantYAML: `apiVersion: v1
|
2022-03-25 05:19:29 -04:00
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
---
|
|
|
|
apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: dmFsdWU=
|
|
|
|
kind: Secret
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"Non-pointer is detected": {
|
|
|
|
resources: "non-pointer",
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Nil resource pointer is detected": {
|
|
|
|
resources: nil,
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Non-pointer field is ignored": {
|
|
|
|
resources: &struct{ String string }{String: "somestring"},
|
|
|
|
},
|
|
|
|
"nil field is ignored": {
|
|
|
|
resources: &struct {
|
|
|
|
ConfigMap *k8s.ConfigMap
|
|
|
|
}{
|
|
|
|
ConfigMap: nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
yaml, err := MarshalK8SResources(tc.resources)
|
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-03-25 05:19:29 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
assert.Equal(tc.wantYAML, string(yaml))
|
2022-03-25 05:19:29 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnmarshalK8SResources(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
2022-04-26 10:54:05 -04:00
|
|
|
data string
|
2022-04-28 04:28:28 -04:00
|
|
|
into any
|
|
|
|
wantObj any
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr bool
|
2022-03-25 05:19:29 -04:00
|
|
|
}{
|
|
|
|
"ConfigMap as only field can be unmarshaled": {
|
|
|
|
data: `apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
into: &struct {
|
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
}{},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantObj: &struct {
|
2022-03-25 05:19:29 -04:00
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
}{
|
|
|
|
ConfigMap: k8s.ConfigMap{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string]string{
|
|
|
|
"key": "value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"Multiple fields are correctly unmarshaled": {
|
|
|
|
data: `apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
---
|
|
|
|
apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: dmFsdWU=
|
|
|
|
kind: Secret
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
into: &struct {
|
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
Secret k8s.Secret
|
|
|
|
}{},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantObj: &struct {
|
2022-03-25 05:19:29 -04:00
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
Secret k8s.Secret
|
|
|
|
}{
|
|
|
|
ConfigMap: k8s.ConfigMap{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string]string{
|
|
|
|
"key": "value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Secret: k8s.Secret{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "Secret",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
|
|
"key": []byte("value"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"Mismatching amount of fields is detected": {
|
|
|
|
data: `apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
---
|
|
|
|
apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: dmFsdWU=
|
|
|
|
kind: Secret
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
into: &struct {
|
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
}{},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Non-struct pointer is detected": {
|
2022-04-26 10:54:05 -04:00
|
|
|
into: proto.String("test"),
|
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Nil into is detected": {
|
2022-04-26 10:54:05 -04:00
|
|
|
into: nil,
|
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Invalid yaml is detected": {
|
|
|
|
data: `duplicateKey: value
|
|
|
|
duplicateKey: value`,
|
|
|
|
into: &struct {
|
|
|
|
ConfigMap k8s.ConfigMap
|
|
|
|
}{},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Struct field cannot interface with runtime.Object": {
|
|
|
|
data: `apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
into: &struct {
|
|
|
|
String string
|
|
|
|
}{},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
"Struct field mismatch": {
|
|
|
|
data: `apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
into: &struct {
|
|
|
|
Secret k8s.Secret
|
|
|
|
}{},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
err := UnmarshalK8SResources([]byte(tc.data), tc.into)
|
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-03-25 05:19:29 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
assert.Equal(tc.wantObj, tc.into)
|
2022-03-25 05:19:29 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMarshalK8SResourcesList(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
2022-04-26 10:54:05 -04:00
|
|
|
resources []runtime.Object
|
|
|
|
wantErr bool
|
|
|
|
wantYAML string
|
2022-03-25 05:19:29 -04:00
|
|
|
}{
|
|
|
|
"ConfigMap as only element be marshaled": {
|
|
|
|
resources: []runtime.Object{
|
|
|
|
&k8s.ConfigMap{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string]string{
|
|
|
|
"key": "value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantYAML: `apiVersion: v1
|
2022-03-25 05:19:29 -04:00
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"Multiple fields are correctly encoded": {
|
|
|
|
resources: []runtime.Object{
|
|
|
|
&k8s.ConfigMap{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "ConfigMap",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string]string{
|
|
|
|
"key": "value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
&k8s.Secret{
|
|
|
|
TypeMeta: v1.TypeMeta{
|
|
|
|
Kind: "Secret",
|
|
|
|
APIVersion: "v1",
|
|
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
|
|
"key": []byte("value"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantYAML: `apiVersion: v1
|
2022-03-25 05:19:29 -04:00
|
|
|
data:
|
|
|
|
key: value
|
|
|
|
kind: ConfigMap
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
---
|
|
|
|
apiVersion: v1
|
|
|
|
data:
|
|
|
|
key: dmFsdWU=
|
|
|
|
kind: Secret
|
|
|
|
metadata:
|
|
|
|
creationTimestamp: null
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"Nil resource pointer is encodes": {
|
2022-04-26 10:54:05 -04:00
|
|
|
resources: []runtime.Object{nil},
|
|
|
|
wantYAML: "null\n",
|
2022-03-25 05:19:29 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
|
|
|
|
|
|
|
yaml, err := MarshalK8SResourcesList(tc.resources)
|
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-03-25 05:19:29 -04:00
|
|
|
assert.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(err)
|
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
assert.Equal(tc.wantYAML, string(yaml))
|
2022-03-25 05:19:29 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|