Skip to content

Commit 92c1d38

Browse files
authored
Merge pull request #258 from com6056/jrodgers-nil-ptr-check
fix panic when calling ToUnstructured on nil metav1.Time
2 parents cf09e71 + f0cbe01 commit 92c1d38

File tree

2 files changed

+54
-5
lines changed

2 files changed

+54
-5
lines changed

Diff for: value/reflectcache.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -184,18 +184,18 @@ func (e TypeReflectCacheEntry) ToUnstructured(sv reflect.Value) (interface{}, er
184184
// This is based on https://github.com/kubernetes/kubernetes/blob/82c9e5c814eb7acc6cc0a090c057294d0667ad66/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L505
185185
// and is intended to replace it.
186186

187+
// Check if the object is a nil pointer.
188+
if sv.Kind() == reflect.Ptr && sv.IsNil() {
189+
// We're done - we don't need to store anything.
190+
return nil, nil
191+
}
187192
// Check if the object has a custom string converter and use it if available, since it is much more efficient
188193
// than round tripping through json.
189194
if converter, ok := e.getUnstructuredConverter(sv); ok {
190195
return converter.ToUnstructured(), nil
191196
}
192197
// Check if the object has a custom JSON marshaller/unmarshaller.
193198
if marshaler, ok := e.getJsonMarshaler(sv); ok {
194-
if sv.Kind() == reflect.Ptr && sv.IsNil() {
195-
// We're done - we don't need to store anything.
196-
return nil, nil
197-
}
198-
199199
data, err := marshaler.MarshalJSON()
200200
if err != nil {
201201
return nil, err

Diff for: value/reflectcache_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package value
1919
import (
2020
"reflect"
2121
"testing"
22+
"time"
2223
)
2324

2425
type CustomValue struct {
@@ -39,6 +40,21 @@ func (c *CustomPointer) MarshalJSON() ([]byte, error) {
3940
return c.data, nil
4041
}
4142

43+
// Mimics https://github.com/kubernetes/apimachinery/blob/master/pkg/apis/meta/v1/time.go.
44+
type Time struct {
45+
time.Time
46+
}
47+
48+
// ToUnstructured implements the value.UnstructuredConverter interface.
49+
func (t Time) ToUnstructured() interface{} {
50+
if t.IsZero() {
51+
return nil
52+
}
53+
buf := make([]byte, 0, len(time.RFC3339))
54+
buf = t.UTC().AppendFormat(buf, time.RFC3339)
55+
return string(buf)
56+
}
57+
4258
func TestToUnstructured(t *testing.T) {
4359
testcases := []struct {
4460
Data string
@@ -78,6 +94,39 @@ func TestToUnstructured(t *testing.T) {
7894
}
7995
}
8096

97+
func timePtr(t time.Time) *time.Time { return &t }
98+
99+
func TestTimeToUnstructured(t *testing.T) {
100+
testcases := []struct {
101+
Name string
102+
Time *time.Time
103+
Expected interface{}
104+
}{
105+
{Name: "nil", Time: nil, Expected: nil},
106+
{Name: "zero", Time: &time.Time{}, Expected: nil},
107+
{Name: "1", Time: timePtr(time.Time{}.Add(time.Second)), Expected: "0001-01-01T00:00:01Z"},
108+
}
109+
110+
for _, tc := range testcases {
111+
tc := tc
112+
t.Run(tc.Name, func(t *testing.T) {
113+
t.Parallel()
114+
var time *Time
115+
rv := reflect.ValueOf(time)
116+
if tc.Time != nil {
117+
rv = reflect.ValueOf(Time{Time: *tc.Time})
118+
}
119+
result, err := TypeReflectEntryOf(rv.Type()).ToUnstructured(rv)
120+
if err != nil {
121+
t.Fatal(err)
122+
}
123+
if !reflect.DeepEqual(result, tc.Expected) {
124+
t.Errorf("expected %#v but got %#v", tc.Expected, result)
125+
}
126+
})
127+
}
128+
}
129+
81130
func TestTypeReflectEntryOf(t *testing.T) {
82131
testString := ""
83132
tests := map[string]struct {

0 commit comments

Comments
 (0)