1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package crdutil_test
16
17 import (
18 "reflect"
19 "testing"
20
21 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/util/crdutil"
22
23 "github.com/google/go-cmp/cmp"
24 apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
25 )
26
27 func TestGetSchemaForFieldUnderObjectOrArray(t *testing.T) {
28 t.Parallel()
29 tests := []struct {
30 name string
31 field string
32 parent *apiextensions.JSONSchemaProps
33 expectedSchema *apiextensions.JSONSchemaProps
34 hasError bool
35 }{
36 {
37 name: "get schema for field under object",
38 field: "test",
39 parent: &apiextensions.JSONSchemaProps{
40 Properties: map[string]apiextensions.JSONSchemaProps{
41 "test": {
42 Description: "field under object",
43 Type: "string",
44 },
45 },
46 Type: "object",
47 },
48 expectedSchema: &apiextensions.JSONSchemaProps{
49 Description: "field under object",
50 Type: "string",
51 },
52 },
53 {
54 name: "get schema for field under map",
55 field: "test",
56 parent: &apiextensions.JSONSchemaProps{
57 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
58 Schema: &apiextensions.JSONSchemaProps{
59 Properties: map[string]apiextensions.JSONSchemaProps{
60 "test": {
61 Description: "field under map",
62 Type: "string",
63 },
64 },
65 Type: "object",
66 },
67 },
68 Type: "object",
69 },
70 expectedSchema: &apiextensions.JSONSchemaProps{
71 Description: "field under map",
72 Type: "string",
73 },
74 },
75 {
76 name: "get schema for field under array",
77 field: "test",
78 parent: &apiextensions.JSONSchemaProps{
79 Items: &apiextensions.JSONSchemaPropsOrArray{
80 Schema: &apiextensions.JSONSchemaProps{
81 Properties: map[string]apiextensions.JSONSchemaProps{
82 "test": {
83 Description: "field under array",
84 Type: "string",
85 },
86 },
87 Type: "object",
88 },
89 },
90 Type: "array",
91 },
92 expectedSchema: &apiextensions.JSONSchemaProps{
93 Description: "field under array",
94 Type: "string",
95 },
96 },
97 {
98 name: "get empty schema when field doesn't exist",
99 field: "test",
100 parent: &apiextensions.JSONSchemaProps{
101 Properties: map[string]apiextensions.JSONSchemaProps{
102 "otherField": {
103 Type: "string",
104 },
105 },
106 Type: "object",
107 },
108 expectedSchema: nil,
109 },
110 {
111 name: "can't get schema for field under string field",
112 field: "test",
113 parent: &apiextensions.JSONSchemaProps{
114 Type: "string",
115 },
116 hasError: true,
117 },
118 {
119 name: "can't get schema for incorrect object schema",
120 field: "test",
121 parent: &apiextensions.JSONSchemaProps{
122 Description: "an object field without properties or additionalProperties",
123 Type: "object",
124 },
125 hasError: true,
126 },
127 }
128
129 for _, tc := range tests {
130 t.Run(tc.name, func(t *testing.T) {
131 schema, _, err := crdutil.GetSchemaForFieldUnderObjectOrArray(tc.field, tc.parent)
132 if err != nil {
133 if !tc.hasError {
134 t.Fatalf("got an error, but want no error: %v", err)
135 }
136 return
137 }
138 if got, want := schema, tc.expectedSchema; !reflect.DeepEqual(got, want) {
139 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
140 }
141 })
142 }
143 }
144
145 func TestSetSchemaForFieldUnderObjectOrArray(t *testing.T) {
146 t.Parallel()
147 tests := []struct {
148 name string
149 field string
150 parent *apiextensions.JSONSchemaProps
151 fieldSchema *apiextensions.JSONSchemaProps
152 expectedSchema *apiextensions.JSONSchemaProps
153 hasError bool
154 }{
155 {
156 name: "set schema for non-existent field under object",
157 field: "test",
158 parent: &apiextensions.JSONSchemaProps{
159 Properties: map[string]apiextensions.JSONSchemaProps{
160 "otherField": {
161 Type: "bool",
162 },
163 },
164 Type: "object",
165 },
166 fieldSchema: &apiextensions.JSONSchemaProps{
167 Description: "field under object",
168 Type: "string",
169 },
170 expectedSchema: &apiextensions.JSONSchemaProps{
171 Properties: map[string]apiextensions.JSONSchemaProps{
172 "otherField": {
173 Type: "bool",
174 },
175 "test": {
176 Description: "field under object",
177 Type: "string",
178 },
179 },
180 Type: "object",
181 },
182 },
183 {
184 name: "set schema for non-existent field under map",
185 field: "test",
186 parent: &apiextensions.JSONSchemaProps{
187 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
188 Schema: &apiextensions.JSONSchemaProps{
189 Properties: map[string]apiextensions.JSONSchemaProps{
190 "otherField": {
191 Type: "bool",
192 },
193 },
194 Type: "object",
195 },
196 },
197 Type: "object",
198 },
199 fieldSchema: &apiextensions.JSONSchemaProps{
200 Description: "field under map",
201 Type: "string",
202 },
203 expectedSchema: &apiextensions.JSONSchemaProps{
204 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
205 Schema: &apiextensions.JSONSchemaProps{
206 Properties: map[string]apiextensions.JSONSchemaProps{
207 "test": {
208 Description: "field under map",
209 Type: "string",
210 },
211 "otherField": {
212 Type: "bool",
213 },
214 },
215 Type: "object",
216 },
217 },
218 Type: "object",
219 },
220 },
221 {
222 name: "set schema for non-existent field under array",
223 field: "test",
224 parent: &apiextensions.JSONSchemaProps{
225 Items: &apiextensions.JSONSchemaPropsOrArray{
226 Schema: &apiextensions.JSONSchemaProps{
227 Properties: map[string]apiextensions.JSONSchemaProps{
228 "otherField": {
229 Type: "bool",
230 },
231 },
232 Type: "object",
233 },
234 },
235 Type: "array",
236 },
237 fieldSchema: &apiextensions.JSONSchemaProps{
238 Description: "field under array",
239 Type: "string",
240 },
241 expectedSchema: &apiextensions.JSONSchemaProps{
242 Items: &apiextensions.JSONSchemaPropsOrArray{
243 Schema: &apiextensions.JSONSchemaProps{
244 Properties: map[string]apiextensions.JSONSchemaProps{
245 "test": {
246 Description: "field under array",
247 Type: "string",
248 },
249 "otherField": {
250 Type: "bool",
251 },
252 },
253 Type: "object",
254 },
255 },
256 Type: "array",
257 },
258 },
259 {
260 name: "set schema for existing field under object",
261 field: "test",
262 parent: &apiextensions.JSONSchemaProps{
263 Properties: map[string]apiextensions.JSONSchemaProps{
264 "otherField": {
265 Type: "bool",
266 },
267 "test": {
268 Description: "old description",
269 Type: "bool",
270 },
271 },
272 Type: "object",
273 },
274 fieldSchema: &apiextensions.JSONSchemaProps{
275 Description: "field under object",
276 Type: "string",
277 },
278 expectedSchema: &apiextensions.JSONSchemaProps{
279 Properties: map[string]apiextensions.JSONSchemaProps{
280 "otherField": {
281 Type: "bool",
282 },
283 "test": {
284 Description: "field under object",
285 Type: "string",
286 },
287 },
288 Type: "object",
289 },
290 },
291 {
292 name: "can't set schema under a string field",
293 field: "test",
294 parent: &apiextensions.JSONSchemaProps{
295 Type: "string",
296 },
297 fieldSchema: &apiextensions.JSONSchemaProps{
298 Description: "test schema",
299 Type: "string",
300 },
301 hasError: true,
302 },
303 {
304 name: "can't set schema for incorrect object schema",
305 field: "test",
306 parent: &apiextensions.JSONSchemaProps{
307 Type: "object",
308 },
309 fieldSchema: &apiextensions.JSONSchemaProps{
310 Description: "test schema",
311 Type: "string",
312 },
313 hasError: true,
314 },
315 }
316
317 for _, tc := range tests {
318 t.Run(tc.name, func(t *testing.T) {
319 if err := crdutil.SetSchemaForFieldUnderObjectOrArray(tc.field, tc.parent, tc.fieldSchema); err != nil {
320 if !tc.hasError {
321 t.Fatalf("got an error, but want no error: %v", err)
322 }
323 return
324 }
325 if got, want := tc.parent, tc.expectedSchema; !reflect.DeepEqual(got, want) {
326 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
327 }
328 })
329 }
330 }
331
332 func TestGetRequiredRuleForObjectOrArray(t *testing.T) {
333 t.Parallel()
334 tests := []struct {
335 name string
336 schema *apiextensions.JSONSchemaProps
337 expectedRule []string
338 hasError bool
339 }{
340 {
341 name: "get required rule under object",
342 schema: &apiextensions.JSONSchemaProps{
343 Properties: map[string]apiextensions.JSONSchemaProps{
344 "test": {
345 Description: "field under object",
346 Type: "string",
347 },
348 },
349 Type: "object",
350 Required: []string{"requiredField"},
351 },
352 expectedRule: []string{"requiredField"},
353 },
354 {
355 name: "get required rule under map",
356 schema: &apiextensions.JSONSchemaProps{
357 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
358 Schema: &apiextensions.JSONSchemaProps{
359 Properties: map[string]apiextensions.JSONSchemaProps{
360 "test": {
361 Description: "field under map",
362 Type: "string",
363 },
364 },
365 Type: "object",
366 Required: []string{"requiredField"},
367 },
368 },
369 Type: "object",
370 },
371 expectedRule: []string{"requiredField"},
372 },
373 {
374 name: "get required rule under array",
375 schema: &apiextensions.JSONSchemaProps{
376 Items: &apiextensions.JSONSchemaPropsOrArray{
377 Schema: &apiextensions.JSONSchemaProps{
378 Properties: map[string]apiextensions.JSONSchemaProps{
379 "test": {
380 Description: "field under array",
381 Type: "string",
382 },
383 },
384 Type: "object",
385 Required: []string{"requiredField"},
386 },
387 },
388 Type: "array",
389 },
390 expectedRule: []string{"requiredField"},
391 },
392 {
393 name: "can't get rule for field under string field",
394 schema: &apiextensions.JSONSchemaProps{
395 Type: "string",
396 Required: []string{"nonretrievable"},
397 },
398 hasError: true,
399 },
400 {
401 name: "can't get rule for incorrect object schema",
402 schema: &apiextensions.JSONSchemaProps{
403 Description: "an object field without properties or additionalProperties",
404 Type: "object",
405 Required: []string{"nonretrievable"},
406 },
407 hasError: true,
408 },
409 }
410
411 for _, tc := range tests {
412 t.Run(tc.name, func(t *testing.T) {
413 rule, err := crdutil.GetRequiredRuleForObjectOrArray(tc.schema)
414 if err != nil {
415 if !tc.hasError {
416 t.Fatalf("got an error, but want no error: %v", err)
417 }
418 return
419 }
420 if got, want := rule, tc.expectedRule; !reflect.DeepEqual(got, want) {
421 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
422 }
423 })
424 }
425 }
426
427 func TestSetRequiredRuleForObjectOrArray(t *testing.T) {
428 t.Parallel()
429 tests := []struct {
430 name string
431 schema *apiextensions.JSONSchemaProps
432 rule []string
433 expectedSchema *apiextensions.JSONSchemaProps
434 hasError bool
435 }{
436 {
437 name: "set required rule under object",
438 schema: &apiextensions.JSONSchemaProps{
439 Properties: map[string]apiextensions.JSONSchemaProps{
440 "otherField": {
441 Type: "bool",
442 },
443 },
444 Type: "object",
445 },
446 rule: []string{"requiredField"},
447 expectedSchema: &apiextensions.JSONSchemaProps{
448 Properties: map[string]apiextensions.JSONSchemaProps{
449 "otherField": {
450 Type: "bool",
451 },
452 },
453 Type: "object",
454 Required: []string{"requiredField"},
455 },
456 },
457 {
458 name: "set required rule under map",
459 schema: &apiextensions.JSONSchemaProps{
460 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
461 Schema: &apiextensions.JSONSchemaProps{
462 Properties: map[string]apiextensions.JSONSchemaProps{
463 "otherField": {
464 Type: "bool",
465 },
466 },
467 Type: "object",
468 },
469 },
470 Type: "object",
471 },
472 rule: []string{"requiredField"},
473 expectedSchema: &apiextensions.JSONSchemaProps{
474 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
475 Schema: &apiextensions.JSONSchemaProps{
476 Properties: map[string]apiextensions.JSONSchemaProps{
477 "otherField": {
478 Type: "bool",
479 },
480 },
481 Type: "object",
482 Required: []string{"requiredField"},
483 },
484 },
485 Type: "object",
486 },
487 },
488 {
489 name: "set required rule under array",
490 schema: &apiextensions.JSONSchemaProps{
491 Items: &apiextensions.JSONSchemaPropsOrArray{
492 Schema: &apiextensions.JSONSchemaProps{
493 Properties: map[string]apiextensions.JSONSchemaProps{
494 "otherField": {
495 Type: "bool",
496 },
497 },
498 Type: "object",
499 },
500 },
501 Type: "array",
502 },
503 rule: []string{"requiredField"},
504 expectedSchema: &apiextensions.JSONSchemaProps{
505 Items: &apiextensions.JSONSchemaPropsOrArray{
506 Schema: &apiextensions.JSONSchemaProps{
507 Properties: map[string]apiextensions.JSONSchemaProps{
508 "otherField": {
509 Type: "bool",
510 },
511 },
512 Type: "object",
513 Required: []string{"requiredField"},
514 },
515 },
516 Type: "array",
517 },
518 },
519 {
520 name: "can't set rulee under a string field",
521 schema: &apiextensions.JSONSchemaProps{
522 Type: "string",
523 },
524 rule: []string{"unsettable"},
525 hasError: true,
526 },
527 {
528 name: "can't set rule for incorrect object schema",
529 schema: &apiextensions.JSONSchemaProps{
530 Type: "object",
531 },
532 rule: []string{"unsettable"},
533 hasError: true,
534 },
535 }
536
537 for _, tc := range tests {
538 t.Run(tc.name, func(t *testing.T) {
539 if err := crdutil.SetRequiredRuleForObjectOrArray(tc.schema, tc.rule); err != nil {
540 if !tc.hasError {
541 t.Fatalf("got an error, but want no error: %v", err)
542 }
543 return
544 }
545 if got, want := tc.schema, tc.expectedSchema; !reflect.DeepEqual(got, want) {
546 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
547 }
548 })
549 }
550 }
551
552 func TestGetNotRuleForObjectOrArray(t *testing.T) {
553 t.Parallel()
554 tests := []struct {
555 name string
556 schema *apiextensions.JSONSchemaProps
557 expectedRule *apiextensions.JSONSchemaProps
558 hasError bool
559 }{
560 {
561 name: "get not rule under object",
562 schema: &apiextensions.JSONSchemaProps{
563 Properties: map[string]apiextensions.JSONSchemaProps{
564 "test": {
565 Description: "field under object",
566 Type: "string",
567 },
568 },
569 Type: "object",
570 Not: &apiextensions.JSONSchemaProps{
571 Required: []string{"requiredField"},
572 },
573 },
574 expectedRule: &apiextensions.JSONSchemaProps{
575 Required: []string{"requiredField"},
576 },
577 },
578 {
579 name: "get not rule under map",
580 schema: &apiextensions.JSONSchemaProps{
581 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
582 Schema: &apiextensions.JSONSchemaProps{
583 Properties: map[string]apiextensions.JSONSchemaProps{
584 "test": {
585 Description: "field under map",
586 Type: "string",
587 },
588 },
589 Type: "object",
590 Not: &apiextensions.JSONSchemaProps{
591 Required: []string{"requiredField"},
592 },
593 },
594 },
595 Type: "object",
596 },
597 expectedRule: &apiextensions.JSONSchemaProps{
598 Required: []string{"requiredField"},
599 },
600 },
601 {
602 name: "get not rule under array",
603 schema: &apiextensions.JSONSchemaProps{
604 Items: &apiextensions.JSONSchemaPropsOrArray{
605 Schema: &apiextensions.JSONSchemaProps{
606 Properties: map[string]apiextensions.JSONSchemaProps{
607 "test": {
608 Description: "field under array",
609 Type: "string",
610 },
611 },
612 Type: "object",
613 Not: &apiextensions.JSONSchemaProps{
614 Required: []string{"requiredField"},
615 },
616 },
617 },
618 Type: "array",
619 },
620 expectedRule: &apiextensions.JSONSchemaProps{
621 Required: []string{"requiredField"},
622 },
623 },
624 {
625 name: "can't get rule for field under string field",
626 schema: &apiextensions.JSONSchemaProps{
627 Type: "string",
628 Not: &apiextensions.JSONSchemaProps{
629 Required: []string{"nonretrievable"},
630 },
631 },
632 hasError: true,
633 },
634 {
635 name: "can't get rule for incorrect object schema",
636 schema: &apiextensions.JSONSchemaProps{
637 Description: "an object field without properties or additionalProperties",
638 Type: "object",
639 Not: &apiextensions.JSONSchemaProps{
640 Required: []string{"nonretrievable"},
641 },
642 },
643 hasError: true,
644 },
645 }
646
647 for _, tc := range tests {
648 t.Run(tc.name, func(t *testing.T) {
649 rule, err := crdutil.GetNotRuleForObjectOrArray(tc.schema)
650 if err != nil {
651 if !tc.hasError {
652 t.Fatalf("got an error, but want no error: %v", err)
653 }
654 return
655 }
656 if got, want := rule, tc.expectedRule; !reflect.DeepEqual(got, want) {
657 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
658 }
659 })
660 }
661 }
662
663 func TestSetNotRuleForObjectOrArray(t *testing.T) {
664 t.Parallel()
665 tests := []struct {
666 name string
667 schema *apiextensions.JSONSchemaProps
668 rule *apiextensions.JSONSchemaProps
669 expectedSchema *apiextensions.JSONSchemaProps
670 hasError bool
671 }{
672 {
673 name: "set required rule under object",
674 schema: &apiextensions.JSONSchemaProps{
675 Properties: map[string]apiextensions.JSONSchemaProps{
676 "otherField": {
677 Type: "bool",
678 },
679 },
680 Type: "object",
681 },
682 rule: &apiextensions.JSONSchemaProps{
683 Required: []string{"requiredField"},
684 },
685 expectedSchema: &apiextensions.JSONSchemaProps{
686 Properties: map[string]apiextensions.JSONSchemaProps{
687 "otherField": {
688 Type: "bool",
689 },
690 },
691 Type: "object",
692 Not: &apiextensions.JSONSchemaProps{
693 Required: []string{"requiredField"},
694 },
695 },
696 },
697 {
698 name: "set required rule under map",
699 schema: &apiextensions.JSONSchemaProps{
700 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
701 Schema: &apiextensions.JSONSchemaProps{
702 Properties: map[string]apiextensions.JSONSchemaProps{
703 "otherField": {
704 Type: "bool",
705 },
706 },
707 Type: "object",
708 },
709 },
710 Type: "object",
711 },
712 rule: &apiextensions.JSONSchemaProps{
713 Required: []string{"requiredField"},
714 },
715 expectedSchema: &apiextensions.JSONSchemaProps{
716 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
717 Schema: &apiextensions.JSONSchemaProps{
718 Properties: map[string]apiextensions.JSONSchemaProps{
719 "otherField": {
720 Type: "bool",
721 },
722 },
723 Type: "object",
724 Not: &apiextensions.JSONSchemaProps{
725 Required: []string{"requiredField"},
726 },
727 },
728 },
729 Type: "object",
730 },
731 },
732 {
733 name: "set required rule under array",
734 schema: &apiextensions.JSONSchemaProps{
735 Items: &apiextensions.JSONSchemaPropsOrArray{
736 Schema: &apiextensions.JSONSchemaProps{
737 Properties: map[string]apiextensions.JSONSchemaProps{
738 "otherField": {
739 Type: "bool",
740 },
741 },
742 Type: "object",
743 },
744 },
745 Type: "array",
746 },
747 rule: &apiextensions.JSONSchemaProps{
748 Required: []string{"requiredField"},
749 },
750 expectedSchema: &apiextensions.JSONSchemaProps{
751 Items: &apiextensions.JSONSchemaPropsOrArray{
752 Schema: &apiextensions.JSONSchemaProps{
753 Properties: map[string]apiextensions.JSONSchemaProps{
754 "otherField": {
755 Type: "bool",
756 },
757 },
758 Type: "object",
759 Not: &apiextensions.JSONSchemaProps{
760 Required: []string{"requiredField"},
761 },
762 },
763 },
764 Type: "array",
765 },
766 },
767 {
768 name: "can't set rulee under a string field",
769 schema: &apiextensions.JSONSchemaProps{
770 Type: "string",
771 },
772 rule: &apiextensions.JSONSchemaProps{
773 Required: []string{"unsettable"},
774 },
775 hasError: true,
776 },
777 {
778 name: "can't set rule for incorrect object schema",
779 schema: &apiextensions.JSONSchemaProps{
780 Type: "object",
781 },
782 rule: &apiextensions.JSONSchemaProps{
783 Required: []string{"unsettable"},
784 },
785 hasError: true,
786 },
787 }
788
789 for _, tc := range tests {
790 t.Run(tc.name, func(t *testing.T) {
791 if err := crdutil.SetNotRuleForObjectOrArray(tc.schema, tc.rule); err != nil {
792 if !tc.hasError {
793 t.Fatalf("got an error, but want no error: %v", err)
794 }
795 return
796 }
797 if got, want := tc.schema, tc.expectedSchema; !reflect.DeepEqual(got, want) {
798 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
799 }
800 })
801 }
802 }
803
804 func TestGetOneOfRuleForObjectOrArray(t *testing.T) {
805 t.Parallel()
806 tests := []struct {
807 name string
808 schema *apiextensions.JSONSchemaProps
809 expectedRule []*apiextensions.JSONSchemaProps
810 hasError bool
811 }{
812 {
813 name: "get oneOf rule under object",
814 schema: &apiextensions.JSONSchemaProps{
815 Properties: map[string]apiextensions.JSONSchemaProps{
816 "test": {
817 Description: "field under object",
818 Type: "string",
819 },
820 },
821 Type: "object",
822 OneOf: []apiextensions.JSONSchemaProps{
823 {Required: []string{"field1"}},
824 {Required: []string{"field2"}},
825 },
826 },
827 expectedRule: []*apiextensions.JSONSchemaProps{
828 {Required: []string{"field1"}},
829 {Required: []string{"field2"}},
830 },
831 },
832 {
833 name: "get oneOf rule under map",
834 schema: &apiextensions.JSONSchemaProps{
835 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
836 Schema: &apiextensions.JSONSchemaProps{
837 Properties: map[string]apiextensions.JSONSchemaProps{
838 "test": {
839 Description: "field under map",
840 Type: "string",
841 },
842 },
843 Type: "object",
844 OneOf: []apiextensions.JSONSchemaProps{
845 {Required: []string{"field1"}},
846 {Required: []string{"field2"}},
847 },
848 },
849 },
850 Type: "object",
851 },
852 expectedRule: []*apiextensions.JSONSchemaProps{
853 {Required: []string{"field1"}},
854 {Required: []string{"field2"}},
855 },
856 },
857 {
858 name: "get oneOf rule under array",
859 schema: &apiextensions.JSONSchemaProps{
860 Items: &apiextensions.JSONSchemaPropsOrArray{
861 Schema: &apiextensions.JSONSchemaProps{
862 Properties: map[string]apiextensions.JSONSchemaProps{
863 "test": {
864 Description: "field under array",
865 Type: "string",
866 },
867 },
868 Type: "object",
869 OneOf: []apiextensions.JSONSchemaProps{
870 {Required: []string{"field1"}},
871 {Required: []string{"field2"}},
872 },
873 },
874 },
875 Type: "array",
876 },
877 expectedRule: []*apiextensions.JSONSchemaProps{
878 {Required: []string{"field1"}},
879 {Required: []string{"field2"}},
880 },
881 },
882 {
883 name: "can't get rule for field under string field",
884 schema: &apiextensions.JSONSchemaProps{
885 Type: "string",
886 OneOf: []apiextensions.JSONSchemaProps{
887 {Required: []string{"field1"}},
888 {Required: []string{"field2"}},
889 },
890 },
891 hasError: true,
892 },
893 {
894 name: "can't get rule for incorrect object schema",
895 schema: &apiextensions.JSONSchemaProps{
896 Description: "an object field without properties or additionalProperties",
897 Type: "object",
898 OneOf: []apiextensions.JSONSchemaProps{
899 {Required: []string{"field1"}},
900 {Required: []string{"field2"}},
901 },
902 },
903 hasError: true,
904 },
905 }
906
907 for _, tc := range tests {
908 t.Run(tc.name, func(t *testing.T) {
909 rule, err := crdutil.GetOneOfRuleForObjectOrArray(tc.schema)
910 if err != nil {
911 if !tc.hasError {
912 t.Fatalf("got an error, but want no error: %v", err)
913 }
914 return
915 }
916 if got, want := rule, tc.expectedRule; !reflect.DeepEqual(got, want) {
917 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
918 }
919 })
920 }
921 }
922
923 func TestSetOneOfRuleForObjectOrArray(t *testing.T) {
924 t.Parallel()
925 tests := []struct {
926 name string
927 schema *apiextensions.JSONSchemaProps
928 rule []*apiextensions.JSONSchemaProps
929 expectedSchema *apiextensions.JSONSchemaProps
930 hasError bool
931 }{
932 {
933 name: "set required rule under object",
934 schema: &apiextensions.JSONSchemaProps{
935 Properties: map[string]apiextensions.JSONSchemaProps{
936 "otherField": {
937 Type: "bool",
938 },
939 },
940 Type: "object",
941 },
942 rule: []*apiextensions.JSONSchemaProps{
943 {Required: []string{"field1"}},
944 {Required: []string{"field2"}},
945 },
946 expectedSchema: &apiextensions.JSONSchemaProps{
947 Properties: map[string]apiextensions.JSONSchemaProps{
948 "otherField": {
949 Type: "bool",
950 },
951 },
952 Type: "object",
953 OneOf: []apiextensions.JSONSchemaProps{
954 {Required: []string{"field1"}},
955 {Required: []string{"field2"}},
956 },
957 },
958 },
959 {
960 name: "set required rule under map",
961 schema: &apiextensions.JSONSchemaProps{
962 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
963 Schema: &apiextensions.JSONSchemaProps{
964 Properties: map[string]apiextensions.JSONSchemaProps{
965 "otherField": {
966 Type: "bool",
967 },
968 },
969 Type: "object",
970 },
971 },
972 Type: "object",
973 },
974 rule: []*apiextensions.JSONSchemaProps{
975 {Required: []string{"field1"}},
976 {Required: []string{"field2"}},
977 },
978 expectedSchema: &apiextensions.JSONSchemaProps{
979 AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
980 Schema: &apiextensions.JSONSchemaProps{
981 Properties: map[string]apiextensions.JSONSchemaProps{
982 "otherField": {
983 Type: "bool",
984 },
985 },
986 Type: "object",
987 OneOf: []apiextensions.JSONSchemaProps{
988 {Required: []string{"field1"}},
989 {Required: []string{"field2"}},
990 },
991 },
992 },
993 Type: "object",
994 },
995 },
996 {
997 name: "set required rule under array",
998 schema: &apiextensions.JSONSchemaProps{
999 Items: &apiextensions.JSONSchemaPropsOrArray{
1000 Schema: &apiextensions.JSONSchemaProps{
1001 Properties: map[string]apiextensions.JSONSchemaProps{
1002 "otherField": {
1003 Type: "bool",
1004 },
1005 },
1006 Type: "object",
1007 },
1008 },
1009 Type: "array",
1010 },
1011 rule: []*apiextensions.JSONSchemaProps{
1012 {Required: []string{"field1"}},
1013 {Required: []string{"field2"}},
1014 },
1015 expectedSchema: &apiextensions.JSONSchemaProps{
1016 Items: &apiextensions.JSONSchemaPropsOrArray{
1017 Schema: &apiextensions.JSONSchemaProps{
1018 Properties: map[string]apiextensions.JSONSchemaProps{
1019 "otherField": {
1020 Type: "bool",
1021 },
1022 },
1023 Type: "object",
1024 OneOf: []apiextensions.JSONSchemaProps{
1025 {Required: []string{"field1"}},
1026 {Required: []string{"field2"}},
1027 },
1028 },
1029 },
1030 Type: "array",
1031 },
1032 },
1033 {
1034 name: "can't set rulee under a string field",
1035 schema: &apiextensions.JSONSchemaProps{
1036 Type: "string",
1037 },
1038 rule: []*apiextensions.JSONSchemaProps{
1039 {Required: []string{"field1"}},
1040 {Required: []string{"field2"}},
1041 },
1042 hasError: true,
1043 },
1044 {
1045 name: "can't set rule for incorrect object schema",
1046 schema: &apiextensions.JSONSchemaProps{
1047 Type: "object",
1048 },
1049 rule: []*apiextensions.JSONSchemaProps{
1050 {Required: []string{"field1"}},
1051 {Required: []string{"field2"}},
1052 },
1053 hasError: true,
1054 },
1055 }
1056
1057 for _, tc := range tests {
1058 t.Run(tc.name, func(t *testing.T) {
1059 if err := crdutil.SetOneOfRuleForObjectOrArray(tc.schema, tc.rule); err != nil {
1060 if !tc.hasError {
1061 t.Fatalf("got an error, but want no error: %v", err)
1062 }
1063 return
1064 }
1065 if got, want := tc.schema, tc.expectedSchema; !reflect.DeepEqual(got, want) {
1066 t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(want, got))
1067 }
1068 })
1069 }
1070 }
1071
View as plain text