constellation/bootstrapper/internal/kubernetes/k8sapi/resources/marshal_test.go

361 lines
6.4 KiB
Go

package resources
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 {
resources any
wantErr bool
wantYAML string
}{
"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",
},
},
},
wantYAML: `apiVersion: v1
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"),
},
},
},
wantYAML: `apiVersion: v1
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",
wantErr: true,
},
"Nil resource pointer is detected": {
resources: nil,
wantErr: true,
},
"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)
if tc.wantErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.wantYAML, string(yaml))
})
}
}
func TestUnmarshalK8SResources(t *testing.T) {
testCases := map[string]struct {
data string
into any
wantObj any
wantErr bool
}{
"ConfigMap as only field can be unmarshaled": {
data: `apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
creationTimestamp: null
`,
into: &struct {
ConfigMap k8s.ConfigMap
}{},
wantObj: &struct {
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
}{},
wantObj: &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"),
},
},
},
},
"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
}{},
wantErr: true,
},
"Non-struct pointer is detected": {
into: proto.String("test"),
wantErr: true,
},
"Nil into is detected": {
into: nil,
wantErr: true,
},
"Invalid yaml is detected": {
data: `duplicateKey: value
duplicateKey: value`,
into: &struct {
ConfigMap k8s.ConfigMap
}{},
wantErr: true,
},
"Struct field cannot interface with runtime.Object": {
data: `apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
creationTimestamp: null
`,
into: &struct {
String string
}{},
wantErr: true,
},
"Struct field mismatch": {
data: `apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
creationTimestamp: null
`,
into: &struct {
Secret k8s.Secret
}{},
wantErr: true,
},
}
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)
if tc.wantErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.wantObj, tc.into)
})
}
}
func TestMarshalK8SResourcesList(t *testing.T) {
testCases := map[string]struct {
resources []runtime.Object
wantErr bool
wantYAML string
}{
"ConfigMap as only element be marshaled": {
resources: []runtime.Object{
&k8s.ConfigMap{
TypeMeta: v1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
Data: map[string]string{
"key": "value",
},
},
},
wantYAML: `apiVersion: v1
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"),
},
},
},
wantYAML: `apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
creationTimestamp: null
---
apiVersion: v1
data:
key: dmFsdWU=
kind: Secret
metadata:
creationTimestamp: null
`,
},
"Nil resource pointer is encodes": {
resources: []runtime.Object{nil},
wantYAML: "null\n",
},
}
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)
if tc.wantErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.wantYAML, string(yaml))
})
}
}