Skip to content

Commit ba15690

Browse files
authored
Initialize resourcelist.functionConfig even if it's empty. (#570)
1 parent cdc9f0c commit ba15690

File tree

4 files changed

+100
-11
lines changed

4 files changed

+100
-11
lines changed

go/fn/internal/map.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type MapVariant struct {
4646
node *yaml.Node
4747
}
4848

49+
4950
func (o *MapVariant) GetKind() variantKind {
5051
return variantKindMap
5152
}

go/fn/object.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,11 +307,14 @@ func (o *SubObject) SetOrDie(val interface{}, fields ...string) {
307307
// use Get method and modify the underlying yaml.Node.
308308
func (o *SubObject) SetNestedField(val interface{}, fields ...string) error {
309309
err := func() error {
310+
if val == nil {
311+
return fmt.Errorf("the passed-in object must not be nil")
312+
}
310313
if o == nil {
311314
return fmt.Errorf("the object doesn't exist")
312315
}
313-
if val == nil {
314-
return fmt.Errorf("the passed-in object must not be nil")
316+
if o.obj == nil {
317+
o.obj = internal.NewMap(nil)
315318
}
316319
kind := reflect.ValueOf(val).Kind()
317320
if kind == reflect.Ptr {
@@ -531,7 +534,7 @@ func (o *KubeObject) GetKind() string {
531534
}
532535

533536
func (o *KubeObject) SetKind(kind string) {
534-
if err := o.obj.SetNestedString(kind, "kind"); err != nil {
537+
if err := o.SetNestedField(kind, "kind"); err != nil {
535538
panic(fmt.Errorf("cannot set kind '%v': %v", kind, err))
536539
}
537540
}
@@ -542,7 +545,7 @@ func (o *KubeObject) GetName() string {
542545
}
543546

544547
func (o *KubeObject) SetName(name string) {
545-
if err := o.obj.SetNestedString(name, "metadata", "name"); err != nil {
548+
if err := o.SetNestedField(name, "metadata", "name"); err != nil {
546549
panic(fmt.Errorf("cannot set metadata name '%v': %v", name, err))
547550
}
548551
}
@@ -574,13 +577,13 @@ func (o *KubeObject) HasNamespace() bool {
574577
}
575578

576579
func (o *KubeObject) SetNamespace(name string) {
577-
if err := o.obj.SetNestedString(name, "metadata", "namespace"); err != nil {
580+
if err := o.SetNestedField(name, "metadata", "namespace"); err != nil {
578581
panic(fmt.Errorf("cannot set namespace '%v': %v", name, err))
579582
}
580583
}
581584

582585
func (o *KubeObject) SetAnnotation(k, v string) {
583-
if err := o.obj.SetNestedString(v, "metadata", "annotations", k); err != nil {
586+
if err := o.SetNestedField(v, "metadata", "annotations", k); err != nil {
584587
panic(fmt.Errorf("cannot set metadata annotations '%v': %v", k, err))
585588
}
586589
}
@@ -611,7 +614,7 @@ func (o *KubeObject) RemoveAnnotationsIfEmpty() error {
611614
}
612615

613616
func (o *KubeObject) SetLabel(k, v string) {
614-
if err := o.obj.SetNestedString(v, "metadata", "labels", k); err != nil {
617+
if err := o.SetNestedField(v, "metadata", "labels", k); err != nil {
615618
panic(fmt.Errorf("cannot set metadata labels '%v': %v", k, err))
616619
}
617620
}
@@ -666,6 +669,14 @@ func (o KubeObjects) Less(i, j int) bool {
666669
return idStrI < idStrJ
667670
}
668671

672+
func (o *KubeObject) IsEmpty() bool {
673+
return yaml.IsYNodeEmptyMap(o.obj.Node())
674+
}
675+
676+
func NewEmptyKubeObject() *KubeObject {
677+
return &KubeObject{SubObject{internal.NewMap(nil)}}
678+
}
679+
669680
func asKubeObject(obj *internal.MapVariant) *KubeObject {
670681
return &KubeObject{SubObject{obj}}
671682
}

go/fn/object_test.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package fn
22

3-
import "testing"
3+
import (
4+
"testing"
5+
)
46

57
func TestIsNamespaceScoped(t *testing.T) {
68
testdata := map[string]struct{
@@ -59,3 +61,74 @@ metadata:
5961
}
6062
}
6163
}
64+
65+
var noFnConfigResourceList = []byte(`apiVersion: config.kubernetes.io/v1
66+
kind: ResourceList
67+
`)
68+
func TestNilFnConfigResourceList(t *testing.T) {
69+
rl, _ := ParseResourceList(noFnConfigResourceList)
70+
if rl.FunctionConfig == nil {
71+
t.Errorf("Empty functionConfig in ResourceList should still be initialized to avoid nil pointer error")
72+
}
73+
if !rl.FunctionConfig.IsEmpty() {
74+
t.Errorf("The dummy fnConfig should be surfaced and checkable.")
75+
}
76+
// Check that FunctionConfig should be able to call KRM methods even if its Nil"
77+
{
78+
if rl.FunctionConfig.GetKind() != "" {
79+
t.Errorf("Nil KubeObject cannot call GetKind()")
80+
}
81+
if rl.FunctionConfig.GetAPIVersion() != "" {
82+
t.Errorf("Nil KubeObject cannot call GetAPIVersion()")
83+
}
84+
if rl.FunctionConfig.GetName() != "" {
85+
t.Errorf("Nil KubeObject cannot call GetName()")
86+
}
87+
if rl.FunctionConfig.GetNamespace() != "" {
88+
t.Errorf("Nil KubeObject cannot call GetNamespace()")
89+
}
90+
if rl.FunctionConfig.GetAnnotation("X") != "" {
91+
t.Errorf("Nil KubeObject cannot call GetAnnotation()")
92+
}
93+
if rl.FunctionConfig.GetLabel("Y") != "" {
94+
t.Errorf("Nil KubeObject cannot call GetLabel()")
95+
}
96+
}
97+
// Check that nil FunctionConfig can use SubObject methods.
98+
{
99+
_, found, err := rl.FunctionConfig.NestedString("not-exist")
100+
if found || err != nil {
101+
t.Errorf("Nil KubeObject shall not have the field path `not-exist` exist, and not expect errors")
102+
}
103+
}
104+
// Check that nil FunctionConfig should be editable.
105+
{
106+
rl.FunctionConfig.SetKind("CustomFn")
107+
if rl.FunctionConfig.GetKind() != "CustomFn" {
108+
t.Errorf("Nil KubeObject cannot call SetKind()")
109+
}
110+
rl.FunctionConfig.SetAPIVersion("kpt.fn/v1")
111+
if rl.FunctionConfig.GetAPIVersion() != "kpt.fn/v1" {
112+
t.Errorf("Nil KubeObject cannot call SetAPIVersion()")
113+
}
114+
rl.FunctionConfig.SetName("test")
115+
if rl.FunctionConfig.GetName() != "test" {
116+
t.Errorf("Nil KubeObject cannot call SetName()")
117+
}
118+
rl.FunctionConfig.SetNamespace("test-ns")
119+
if rl.FunctionConfig.GetNamespace() != "test-ns" {
120+
t.Errorf("Nil KubeObject cannot call SetNamespace()")
121+
}
122+
rl.FunctionConfig.SetAnnotation("k", "v")
123+
if rl.FunctionConfig.GetAnnotation("k") != "v" {
124+
t.Errorf("Nil KubeObject cannot call SetAnnotation()")
125+
}
126+
rl.FunctionConfig.SetLabel("k", "v")
127+
if rl.FunctionConfig.GetLabel("k") != "v" {
128+
t.Errorf("Nil KubeObject cannot call SetLabel()")
129+
}
130+
if rl.FunctionConfig.IsEmpty() {
131+
t.Errorf("The modified fnConfig is not nil.")
132+
}
133+
}
134+
}

go/fn/resourcelist.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,17 @@ func ParseResourceList(in []byte) (*ResourceList, error) {
8888
}
8989
if found {
9090
rl.FunctionConfig = asKubeObject(fc)
91+
} else {
92+
rl.FunctionConfig = NewEmptyKubeObject()
9193
}
9294

93-
items, _, err := rlObj.obj.GetNestedSlice("items")
95+
items, found, err := rlObj.obj.GetNestedSlice("items")
9496
if err != nil {
9597
return nil, fmt.Errorf("failed when tried to get items: %w", err)
9698
}
99+
if !found {
100+
return rl, nil
101+
}
97102
objectItems, err := items.Elements()
98103
if err != nil {
99104
return nil, fmt.Errorf("failed to extract objects from items: %w", err)
@@ -134,8 +139,7 @@ func (rl *ResourceList) toYNode() (*yaml.Node, error) {
134139
return nil, err
135140
}
136141
}
137-
138-
if rl.FunctionConfig != nil {
142+
if !rl.FunctionConfig.IsEmpty() {
139143
if err := reMap.SetNestedMap(rl.FunctionConfig.node(), "functionConfig"); err != nil {
140144
return nil, err
141145
}

0 commit comments

Comments
 (0)