1
16
17 package roundtrip
18
19 import (
20 "fmt"
21 "reflect"
22 "strconv"
23 "strings"
24 "time"
25
26 apimeta "k8s.io/apimachinery/pkg/api/meta"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/util/intstr"
31 )
32
33 func defaultFillFuncs() map[reflect.Type]FillFunc {
34 funcs := map[reflect.Type]FillFunc{}
35 funcs[reflect.TypeOf(&runtime.RawExtension{})] = func(s string, i int, obj interface{}) {
36
37
38 obj.(*runtime.RawExtension).Raw = []byte(`{"apiVersion":"example.com/v1","kind":"CustomType","spec":{"replicas":1},"status":{"available":1}}`)
39 }
40 funcs[reflect.TypeOf(&metav1.TypeMeta{})] = func(s string, i int, obj interface{}) {
41
42 obj.(*metav1.TypeMeta).APIVersion = ""
43 obj.(*metav1.TypeMeta).Kind = ""
44 }
45 funcs[reflect.TypeOf(&metav1.FieldsV1{})] = func(s string, i int, obj interface{}) {
46 obj.(*metav1.FieldsV1).Raw = []byte(`{}`)
47 }
48 funcs[reflect.TypeOf(&metav1.Time{})] = func(s string, i int, obj interface{}) {
49
50 obj.(*metav1.Time).Time = time.Date(2000+i, 1, 1, 1, 1, 1, 0, time.UTC)
51 }
52 funcs[reflect.TypeOf(&metav1.MicroTime{})] = func(s string, i int, obj interface{}) {
53
54 obj.(*metav1.MicroTime).Time = time.Date(2000+i, 1, 1, 1, 1, 1, i*int(time.Microsecond), time.UTC)
55 }
56 funcs[reflect.TypeOf(&intstr.IntOrString{})] = func(s string, i int, obj interface{}) {
57
58 obj.(*intstr.IntOrString).Type = intstr.String
59 obj.(*intstr.IntOrString).StrVal = s + "Value"
60 }
61 return funcs
62 }
63
64
65 func CompatibilityTestObject(scheme *runtime.Scheme, gvk schema.GroupVersionKind, fillFuncs map[reflect.Type]FillFunc) (runtime.Object, error) {
66
67 obj, err := scheme.New(gvk)
68 if err != nil {
69 return nil, err
70 }
71
72 fill("", 0, reflect.TypeOf(obj), reflect.ValueOf(obj), fillFuncs, map[reflect.Type]bool{})
73
74
75 if typeAcc, err := apimeta.TypeAccessor(obj); err != nil {
76 return nil, err
77 } else {
78 typeAcc.SetKind(gvk.Kind)
79 typeAcc.SetAPIVersion(gvk.GroupVersion().String())
80 }
81
82 return obj, nil
83 }
84
85 func fill(dataString string, dataInt int, t reflect.Type, v reflect.Value, fillFuncs map[reflect.Type]FillFunc, filledTypes map[reflect.Type]bool) {
86 if filledTypes[t] {
87
88 return
89 }
90 filledTypes[t] = true
91 defer delete(filledTypes, t)
92
93
94 if t.Kind() == reflect.Pointer && v.IsNil() {
95 if v.CanSet() {
96 v.Set(reflect.New(t.Elem()))
97 } else if v.IsNil() {
98 panic(fmt.Errorf("unsettable nil pointer of type %v in field %s", t, dataString))
99 }
100 }
101
102 if f, ok := fillFuncs[t]; ok {
103
104 f(dataString, dataInt, v.Interface())
105 return
106 }
107
108 switch t.Kind() {
109 case reflect.Slice:
110
111 v.Set(reflect.MakeSlice(t, 1, 1))
112
113 if t.Elem().Kind() == reflect.Pointer {
114 fill(dataString, dataInt, t.Elem(), v.Index(0), fillFuncs, filledTypes)
115 } else {
116 fill(dataString, dataInt, reflect.PointerTo(t.Elem()), v.Index(0).Addr(), fillFuncs, filledTypes)
117 }
118
119 case reflect.Map:
120
121 key := reflect.ValueOf(dataString + "Key").Convert(t.Key())
122
123 item := reflect.New(t.Elem())
124
125 fill(dataString, dataInt, t.Elem(), item.Elem(), fillFuncs, filledTypes)
126
127 v.Set(reflect.MakeMap(t))
128 v.SetMapIndex(key, item.Elem())
129
130 case reflect.Struct:
131 for i := 0; i < t.NumField(); i++ {
132 field := t.Field(i)
133
134 if !field.IsExported() {
135 continue
136 }
137
138
139 dataString := strings.Split(field.Tag.Get("json"), ",")[0]
140 if dataString == "-" {
141
142 continue
143 }
144 if len(dataString) == 0 {
145
146 dataString = "<no json tag> " + field.Name
147 }
148
149
150 dataInt := 0
151 if protobufTagParts := strings.Split(field.Tag.Get("protobuf"), ","); len(protobufTagParts) > 1 {
152 if tag, err := strconv.Atoi(protobufTagParts[1]); err != nil {
153 panic(err)
154 } else {
155 dataInt = tag
156 }
157 }
158 if dataInt == 0 {
159
160 dataInt = -len(dataString)
161 }
162
163 fieldType := field.Type
164 fieldValue := v.Field(i)
165
166 fill(dataString, dataInt, reflect.PointerTo(fieldType), fieldValue.Addr(), fillFuncs, filledTypes)
167 }
168
169 case reflect.Pointer:
170 fill(dataString, dataInt, t.Elem(), v.Elem(), fillFuncs, filledTypes)
171
172 case reflect.String:
173
174 v.Set(reflect.ValueOf(dataString + "Value").Convert(t))
175
176 case reflect.Bool:
177
178 v.Set(reflect.ValueOf(true).Convert(t))
179
180 case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
181
182 v.Set(reflect.ValueOf(dataInt).Convert(t))
183
184 case reflect.Float32, reflect.Float64:
185
186 v.Set(reflect.ValueOf(float32(dataInt) + 0.5).Convert(t))
187
188 default:
189 panic(fmt.Errorf("unhandled type %v in field %s", t, dataString))
190 }
191 }
192
View as plain text