1 package v2_test
2
3 import (
4 "encoding/json"
5 "testing"
6 "time"
7
8 "github.com/stretchr/testify/assert"
9 "sigs.k8s.io/yaml"
10
11 crds "github.com/emissary-ingress/emissary/v3/pkg/api/getambassador.io/v2"
12 )
13
14 func boolPtr(b bool) *bool {
15 return &b
16 }
17
18 func stringPtr(s string) *string {
19 return &s
20 }
21
22 func TestStringOrStringList(t *testing.T) {
23 t.Parallel()
24 type TestResource struct {
25 Field crds.StringOrStringList `json:"field,omitempty"`
26 }
27 type subtest struct {
28 inputYAML string
29 expectedStruct TestResource
30 expectedJSON string
31 expectedErr string
32 }
33 subtests := map[string]subtest{
34 "empty": {`{}`, TestResource{}, `{}`, ``},
35 "explicitEmpty": {`field:`, TestResource{}, `{}`, ``},
36 "explicitnull": {`field: null`, TestResource{}, `{}`, ``},
37 "explicitNull": {`field: Null`, TestResource{}, `{}`, ``},
38 "explicitNULL": {`field: NULL`, TestResource{}, `{}`, ``},
39 "explicitTilde": {`field: ~`, TestResource{}, `{}`, ``},
40 "single": {`field: "single"`, TestResource{crds.StringOrStringList{"single"}}, `{"field":["single"]}`, ``},
41 "singleEmpty": {`field: ""`, TestResource{crds.StringOrStringList{""}}, `{"field":[""]}`, ``},
42 "listSingle": {`field: ["single"]`, TestResource{crds.StringOrStringList{"single"}}, `{"field":["single"]}`, ``},
43 "listEmpty": {`field: []`, TestResource{crds.StringOrStringList{}}, `{}`, ``},
44 "double": {`field: ["first", "second"]`, TestResource{crds.StringOrStringList{"first", "second"}}, `{"field":["first","second"]}`, ``},
45 "number": {`field: 12`, TestResource{}, `{}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal number into Go struct field TestResource.field of type []string"},
46 }
47 for name, info := range subtests {
48 info := info
49 t.Run(name, func(t *testing.T) {
50 t.Parallel()
51 var parsed TestResource
52 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
53 if info.expectedErr == `` {
54 assert.NoError(t, err)
55 } else {
56 assert.EqualError(t, err, info.expectedErr)
57 }
58 assert.Equal(t, info.expectedStruct, parsed)
59 jsonbytes, err := json.Marshal(parsed)
60 assert.NoError(t, err)
61 assert.Equal(t, info.expectedJSON, string(jsonbytes))
62 })
63 }
64 }
65
66 func TestBoolOrString(t *testing.T) {
67 t.Parallel()
68 type TestResource struct {
69 Field crds.BoolOrString `json:"field,omitempty"`
70 }
71 type subtest struct {
72 inputYAML string
73 expectedStruct TestResource
74 expectedJSON string
75 expectedErr string
76 }
77 subtests := map[string]subtest{
78 "empty": {`{}`, TestResource{}, `{"field":null}`, ``},
79 "explicitEmpty": {`field:`, TestResource{}, `{"field":null}`, ``},
80 "explicitnull": {`field: null`, TestResource{}, `{"field":null}`, ``},
81 "explicitNull": {`field: Null`, TestResource{}, `{"field":null}`, ``},
82 "explicitNULL": {`field: NULL`, TestResource{}, `{"field":null}`, ``},
83 "explicitTilde": {`field: ~`, TestResource{}, `{"field":null}`, ``},
84 "true": {`field: true`, TestResource{crds.BoolOrString{Bool: boolPtr(true)}}, `{"field":true}`, ``},
85 "True": {`field: True`, TestResource{crds.BoolOrString{Bool: boolPtr(true)}}, `{"field":true}`, ``},
86 "TRUE": {`field: TRUE`, TestResource{crds.BoolOrString{Bool: boolPtr(true)}}, `{"field":true}`, ``},
87 "false": {`field: false`, TestResource{crds.BoolOrString{Bool: boolPtr(false)}}, `{"field":false}`, ``},
88 "False": {`field: False`, TestResource{crds.BoolOrString{Bool: boolPtr(false)}}, `{"field":false}`, ``},
89 "FALSE": {`field: FALSE`, TestResource{crds.BoolOrString{Bool: boolPtr(false)}}, `{"field":false}`, ``},
90 "strTrue": {`field: "true"`, TestResource{crds.BoolOrString{String: stringPtr("true")}}, `{"field":"true"}`, ``},
91 "strTRue": {`field: TRue`, TestResource{crds.BoolOrString{String: stringPtr("TRue")}}, `{"field":"TRue"}`, ``},
92 "strBare": {`field: bare`, TestResource{crds.BoolOrString{String: stringPtr("bare")}}, `{"field":"bare"}`, ``},
93 "number": {`field: 12`, TestResource{}, `{"field":null}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal number into Go struct field TestResource.field of type string"},
94 "invalid": {``, TestResource{crds.BoolOrString{Bool: boolPtr(true), String: stringPtr("foo")}}, ``, "json: error calling MarshalJSON for type v2.BoolOrString: invalid BoolOrString"},
95 }
96 for name, info := range subtests {
97 info := info
98 t.Run(name, func(t *testing.T) {
99 t.Parallel()
100 if info.inputYAML == `` {
101 jsonbytes, err := json.Marshal(info.expectedStruct)
102 assert.Equal(t, info.expectedJSON, string(jsonbytes))
103 assert.EqualError(t, err, info.expectedErr)
104 } else {
105 var parsed TestResource
106 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
107 if info.expectedErr == `` {
108 assert.NoError(t, err)
109 } else {
110 assert.EqualError(t, err, info.expectedErr)
111 }
112 assert.Equal(t, info.expectedStruct, parsed)
113 jsonbytes, err := json.Marshal(parsed)
114 assert.NoError(t, err)
115 assert.Equal(t, info.expectedJSON, string(jsonbytes))
116 }
117 })
118 }
119 }
120
121 func TestBoolOrStringPtr(t *testing.T) {
122 t.Parallel()
123 type TestResource struct {
124 Field *crds.BoolOrString `json:"field,omitempty"`
125 }
126 type subtest struct {
127 inputYAML string
128 expectedStruct TestResource
129 expectedJSON string
130 expectedErr string
131 }
132 subtests := map[string]subtest{
133 "empty": {`{}`, TestResource{}, `{}`, ``},
134 "explicitEmpty": {`field:`, TestResource{}, `{}`, ``},
135 "explicitnull": {`field: null`, TestResource{}, `{}`, ``},
136 "explicitNull": {`field: Null`, TestResource{}, `{}`, ``},
137 "explicitNULL": {`field: NULL`, TestResource{}, `{}`, ``},
138 "explicitTilde": {`field: ~`, TestResource{}, `{}`, ``},
139 "true": {`field: true`, TestResource{&crds.BoolOrString{Bool: boolPtr(true)}}, `{"field":true}`, ``},
140 "True": {`field: True`, TestResource{&crds.BoolOrString{Bool: boolPtr(true)}}, `{"field":true}`, ``},
141 "TRUE": {`field: TRUE`, TestResource{&crds.BoolOrString{Bool: boolPtr(true)}}, `{"field":true}`, ``},
142 "false": {`field: false`, TestResource{&crds.BoolOrString{Bool: boolPtr(false)}}, `{"field":false}`, ``},
143 "False": {`field: False`, TestResource{&crds.BoolOrString{Bool: boolPtr(false)}}, `{"field":false}`, ``},
144 "FALSE": {`field: FALSE`, TestResource{&crds.BoolOrString{Bool: boolPtr(false)}}, `{"field":false}`, ``},
145 "strTrue": {`field: "true"`, TestResource{&crds.BoolOrString{String: stringPtr("true")}}, `{"field":"true"}`, ``},
146 "strTRue": {`field: TRue`, TestResource{&crds.BoolOrString{String: stringPtr("TRue")}}, `{"field":"TRue"}`, ``},
147 "strBare": {`field: bare`, TestResource{&crds.BoolOrString{String: stringPtr("bare")}}, `{"field":"bare"}`, ``},
148 "number": {`field: 12`, TestResource{&crds.BoolOrString{}}, `{"field":null}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal number into Go struct field TestResource.field of type string"},
149 }
150 for name, info := range subtests {
151 info := info
152 t.Run(name, func(t *testing.T) {
153 t.Parallel()
154 var parsed TestResource
155 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
156 if info.expectedErr == `` {
157 assert.NoError(t, err)
158 } else {
159 assert.EqualError(t, err, info.expectedErr)
160 }
161 assert.Equal(t, info.expectedStruct, parsed)
162 jsonbytes, err := json.Marshal(parsed)
163 assert.NoError(t, err)
164 assert.Equal(t, info.expectedJSON, string(jsonbytes))
165 })
166 }
167 }
168
169 func TestMillisecondDuration(t *testing.T) {
170 t.Parallel()
171 type TestResource struct {
172 Field crds.MillisecondDuration `json:"field,omitempty"`
173 }
174 type subtest struct {
175 inputYAML string
176 expectedStruct TestResource
177 expectedJSON string
178 expectedErr string
179 }
180 subtests := map[string]subtest{
181 "empty": {`{}`, TestResource{}, `{"field":0}`, ``},
182 "explicitEmpty": {`field:`, TestResource{}, `{"field":0}`, ``},
183 "explicitnull": {`field: null`, TestResource{}, `{"field":0}`, ``},
184 "explicitNull": {`field: Null`, TestResource{}, `{"field":0}`, ``},
185 "explicitNULL": {`field: NULL`, TestResource{}, `{"field":0}`, ``},
186 "explicitTilde": {`field: ~`, TestResource{}, `{"field":0}`, ``},
187 "3000": {`field: 3000`, TestResource{crds.MillisecondDuration{3 * time.Second}}, `{"field":3000}`, ``},
188 "overflow32": {`field: 4320000000`, TestResource{crds.MillisecondDuration{50 * 24 * time.Hour}}, `{"field":4320000000}`, ``},
189 "string": {`field: "30s"`, TestResource{crds.MillisecondDuration{0}}, `{"field":0}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field TestResource.field of type int64"},
190 }
191 for name, info := range subtests {
192 info := info
193 t.Run(name, func(t *testing.T) {
194 t.Parallel()
195 var parsed TestResource
196 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
197 if info.expectedErr == `` {
198 assert.NoError(t, err)
199 } else {
200 assert.EqualError(t, err, info.expectedErr)
201 }
202 assert.Equal(t, info.expectedStruct, parsed)
203 jsonbytes, err := json.Marshal(parsed)
204 assert.NoError(t, err)
205 assert.Equal(t, info.expectedJSON, string(jsonbytes))
206 })
207 }
208 }
209
210 func TestMillisecondDurationPtr(t *testing.T) {
211 t.Parallel()
212 type TestResource struct {
213 Field *crds.MillisecondDuration `json:"field,omitempty"`
214 }
215 type subtest struct {
216 inputYAML string
217 expectedStruct TestResource
218 expectedJSON string
219 expectedErr string
220 }
221 subtests := map[string]subtest{
222 "empty": {`{}`, TestResource{}, `{}`, ``},
223 "explicitEmpty": {`field:`, TestResource{}, `{}`, ``},
224 "explicitnull": {`field: null`, TestResource{}, `{}`, ``},
225 "explicitNull": {`field: Null`, TestResource{}, `{}`, ``},
226 "explicitNULL": {`field: NULL`, TestResource{}, `{}`, ``},
227 "explicitTilde": {`field: ~`, TestResource{}, `{}`, ``},
228 "3000": {`field: 3000`, TestResource{&crds.MillisecondDuration{3 * time.Second}}, `{"field":3000}`, ``},
229 "overflow32": {`field: 4320000000`, TestResource{&crds.MillisecondDuration{50 * 24 * time.Hour}}, `{"field":4320000000}`, ``},
230 "string": {`field: "30s"`, TestResource{&crds.MillisecondDuration{0}}, `{"field":0}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field TestResource.field of type int64"},
231 }
232 for name, info := range subtests {
233 info := info
234 t.Run(name, func(t *testing.T) {
235 t.Parallel()
236 var parsed TestResource
237 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
238 if info.expectedErr == `` {
239 assert.NoError(t, err)
240 } else {
241 assert.EqualError(t, err, info.expectedErr)
242 }
243 assert.Equal(t, info.expectedStruct, parsed)
244 jsonbytes, err := json.Marshal(parsed)
245 assert.NoError(t, err)
246 assert.Equal(t, info.expectedJSON, string(jsonbytes))
247 })
248 }
249 }
250
251 func TestUntypedDict(t *testing.T) {
252 t.Parallel()
253 type TestResource struct {
254 Field crds.UntypedDict `json:"field,omitempty"`
255 }
256 type subtest struct {
257 inputYAML string
258 expectedStruct TestResource
259 expectedJSON string
260 expectedErr string
261 }
262 subtests := map[string]subtest{
263 "empty": {`{}`, TestResource{}, `{"field":null}`, ``},
264 "explicitEmpty": {`field:`, TestResource{}, `{"field":null}`, ``},
265 "explicitnull": {`field: null`, TestResource{}, `{"field":null}`, ``},
266 "explicitNull": {`field: Null`, TestResource{}, `{"field":null}`, ``},
267 "explicitNULL": {`field: NULL`, TestResource{}, `{"field":null}`, ``},
268 "explicitTilde": {`field: ~`, TestResource{}, `{"field":null}`, ``},
269 "basic": {`field: {foo: "bar"}`, TestResource{crds.UntypedDict{map[string]json.RawMessage{"foo": json.RawMessage(`"bar"`)}}}, `{"field":{"foo":"bar"}}`, ``},
270 "string": {`field: "str"`, TestResource{}, `{"field":null}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field TestResource.field of type map[string]json.RawMessage"},
271 "badkey": {`
272 badkey: &anchor
273 baz: qux
274 field: { *anchor: "bar"}`, TestResource{}, `{"field":null}`, "error converting YAML to JSON: yaml: invalid map key: map[interface {}]interface {}{\"baz\":\"qux\"}"},
275 }
276 for name, info := range subtests {
277 info := info
278 t.Run(name, func(t *testing.T) {
279 t.Parallel()
280 var parsed TestResource
281 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
282 if info.expectedErr == `` {
283 assert.NoError(t, err)
284 } else {
285 assert.EqualError(t, err, info.expectedErr)
286 }
287 assert.Equal(t, info.expectedStruct, parsed)
288 jsonbytes, err := json.Marshal(parsed)
289 assert.NoError(t, err)
290 assert.Equal(t, info.expectedJSON, string(jsonbytes))
291 })
292 }
293 }
294
295 func TestUntypedDictPtr(t *testing.T) {
296 t.Parallel()
297 type TestResource struct {
298 Field *crds.UntypedDict `json:"field,omitempty"`
299 }
300 type subtest struct {
301 inputYAML string
302 expectedStruct TestResource
303 expectedJSON string
304 expectedErr string
305 }
306 subtests := map[string]subtest{
307 "empty": {`{}`, TestResource{}, `{}`, ``},
308 "explicitEmpty": {`field:`, TestResource{}, `{}`, ``},
309 "explicitnull": {`field: null`, TestResource{}, `{}`, ``},
310 "explicitNull": {`field: Null`, TestResource{}, `{}`, ``},
311 "explicitNULL": {`field: NULL`, TestResource{}, `{}`, ``},
312 "explicitTilde": {`field: ~`, TestResource{}, `{}`, ``},
313 "basic": {`field: {foo: "bar"}`, TestResource{&crds.UntypedDict{map[string]json.RawMessage{"foo": json.RawMessage(`"bar"`)}}}, `{"field":{"foo":"bar"}}`, ``},
314 "string": {`field: "str"`, TestResource{&crds.UntypedDict{}}, `{"field":null}`, "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field TestResource.field of type map[string]json.RawMessage"},
315 "badkey": {`
316 badkey: &anchor
317 baz: qux
318 field: { *anchor: "bar"}`, TestResource{}, `{}`, "error converting YAML to JSON: yaml: invalid map key: map[interface {}]interface {}{\"baz\":\"qux\"}"},
319 }
320 for name, info := range subtests {
321 info := info
322 t.Run(name, func(t *testing.T) {
323 t.Parallel()
324 var parsed TestResource
325 err := yaml.Unmarshal([]byte(info.inputYAML), &parsed)
326 if info.expectedErr == `` {
327 assert.NoError(t, err)
328 } else {
329 assert.EqualError(t, err, info.expectedErr)
330 }
331 assert.Equal(t, info.expectedStruct, parsed)
332 jsonbytes, err := json.Marshal(parsed)
333 assert.NoError(t, err)
334 assert.Equal(t, info.expectedJSON, string(jsonbytes))
335 })
336 }
337 }
338
View as plain text