1
16
17 package generators
18
19 import (
20 "reflect"
21 "strings"
22 "testing"
23
24 "k8s.io/gengo/v2/types"
25 "k8s.io/kube-openapi/pkg/util/sets"
26 )
27
28 func TestSingleTagExtension(t *testing.T) {
29
30
31 var tests = []struct {
32 comments []string
33 extensionTag string
34 extensionName string
35 extensionValues []string
36 }{
37 {
38 comments: []string{"+patchMergeKey=name"},
39 extensionTag: "patchMergeKey",
40 extensionName: "x-kubernetes-patch-merge-key",
41 extensionValues: []string{"name"},
42 },
43 {
44 comments: []string{"+patchStrategy=merge"},
45 extensionTag: "patchStrategy",
46 extensionName: "x-kubernetes-patch-strategy",
47 extensionValues: []string{"merge"},
48 },
49 {
50 comments: []string{"+listType=atomic"},
51 extensionTag: "listType",
52 extensionName: "x-kubernetes-list-type",
53 extensionValues: []string{"atomic"},
54 },
55 {
56 comments: []string{"+listMapKey=port"},
57 extensionTag: "listMapKey",
58 extensionName: "x-kubernetes-list-map-keys",
59 extensionValues: []string{"port"},
60 },
61 {
62 comments: []string{"+mapType=granular"},
63 extensionTag: "mapType",
64 extensionName: "x-kubernetes-map-type",
65 extensionValues: []string{"granular"},
66 },
67 {
68 comments: []string{"+k8s:openapi-gen=x-kubernetes-member-tag:member_test"},
69 extensionTag: "k8s:openapi-gen",
70 extensionName: "x-kubernetes-member-tag",
71 extensionValues: []string{"member_test"},
72 },
73 {
74 comments: []string{"+k8s:openapi-gen=x-kubernetes-member-tag:member_test:member_test2"},
75 extensionTag: "k8s:openapi-gen",
76 extensionName: "x-kubernetes-member-tag",
77 extensionValues: []string{"member_test:member_test2"},
78 },
79 {
80
81 comments: []string{
82 "+k8s:openapi-gen=x-kubernetes-no-value",
83 "+k8s:openapi-gen=x-kubernetes-member-success:success",
84 "+k8s:openapi-gen=x-kubernetes-wrong-separator;error",
85 },
86 extensionTag: "k8s:openapi-gen",
87 extensionName: "x-kubernetes-member-success",
88 extensionValues: []string{"success"},
89 },
90 }
91 for _, test := range tests {
92 extensions, _ := parseExtensions(test.comments)
93 actual := extensions[0]
94 if actual.idlTag != test.extensionTag {
95 t.Errorf("Extension Tag: expected (%s), actual (%s)\n", test.extensionTag, actual.idlTag)
96 }
97 if actual.xName != test.extensionName {
98 t.Errorf("Extension Name: expected (%s), actual (%s)\n", test.extensionName, actual.xName)
99 }
100 if !reflect.DeepEqual(actual.values, test.extensionValues) {
101 t.Errorf("Extension Values: expected (%s), actual (%s)\n", test.extensionValues, actual.values)
102 }
103 if actual.hasMultipleValues() {
104 t.Errorf("%s: hasMultipleValues() should be false\n", actual.xName)
105 }
106 }
107
108 }
109
110 func TestMultipleTagExtensions(t *testing.T) {
111
112 var tests = []struct {
113 comments []string
114 extensionTag string
115 extensionName string
116 extensionValues []string
117 }{
118 {
119 comments: []string{
120 "+listMapKey=port",
121 "+listMapKey=protocol",
122 },
123 extensionTag: "listMapKey",
124 extensionName: "x-kubernetes-list-map-keys",
125 extensionValues: []string{"port", "protocol"},
126 },
127 }
128 for _, test := range tests {
129 extensions, errors := parseExtensions(test.comments)
130 if len(errors) > 0 {
131 t.Errorf("Unexpected errors: %v\n", errors)
132 }
133 actual := extensions[0]
134 if actual.idlTag != test.extensionTag {
135 t.Errorf("Extension Tag: expected (%s), actual (%s)\n", test.extensionTag, actual.idlTag)
136 }
137 if actual.xName != test.extensionName {
138 t.Errorf("Extension Name: expected (%s), actual (%s)\n", test.extensionName, actual.xName)
139 }
140 if !reflect.DeepEqual(actual.values, test.extensionValues) {
141 t.Errorf("Extension Values: expected (%s), actual (%s)\n", test.extensionValues, actual.values)
142 }
143 if !actual.hasMultipleValues() {
144 t.Errorf("%s: hasMultipleValues() should be true\n", actual.xName)
145 }
146 }
147
148 }
149
150 func TestExtensionParseErrors(t *testing.T) {
151
152 var tests = []struct {
153 comments []string
154 errorMessage string
155 }{
156 {
157
158 comments: []string{
159 "+k8s:openapi-gen=x-kubernetes-no-value",
160 },
161 errorMessage: "x-kubernetes-no-value",
162 },
163 {
164
165 comments: []string{
166 "+k8s:openapi-gen=x-kubernetes-wrong-separator;error",
167 },
168 errorMessage: "x-kubernetes-wrong-separator;error",
169 },
170 }
171
172 for _, test := range tests {
173 _, errors := parseExtensions(test.comments)
174 if len(errors) == 0 {
175 t.Errorf("Expected errors while parsing: %v\n", test.comments)
176 }
177 error := errors[0]
178 if !strings.Contains(error.Error(), test.errorMessage) {
179 t.Errorf("Error (%v) should contain substring (%s)\n", error, test.errorMessage)
180 }
181 }
182 }
183
184 func TestExtensionAllowedValues(t *testing.T) {
185
186 var methodTests = []struct {
187 e extension
188 allowedValues sets.String
189 }{
190 {
191 e: extension{
192 idlTag: "patchStrategy",
193 },
194 allowedValues: sets.NewString("merge", "retainKeys"),
195 },
196 {
197 e: extension{
198 idlTag: "patchMergeKey",
199 },
200 allowedValues: nil,
201 },
202 {
203 e: extension{
204 idlTag: "listType",
205 },
206 allowedValues: sets.NewString("atomic", "set", "map"),
207 },
208 {
209 e: extension{
210 idlTag: "listMapKey",
211 },
212 allowedValues: nil,
213 },
214 {
215 e: extension{
216 idlTag: "mapType",
217 },
218 allowedValues: sets.NewString("atomic", "granular"),
219 },
220 {
221 e: extension{
222 idlTag: "structType",
223 },
224 allowedValues: sets.NewString("atomic", "granular"),
225 },
226 {
227 e: extension{
228 idlTag: "k8s:openapi-gen",
229 },
230 allowedValues: nil,
231 },
232 }
233 for _, test := range methodTests {
234 if test.allowedValues != nil {
235 if !test.e.hasAllowedValues() {
236 t.Errorf("hasAllowedValues() expected (true), but received: false")
237 }
238 if !reflect.DeepEqual(test.allowedValues, test.e.allowedValues()) {
239 t.Errorf("allowedValues() expected (%v), but received: %v",
240 test.allowedValues, test.e.allowedValues())
241 }
242 }
243 if test.allowedValues == nil && test.e.hasAllowedValues() {
244 t.Errorf("hasAllowedValues() expected (false), but received: true")
245 }
246 }
247
248 var successTests = []struct {
249 e extension
250 }{
251 {
252 e: extension{
253 idlTag: "patchStrategy",
254 xName: "x-kubernetes-patch-strategy",
255 values: []string{"merge"},
256 },
257 },
258 {
259
260 e: extension{
261 idlTag: "patchStrategy",
262 xName: "x-kubernetes-patch-strategy",
263 values: []string{"merge", "retainKeys"},
264 },
265 },
266 {
267 e: extension{
268 idlTag: "patchMergeKey",
269 xName: "x-kubernetes-patch-merge-key",
270 values: []string{"key1"},
271 },
272 },
273 {
274 e: extension{
275 idlTag: "listType",
276 xName: "x-kubernetes-list-type",
277 values: []string{"atomic"},
278 },
279 },
280 {
281 e: extension{
282 idlTag: "mapType",
283 xName: "x-kubernetes-map-type",
284 values: []string{"atomic"},
285 },
286 },
287 {
288 e: extension{
289 idlTag: "structType",
290 xName: "x-kubernetes-map-type",
291 values: []string{"granular"},
292 },
293 },
294 }
295 for _, test := range successTests {
296 actualErr := test.e.validateAllowedValues()
297 if actualErr != nil {
298 t.Errorf("Expected no error for (%v), but received: %v\n", test.e, actualErr)
299 }
300 }
301
302 var failureTests = []struct {
303 e extension
304 }{
305 {
306
307 e: extension{
308 idlTag: "patchStrategy",
309 xName: "x-kubernetes-patch-strategy",
310 values: []string{"disallowed", "merge"},
311 },
312 },
313 {
314 e: extension{
315 idlTag: "patchStrategy",
316 xName: "x-kubernetes-patch-strategy",
317 values: []string{"foo"},
318 },
319 },
320 {
321 e: extension{
322 idlTag: "listType",
323 xName: "x-kubernetes-list-type",
324 values: []string{"not-allowed"},
325 },
326 },
327 {
328 e: extension{
329 idlTag: "mapType",
330 xName: "x-kubernetes-map-type",
331 values: []string{"something-pretty-wrong"},
332 },
333 },
334 {
335 e: extension{
336 idlTag: "structType",
337 xName: "x-kubernetes-map-type",
338 values: []string{"not-quite-right"},
339 },
340 },
341 }
342 for _, test := range failureTests {
343 actualErr := test.e.validateAllowedValues()
344 if actualErr == nil {
345 t.Errorf("Expected error, but received none: %v\n", test.e)
346 }
347 }
348
349 }
350
351 func TestExtensionKind(t *testing.T) {
352
353 var methodTests = []struct {
354 e extension
355 kind types.Kind
356 }{
357 {
358 e: extension{
359 idlTag: "patchStrategy",
360 },
361 kind: types.Slice,
362 },
363 {
364 e: extension{
365 idlTag: "patchMergeKey",
366 },
367 kind: types.Slice,
368 },
369 {
370 e: extension{
371 idlTag: "listType",
372 },
373 kind: types.Slice,
374 },
375 {
376 e: extension{
377 idlTag: "mapType",
378 },
379 kind: types.Map,
380 },
381 {
382 e: extension{
383 idlTag: "structType",
384 },
385 kind: types.Struct,
386 },
387 {
388 e: extension{
389 idlTag: "listMapKey",
390 },
391 kind: types.Slice,
392 },
393 {
394 e: extension{
395 idlTag: "k8s:openapi-gen",
396 },
397 kind: "",
398 },
399 }
400 for _, test := range methodTests {
401 if len(test.kind) > 0 {
402 if !test.e.hasKind() {
403 t.Errorf("%v: hasKind() expected (true), but received: false", test.e)
404 }
405 if test.kind != test.e.kind() {
406 t.Errorf("%v: kind() expected (%v), but received: %v", test.e, test.kind, test.e.kind())
407 }
408 } else {
409 if test.e.hasKind() {
410 t.Errorf("%v: hasKind() expected (false), but received: true", test.e)
411 }
412 }
413 }
414 }
415
416 func TestValidateMemberExtensions(t *testing.T) {
417
418 patchStrategyExtension := extension{
419 idlTag: "patchStrategy",
420 xName: "x-kubernetes-patch-strategy",
421 values: []string{"merge"},
422 }
423 patchMergeKeyExtension := extension{
424 idlTag: "patchMergeKey",
425 xName: "x-kubernetes-patch-merge-key",
426 values: []string{"key1", "key2"},
427 }
428 listTypeExtension := extension{
429 idlTag: "listType",
430 xName: "x-kubernetes-list-type",
431 values: []string{"atomic"},
432 }
433 listMapKeysExtension := extension{
434 idlTag: "listMapKey",
435 xName: "x-kubernetes-map-keys",
436 values: []string{"key1"},
437 }
438 genExtension := extension{
439 idlTag: "k8s:openapi-gen",
440 xName: "x-kubernetes-member-type",
441 values: []string{"value1"},
442 }
443
444 sliceField := types.Member{
445 Name: "Containers",
446 Type: &types.Type{
447 Kind: types.Slice,
448 },
449 }
450 mapField := types.Member{
451 Name: "Containers",
452 Type: &types.Type{
453 Kind: types.Map,
454 },
455 }
456
457 var successTests = []struct {
458 extensions []extension
459 member types.Member
460 }{
461
462 {
463 extensions: []extension{patchStrategyExtension},
464 member: sliceField,
465 },
466
467 {
468 extensions: []extension{
469 patchMergeKeyExtension,
470 listTypeExtension,
471 listMapKeysExtension,
472 genExtension,
473 },
474 member: sliceField,
475 },
476 }
477 for _, test := range successTests {
478 errors := validateMemberExtensions(test.extensions, &test.member)
479 if len(errors) > 0 {
480 t.Errorf("validateMemberExtensions: %v should have produced no errors. Errors: %v",
481 test.extensions, errors)
482 }
483 }
484
485 var failureTests = []struct {
486 extensions []extension
487 member types.Member
488 }{
489
490 {
491 extensions: []extension{patchStrategyExtension},
492 member: mapField,
493 },
494
495 {
496 extensions: []extension{
497 patchMergeKeyExtension,
498 listTypeExtension,
499 listMapKeysExtension,
500 },
501 member: mapField,
502 },
503 }
504 for _, test := range failureTests {
505 errors := validateMemberExtensions(test.extensions, &test.member)
506 if len(errors) != len(test.extensions) {
507 t.Errorf("validateMemberExtensions: %v should have produced all errors. Errors: %v",
508 test.extensions, errors)
509 }
510 }
511
512 }
513
View as plain text