1
16
17 package aggregator
18
19 import (
20 "encoding/json"
21 "fmt"
22 "os"
23 "path/filepath"
24 "reflect"
25 "testing"
26
27 "github.com/stretchr/testify/assert"
28 "github.com/stretchr/testify/require"
29
30 "k8s.io/kube-openapi/pkg/handler"
31 "k8s.io/kube-openapi/pkg/validation/spec"
32 "sigs.k8s.io/yaml"
33 )
34
35 type DebugSpec struct {
36 *spec.Swagger
37 }
38
39 func (d DebugSpec) String() string {
40 bytes, err := d.Swagger.MarshalJSON()
41 if err != nil {
42 return fmt.Sprintf("DebugSpec.String failed: %s", err)
43 }
44 return string(bytes)
45 }
46 func TestFilterSpecs(t *testing.T) {
47 var spec1, spec1_filtered *spec.Swagger
48 yaml.Unmarshal([]byte(`
49 swagger: "2.0"
50 paths:
51 /test:
52 post:
53 tags:
54 - "test"
55 summary: "Test API"
56 operationId: "addTest"
57 parameters:
58 - in: "body"
59 name: "body"
60 description: "test object"
61 required: true
62 schema:
63 $ref: "#/definitions/Test"
64 responses:
65 405:
66 description: "Invalid input"
67 $ref: "#/definitions/InvalidInput"
68 /othertest:
69 post:
70 tags:
71 - "test2"
72 summary: "Test2 API"
73 operationId: "addTest2"
74 consumes:
75 - "application/json"
76 produces:
77 - "application/xml"
78 parameters:
79 - in: "body"
80 name: "body"
81 description: "test2 object"
82 required: true
83 schema:
84 $ref: "#/definitions/Test2"
85 definitions:
86 Test:
87 type: "object"
88 properties:
89 id:
90 type: "integer"
91 format: "int64"
92 status:
93 type: "string"
94 description: "Status"
95 InvalidInput:
96 type: "string"
97 format: "string"
98 Test2:
99 type: "object"
100 properties:
101 other:
102 $ref: "#/definitions/Other"
103 Other:
104 type: "string"
105 `), &spec1)
106
107 yaml.Unmarshal([]byte(`
108 swagger: "2.0"
109 paths:
110 /test:
111 post:
112 tags:
113 - "test"
114 summary: "Test API"
115 operationId: "addTest"
116 parameters:
117 - in: "body"
118 name: "body"
119 description: "test object"
120 required: true
121 schema:
122 $ref: "#/definitions/Test"
123 responses:
124 405:
125 description: "Invalid input"
126 $ref: "#/definitions/InvalidInput"
127 definitions:
128 Test:
129 type: "object"
130 properties:
131 id:
132 type: "integer"
133 format: "int64"
134 status:
135 type: "string"
136 description: "Status"
137 InvalidInput:
138 type: "string"
139 format: "string"
140 `), &spec1_filtered)
141
142 ast := assert.New(t)
143 orig_spec1, _ := cloneSpec(spec1)
144 new_spec1 := FilterSpecByPathsWithoutSideEffects(spec1, []string{"/test"})
145 ast.Equal(DebugSpec{spec1_filtered}, DebugSpec{new_spec1})
146 ast.Equal(DebugSpec{orig_spec1}, DebugSpec{spec1}, "unexpected mutation of input")
147 }
148
149 func TestFilterSpecsWithUnusedDefinitions(t *testing.T) {
150 var spec1, spec1Filtered *spec.Swagger
151 yaml.Unmarshal([]byte(`
152 swagger: "2.0"
153 paths:
154 /test:
155 post:
156 tags:
157 - "test"
158 summary: "Test API"
159 operationId: "addTest"
160 parameters:
161 - in: "body"
162 name: "body"
163 description: "test object"
164 required: true
165 schema:
166 $ref: "#/definitions/Test"
167 responses:
168 405:
169 description: "Invalid input"
170 $ref: "#/definitions/InvalidInput"
171 /othertest:
172 post:
173 tags:
174 - "test2"
175 summary: "Test2 API"
176 operationId: "addTest2"
177 consumes:
178 - "application/json"
179 produces:
180 - "application/xml"
181 parameters:
182 - in: "body"
183 name: "body"
184 description: "test2 object"
185 required: true
186 schema:
187 $ref: "#/definitions/Test2"
188 definitions:
189 Test:
190 type: "object"
191 properties:
192 id:
193 type: "integer"
194 format: "int64"
195 status:
196 type: "string"
197 description: "Status"
198 InvalidInput:
199 type: "string"
200 format: "string"
201 Test2:
202 type: "object"
203 properties:
204 other:
205 $ref: "#/definitions/Other"
206 Other:
207 type: "string"
208 Unused:
209 type: "object"
210 `), &spec1)
211
212 yaml.Unmarshal([]byte(`
213 swagger: "2.0"
214 paths:
215 /test:
216 post:
217 tags:
218 - "test"
219 summary: "Test API"
220 operationId: "addTest"
221 parameters:
222 - in: "body"
223 name: "body"
224 description: "test object"
225 required: true
226 schema:
227 $ref: "#/definitions/Test"
228 responses:
229 405:
230 description: "Invalid input"
231 $ref: "#/definitions/InvalidInput"
232 definitions:
233 Test:
234 type: "object"
235 properties:
236 id:
237 type: "integer"
238 format: "int64"
239 status:
240 type: "string"
241 description: "Status"
242 InvalidInput:
243 type: "string"
244 format: "string"
245 Unused:
246 type: "object"
247 `), &spec1Filtered)
248
249 ast := assert.New(t)
250 orig_spec1, _ := cloneSpec(spec1)
251 new_spec1 := FilterSpecByPathsWithoutSideEffects(spec1, []string{"/test"})
252 ast.Equal(DebugSpec{spec1Filtered}, DebugSpec{new_spec1})
253 ast.Equal(DebugSpec{orig_spec1}, DebugSpec{spec1}, "unexpected mutation of input")
254 }
255
256 func TestMergeSpecsSimple(t *testing.T) {
257 var spec1, spec2, expected *spec.Swagger
258 require.NoError(t, yaml.Unmarshal([]byte(`
259 swagger: "2.0"
260 paths:
261 /test:
262 post:
263 tags:
264 - "test"
265 summary: "Test API"
266 operationId: "addTest"
267 parameters:
268 - in: "body"
269 name: "body"
270 description: "test object"
271 required: true
272 schema:
273 $ref: "#/definitions/Test"
274 - $ref: "#/parameters/a"
275 responses:
276 405:
277 description: "Invalid input"
278 $ref: "#/definitions/InvalidInput"
279 definitions:
280 Test:
281 type: "object"
282 properties:
283 id:
284 type: "integer"
285 format: "int64"
286 status:
287 type: "string"
288 description: "Status"
289 InvalidInput:
290 type: "string"
291 format: "string"
292 parameters:
293 a:
294 in: query
295 name: a
296 schema:
297 $ref: "#/definitions/Test"
298 `), &spec1))
299
300 require.NoError(t, yaml.Unmarshal([]byte(`
301 swagger: "2.0"
302 paths:
303 /othertest:
304 post:
305 tags:
306 - "test2"
307 summary: "Test2 API"
308 operationId: "addTest2"
309 consumes:
310 - "application/json"
311 produces:
312 - "application/xml"
313 parameters:
314 - in: "body"
315 name: "body"
316 description: "test2 object"
317 required: true
318 schema:
319 $ref: "#/definitions/Test2"
320 - $ref: "#/parameters/b"
321 definitions:
322 Test2:
323 type: "object"
324 properties:
325 other:
326 $ref: "#/definitions/Other"
327 Other:
328 type: "string"
329 parameters:
330 b:
331 in: query
332 name: b
333 schema:
334 $ref: "#/definitions/Test2"
335 `), &spec2))
336
337 require.NoError(t, yaml.Unmarshal([]byte(`
338 swagger: "2.0"
339 paths:
340 /test:
341 post:
342 tags:
343 - "test"
344 summary: "Test API"
345 operationId: "addTest"
346 parameters:
347 - in: "body"
348 name: "body"
349 description: "test object"
350 required: true
351 schema:
352 $ref: "#/definitions/Test"
353 - $ref: "#/parameters/a"
354 responses:
355 405:
356 description: "Invalid input"
357 $ref: "#/definitions/InvalidInput"
358 /othertest:
359 post:
360 tags:
361 - "test2"
362 summary: "Test2 API"
363 operationId: "addTest2"
364 consumes:
365 - "application/json"
366 produces:
367 - "application/xml"
368 parameters:
369 - in: "body"
370 name: "body"
371 description: "test2 object"
372 required: true
373 schema:
374 $ref: "#/definitions/Test2"
375 - $ref: "#/parameters/b"
376 definitions:
377 Test:
378 type: "object"
379 properties:
380 id:
381 type: "integer"
382 format: "int64"
383 status:
384 type: "string"
385 description: "Status"
386 InvalidInput:
387 type: "string"
388 format: "string"
389 Test2:
390 type: "object"
391 properties:
392 other:
393 $ref: "#/definitions/Other"
394 Other:
395 type: "string"
396 parameters:
397 a:
398 in: query
399 name: a
400 schema:
401 $ref: "#/definitions/Test"
402 b:
403 in: query
404 name: b
405 schema:
406 $ref: "#/definitions/Test2"
407 `), &expected))
408
409 ast := assert.New(t)
410 orig_spec2, _ := cloneSpec(spec2)
411 if !ast.NoError(MergeSpecs(spec1, spec2)) {
412 return
413 }
414 ast.Equal(DebugSpec{expected}.String(), DebugSpec{spec1}.String())
415 ast.Equal(DebugSpec{orig_spec2}.String(), DebugSpec{spec2}.String(), "unexpected mutation of input")
416 }
417
418 func TestMergeSpecsEmptyDefinitions(t *testing.T) {
419 var spec1, spec2, expected *spec.Swagger
420 require.NoError(t, yaml.Unmarshal([]byte(`
421 swagger: "2.0"
422 paths:
423 /test:
424 post:
425 tags:
426 - "test"
427 summary: "Test API"
428 operationId: "addTest"
429 parameters:
430 - in: "body"
431 name: "body"
432 description: "test object"
433 required: true
434 responses:
435 405:
436 description: "Invalid input"
437 `), &spec1))
438
439 require.NoError(t, yaml.Unmarshal([]byte(`
440 swagger: "2.0"
441 paths:
442 /othertest:
443 post:
444 tags:
445 - "test2"
446 summary: "Test2 API"
447 operationId: "addTest2"
448 consumes:
449 - "application/json"
450 produces:
451 - "application/xml"
452 parameters:
453 - in: "body"
454 name: "body"
455 description: "test2 object"
456 required: true
457 schema:
458 $ref: "#/definitions/Test2"
459 definitions:
460 Test2:
461 type: "object"
462 properties:
463 other:
464 $ref: "#/definitions/Other"
465 Other:
466 type: "string"
467 `), &spec2))
468
469 require.NoError(t, yaml.Unmarshal([]byte(`
470 swagger: "2.0"
471 paths:
472 /test:
473 post:
474 tags:
475 - "test"
476 summary: "Test API"
477 operationId: "addTest"
478 parameters:
479 - in: "body"
480 name: "body"
481 description: "test object"
482 required: true
483 responses:
484 405:
485 description: "Invalid input"
486 /othertest:
487 post:
488 tags:
489 - "test2"
490 summary: "Test2 API"
491 operationId: "addTest2"
492 consumes:
493 - "application/json"
494 produces:
495 - "application/xml"
496 parameters:
497 - in: "body"
498 name: "body"
499 description: "test2 object"
500 required: true
501 schema:
502 $ref: "#/definitions/Test2"
503 definitions:
504 Test2:
505 type: "object"
506 properties:
507 other:
508 $ref: "#/definitions/Other"
509 Other:
510 type: "string"
511 `), &expected))
512
513 ast := assert.New(t)
514 orig_spec2, _ := cloneSpec(spec2)
515 if !ast.NoError(MergeSpecs(spec1, spec2)) {
516 return
517 }
518 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
519 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
520 }
521
522 func TestMergeSpecsEmptyPaths(t *testing.T) {
523 var spec1, spec2, expected *spec.Swagger
524 yaml.Unmarshal([]byte(`
525 swagger: "2.0"
526 definitions:
527 Test:
528 type: "object"
529 properties:
530 id:
531 type: "integer"
532 format: "int64"
533 status:
534 type: "string"
535 description: "Status"
536 InvalidInput:
537 type: "string"
538 format: "string"
539 `), &spec1)
540
541 yaml.Unmarshal([]byte(`
542 swagger: "2.0"
543 paths:
544 /othertest:
545 post:
546 tags:
547 - "test2"
548 summary: "Test2 API"
549 operationId: "addTest2"
550 consumes:
551 - "application/json"
552 produces:
553 - "application/xml"
554 parameters:
555 - in: "body"
556 name: "body"
557 description: "test2 object"
558 required: true
559 schema:
560 $ref: "#/definitions/Test2"
561 definitions:
562 Test2:
563 type: "object"
564 properties:
565 other:
566 $ref: "#/definitions/Other"
567 Other:
568 type: "string"
569 `), &spec2)
570
571 yaml.Unmarshal([]byte(`
572 swagger: "2.0"
573 paths:
574 /othertest:
575 post:
576 tags:
577 - "test2"
578 summary: "Test2 API"
579 operationId: "addTest2"
580 consumes:
581 - "application/json"
582 produces:
583 - "application/xml"
584 parameters:
585 - in: "body"
586 name: "body"
587 description: "test2 object"
588 required: true
589 schema:
590 $ref: "#/definitions/Test2"
591 definitions:
592 Test:
593 type: "object"
594 properties:
595 id:
596 type: "integer"
597 format: "int64"
598 status:
599 type: "string"
600 description: "Status"
601 InvalidInput:
602 type: "string"
603 format: "string"
604 Test2:
605 type: "object"
606 properties:
607 other:
608 $ref: "#/definitions/Other"
609 Other:
610 type: "string"
611 `), &expected)
612
613 ast := assert.New(t)
614 orig_spec2, _ := cloneSpec(spec2)
615 if !ast.NoError(MergeSpecs(spec1, spec2)) {
616 return
617 }
618 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
619 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
620 }
621
622 func TestMergeSpecsReuseModel(t *testing.T) {
623 var spec1, spec2, expected *spec.Swagger
624 require.NoError(t, yaml.Unmarshal([]byte(`
625 swagger: "2.0"
626 paths:
627 /test:
628 post:
629 tags:
630 - "test"
631 summary: "Test API"
632 operationId: "addTest"
633 parameters:
634 - in: "body"
635 name: "body"
636 description: "test object"
637 required: true
638 schema:
639 $ref: "#/definitions/Test"
640 - $ref: "#/parameters/a"
641 responses:
642 405:
643 description: "Invalid input"
644 $ref: "#/definitions/InvalidInput"
645 definitions:
646 Test:
647 type: "object"
648 properties:
649 id:
650 type: "integer"
651 format: "int64"
652 status:
653 type: "string"
654 description: "Status"
655 InvalidInput:
656 type: "string"
657 format: "string"
658 parameters:
659 a:
660 in: query
661 name: a
662 schema:
663 $ref: "#/definitions/Test"
664 `), &spec1))
665
666 require.NoError(t, yaml.Unmarshal([]byte(`
667 swagger: "2.0"
668 paths:
669 /othertest:
670 post:
671 tags:
672 - "test2"
673 summary: "Test2 API"
674 operationId: "addTest2"
675 consumes:
676 - "application/json"
677 produces:
678 - "application/xml"
679 parameters:
680 - in: "body"
681 name: "body"
682 description: "test2 object"
683 required: true
684 schema:
685 $ref: "#/definitions/Test"
686 - $ref: "#/parameters/a"
687 definitions:
688 Test:
689 type: "object"
690 properties:
691 id:
692 type: "integer"
693 format: "int64"
694 status:
695 type: "string"
696 description: "Status"
697 InvalidInput:
698 type: "string"
699 format: "string"
700 parameters:
701 a:
702 in: query
703 name: a
704 schema:
705 $ref: "#/definitions/Test"
706 `), &spec2))
707
708 require.NoError(t, yaml.Unmarshal([]byte(`
709 swagger: "2.0"
710 paths:
711 /test:
712 post:
713 tags:
714 - "test"
715 summary: "Test API"
716 operationId: "addTest"
717 parameters:
718 - in: "body"
719 name: "body"
720 description: "test object"
721 required: true
722 schema:
723 $ref: "#/definitions/Test"
724 - $ref: "#/parameters/a"
725 responses:
726 405:
727 description: "Invalid input"
728 $ref: "#/definitions/InvalidInput"
729 /othertest:
730 post:
731 tags:
732 - "test2"
733 summary: "Test2 API"
734 operationId: "addTest2"
735 consumes:
736 - "application/json"
737 produces:
738 - "application/xml"
739 parameters:
740 - in: "body"
741 name: "body"
742 description: "test2 object"
743 required: true
744 schema:
745 $ref: "#/definitions/Test"
746 - $ref: "#/parameters/a"
747 definitions:
748 Test:
749 type: "object"
750 properties:
751 id:
752 type: "integer"
753 format: "int64"
754 status:
755 type: "string"
756 description: "Status"
757 InvalidInput:
758 type: "string"
759 format: "string"
760 parameters:
761 a:
762 in: query
763 name: a
764 schema:
765 $ref: "#/definitions/Test"
766 `), &expected))
767
768 ast := assert.New(t)
769 orig_spec2, _ := cloneSpec(spec2)
770 if !ast.NoError(MergeSpecs(spec1, spec2)) {
771 return
772 }
773 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
774 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
775 }
776
777 func TestMergeSpecsRenameModel(t *testing.T) {
778 var spec1, spec2, expected *spec.Swagger
779 require.NoError(t, yaml.Unmarshal([]byte(`
780 swagger: "2.0"
781 paths:
782 /test:
783 post:
784 tags:
785 - "test"
786 summary: "Test API"
787 operationId: "addTest"
788 parameters:
789 - in: "body"
790 name: "body"
791 description: "test object"
792 required: true
793 schema:
794 $ref: "#/definitions/Test"
795 - $ref: "#/parameters/a"
796 responses:
797 405:
798 description: "Invalid input"
799 $ref: "#/definitions/InvalidInput"
800 definitions:
801 Test:
802 type: "object"
803 properties:
804 id:
805 type: "integer"
806 format: "int64"
807 status:
808 type: "string"
809 description: "Status"
810 InvalidInput:
811 type: "string"
812 format: "string"
813 parameters:
814 a:
815 in: query
816 name: a
817 schema:
818 $ref: "#/definitions/Test"
819 `), &spec1))
820
821 require.NoError(t, yaml.Unmarshal([]byte(`
822 swagger: "2.0"
823 paths:
824 /othertest:
825 post:
826 tags:
827 - "test2"
828 summary: "Test2 API"
829 operationId: "addTest2"
830 consumes:
831 - "application/json"
832 produces:
833 - "application/xml"
834 parameters:
835 - in: "body"
836 name: "body"
837 description: "test2 object"
838 required: true
839 schema:
840 $ref: "#/definitions/Test"
841 - $ref: "#/parameters/a"
842 definitions:
843 Test:
844 description: "This Test has a description"
845 type: "object"
846 properties:
847 id:
848 type: "integer"
849 format: "int64"
850 InvalidInput:
851 type: "string"
852 format: "string"
853 parameters:
854 a:
855 in: query
856 name: a
857 schema:
858 $ref: "#/definitions/Test"
859 `), &spec2))
860
861 require.NoError(t, yaml.Unmarshal([]byte(`
862 swagger: "2.0"
863 paths:
864 /test:
865 post:
866 tags:
867 - "test"
868 summary: "Test API"
869 operationId: "addTest"
870 parameters:
871 - in: "body"
872 name: "body"
873 description: "test object"
874 required: true
875 schema:
876 $ref: "#/definitions/Test"
877 - $ref: "#/parameters/a"
878 responses:
879 405:
880 description: "Invalid input"
881 $ref: "#/definitions/InvalidInput"
882 /othertest:
883 post:
884 tags:
885 - "test2"
886 summary: "Test2 API"
887 operationId: "addTest2"
888 consumes:
889 - "application/json"
890 produces:
891 - "application/xml"
892 parameters:
893 - in: "body"
894 name: "body"
895 description: "test2 object"
896 required: true
897 schema:
898 $ref: "#/definitions/Test_v2"
899 - $ref: "#/parameters/a_v2"
900 definitions:
901 Test:
902 type: "object"
903 properties:
904 id:
905 type: "integer"
906 format: "int64"
907 status:
908 type: "string"
909 description: "Status"
910 Test_v2:
911 description: "This Test has a description"
912 type: "object"
913 properties:
914 id:
915 type: "integer"
916 format: "int64"
917 InvalidInput:
918 type: "string"
919 format: "string"
920 parameters:
921 a:
922 in: query
923 name: a
924 schema:
925 $ref: "#/definitions/Test"
926 a_v2:
927 in: query
928 name: a
929 schema:
930 $ref: "#/definitions/Test_v2"
931 `), &expected))
932
933 ast := assert.New(t)
934 orig_spec2, _ := cloneSpec(spec2)
935 if !ast.NoError(MergeSpecs(spec1, spec2)) {
936 return
937 }
938 ast.Equal(DebugSpec{expected}, DebugSpec{spec1}, DebugSpec{spec1}.String())
939 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
940 }
941
942 func TestMergeSpecsRenameModelWithExistingV2InDestination(t *testing.T) {
943 var spec1, spec2, expected *spec.Swagger
944 require.NoError(t, yaml.Unmarshal([]byte(`
945 swagger: "2.0"
946 paths:
947 /test:
948 post:
949 parameters:
950 - name: "body"
951 schema:
952 $ref: "#/definitions/Test"
953 - $ref: "#/parameters/a"
954 /testv2:
955 post:
956 parameters:
957 - name: "body"
958 schema:
959 $ref: "#/definitions/Test_v2"
960 - $ref: "#/parameters/a_v2"
961 definitions:
962 Test:
963 type: "object"
964 Test_v2:
965 description: "This is an existing Test_v2 in destination schema"
966 type: "object"
967 parameters:
968 a:
969 in: query
970 name: a
971 schema:
972 $ref: "#/definitions/Test"
973 a_v2:
974 in: query
975 name: a
976 schema:
977 $ref: "#/definitions/Test_v2"
978 `), &spec1))
979
980 require.NoError(t, yaml.Unmarshal([]byte(`
981 swagger: "2.0"
982 paths:
983 /othertest:
984 post:
985 parameters:
986 - name: "body"
987 schema:
988 $ref: "#/definitions/Test"
989 - $ref: "#/parameters/a"
990 definitions:
991 Test:
992 description: "This Test has a description"
993 type: "object"
994 parameters:
995 a:
996 in: query
997 name: a
998 schema:
999 $ref: "#/definitions/Test"
1000 `), &spec2))
1001
1002 require.NoError(t, yaml.Unmarshal([]byte(`
1003 swagger: "2.0"
1004 paths:
1005 /test:
1006 post:
1007 parameters:
1008 - name: "body"
1009 schema:
1010 $ref: "#/definitions/Test"
1011 - $ref: "#/parameters/a"
1012 /testv2:
1013 post:
1014 parameters:
1015 - name: "body"
1016 schema:
1017 $ref: "#/definitions/Test_v2"
1018 - $ref: "#/parameters/a_v2"
1019 /othertest:
1020 post:
1021 parameters:
1022 - name: "body"
1023 schema:
1024 $ref: "#/definitions/Test_v3"
1025 - $ref: "#/parameters/a_v3"
1026 definitions:
1027 Test:
1028 type: "object"
1029 Test_v2:
1030 description: "This is an existing Test_v2 in destination schema"
1031 type: "object"
1032 Test_v3:
1033 description: "This Test has a description"
1034 type: "object"
1035 parameters:
1036 a:
1037 in: query
1038 name: a
1039 schema:
1040 $ref: "#/definitions/Test"
1041 a_v2:
1042 in: query
1043 name: a
1044 schema:
1045 $ref: "#/definitions/Test_v2"
1046 a_v3:
1047 in: query
1048 name: a
1049 schema:
1050 $ref: "#/definitions/Test_v3"
1051 `), &expected))
1052
1053 ast := assert.New(t)
1054 orig_spec2, _ := cloneSpec(spec2)
1055 if !ast.NoError(MergeSpecs(spec1, spec2)) {
1056 return
1057 }
1058 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
1059 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
1060 }
1061
1062 func TestMergeSpecsMultipleRenamesOfModelsAndLateConflict(t *testing.T) {
1063 var spec1, spec2, expected *spec.Swagger
1064 require.NoError(t, yaml.Unmarshal([]byte(`
1065 swagger: "2.0"
1066 paths:
1067 /test:
1068 post:
1069 parameters:
1070 - name: "body"
1071 schema:
1072 $ref: "#/definitions/Test"
1073 - $ref: "#/parameters/a"
1074 /test3:
1075 post:
1076 parameters:
1077 - name: "body"
1078 schema:
1079 $ref: "#/definitions/Test_v3"
1080 - $ref: "#/parameters/a_v3"
1081 definitions:
1082 Test:
1083 description: "I used to be Test in destination"
1084 type: "object"
1085 Test_v3:
1086 description: "I used to be Test_v3 in destination"
1087 type: "object"
1088 parameters:
1089 a:
1090 in: query
1091 name: a
1092 schema:
1093 $ref: "#/definitions/Test"
1094 a_v3:
1095 in: query
1096 name: a
1097 schema:
1098 $ref: "#/definitions/Test_v3"
1099 `), &spec1))
1100
1101 require.NoError(t, yaml.Unmarshal([]byte(`
1102 swagger: "2.0"
1103 paths:
1104 /othertest:
1105 post:
1106 parameters:
1107 - name: "body"
1108 schema:
1109 $ref: "#/definitions/Test"
1110 - $ref: "#/parameters/a"
1111 /othertest2:
1112 post:
1113 parameters:
1114 - name: "body"
1115 schema:
1116 $ref: "#/definitions/Test_v2"
1117 - $ref: "#/parameters/a_v2"
1118 definitions:
1119 Test:
1120 description: "I used to be Test in source"
1121 type: "object"
1122 Test_v2:
1123 description: "I used to be Test_v2 in source"
1124 type: "object"
1125 parameters:
1126 a:
1127 in: query
1128 name: a
1129 schema:
1130 $ref: "#/definitions/Test"
1131 a_v2:
1132 in: query
1133 name: a
1134 schema:
1135 $ref: "#/definitions/Test_v2"
1136 `), &spec2))
1137
1138 require.NoError(t, yaml.Unmarshal([]byte(`
1139 swagger: "2.0"
1140 paths:
1141 /test:
1142 post:
1143 parameters:
1144 - name: "body"
1145 schema:
1146 $ref: "#/definitions/Test"
1147 - $ref: "#/parameters/a"
1148 /test3:
1149 post:
1150 parameters:
1151 - name: "body"
1152 schema:
1153 $ref: "#/definitions/Test_v3"
1154 - $ref: "#/parameters/a_v3"
1155 /othertest2:
1156 post:
1157 parameters:
1158 - name: "body"
1159 schema:
1160 $ref: "#/definitions/Test_v2"
1161 - $ref: "#/parameters/a_v2"
1162 /othertest:
1163 post:
1164 parameters:
1165 - name: "body"
1166 schema:
1167 $ref: "#/definitions/Test_v4"
1168 - $ref: "#/parameters/a_v4"
1169 definitions:
1170 Test:
1171 description: "I used to be Test in destination"
1172 type: "object"
1173 Test_v2:
1174 description: "I used to be Test_v2 in source"
1175 type: "object"
1176 Test_v3:
1177 description: "I used to be Test_v3 in destination"
1178 type: "object"
1179 Test_v4:
1180 description: "I used to be Test in source"
1181 type: "object"
1182 parameters:
1183 a:
1184 in: query
1185 name: a
1186 schema:
1187 $ref: "#/definitions/Test"
1188 a_v2:
1189 in: query
1190 name: a
1191 schema:
1192 $ref: "#/definitions/Test_v2"
1193 a_v3:
1194 in: query
1195 name: a
1196 schema:
1197 $ref: "#/definitions/Test_v3"
1198 a_v4:
1199 in: query
1200 name: a
1201 schema:
1202 $ref: "#/definitions/Test_v4"
1203 `), &expected))
1204
1205 ast := assert.New(t)
1206 orig_spec2, _ := cloneSpec(spec2)
1207 if !ast.NoError(MergeSpecs(spec1, spec2)) {
1208 return
1209 }
1210 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
1211 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
1212 }
1213
1214 func TestMergeSpecsRenameModelWithExistingV2InSource(t *testing.T) {
1215 var spec1, spec2, expected *spec.Swagger
1216 require.NoError(t, yaml.Unmarshal([]byte(`
1217 swagger: "2.0"
1218 paths:
1219 /test:
1220 post:
1221 parameters:
1222 - name: "body"
1223 schema:
1224 $ref: "#/definitions/Test"
1225 - $ref: "#/parameters/a"
1226 definitions:
1227 Test:
1228 type: "object"
1229 parameters:
1230 a:
1231 in: query
1232 name: a
1233 schema:
1234 $ref: "#/definitions/Test"
1235 `), &spec1))
1236
1237 require.NoError(t, yaml.Unmarshal([]byte(`
1238 swagger: "2.0"
1239 paths:
1240 /othertest:
1241 post:
1242 parameters:
1243 - name: "body"
1244 schema:
1245 $ref: "#/definitions/Test"
1246 - $ref: "#/parameters/a"
1247 /testv2:
1248 post:
1249 parameters:
1250 - name: "body"
1251 schema:
1252 $ref: "#/definitions/Test_v2"
1253 - $ref: "#/parameters/a_v2"
1254 definitions:
1255 Test:
1256 description: "This Test has a description"
1257 type: "object"
1258 Test_v2:
1259 description: "This is an existing Test_v2 in source schema"
1260 type: "object"
1261 parameters:
1262 a:
1263 in: query
1264 name: a
1265 schema:
1266 $ref: "#/definitions/Test"
1267 a_v2:
1268 in: query
1269 name: a
1270 schema:
1271 $ref: "#/definitions/Test_v2"
1272 `), &spec2))
1273
1274 require.NoError(t, yaml.Unmarshal([]byte(`
1275 swagger: "2.0"
1276 paths:
1277 /test:
1278 post:
1279 parameters:
1280 - name: "body"
1281 schema:
1282 $ref: "#/definitions/Test"
1283 - $ref: "#/parameters/a"
1284 /testv2:
1285 post:
1286 parameters:
1287 - name: "body"
1288 schema:
1289 $ref: "#/definitions/Test_v2"
1290 - $ref: "#/parameters/a_v2"
1291 /othertest:
1292 post:
1293 parameters:
1294 - name: "body"
1295 schema:
1296 $ref: "#/definitions/Test_v3"
1297 - $ref: "#/parameters/a_v3"
1298 definitions:
1299 Test:
1300 type: "object"
1301 Test_v2:
1302 description: "This is an existing Test_v2 in source schema"
1303 type: "object"
1304 Test_v3:
1305 description: "This Test has a description"
1306 type: "object"
1307 parameters:
1308 a:
1309 in: query
1310 name: a
1311 schema:
1312 $ref: "#/definitions/Test"
1313 a_v2:
1314 in: query
1315 name: a
1316 schema:
1317 $ref: "#/definitions/Test_v2"
1318 a_v3:
1319 in: query
1320 name: a
1321 schema:
1322 $ref: "#/definitions/Test_v3"
1323 `), &expected))
1324
1325 ast := assert.New(t)
1326 orig_spec2, _ := cloneSpec(spec2)
1327 if !ast.NoError(MergeSpecs(spec1, spec2)) {
1328 return
1329 }
1330 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
1331 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
1332 }
1333
1334
1335
1336
1337 func TestTwoMergeSpecsFirstTwoSchemasHaveSameDefinition(t *testing.T) {
1338 var spec1, spec2, spec3, expected *spec.Swagger
1339 yaml.Unmarshal([]byte(`
1340 swagger: "2.0"
1341 paths:
1342 /test:
1343 post:
1344 parameters:
1345 - name: "body"
1346 schema:
1347 $ref: "#/definitions/Test"
1348 definitions:
1349 Test:
1350 description: "spec1 and spec2 use the same object definition, while spec3 doesn't"
1351 type: "object"
1352 `), &spec1)
1353
1354 yaml.Unmarshal([]byte(`
1355 swagger: "2.0"
1356 paths:
1357 /test2:
1358 post:
1359 parameters:
1360 - name: "body"
1361 schema:
1362 $ref: "#/definitions/Test"
1363 definitions:
1364 Test:
1365 description: "spec1 and spec2 use the same object definition, while spec3 doesn't"
1366 type: "object"
1367 `), &spec2)
1368
1369 yaml.Unmarshal([]byte(`
1370 swagger: "2.0"
1371 paths:
1372 /test3:
1373 post:
1374 parameters:
1375 - name: "body"
1376 schema:
1377 $ref: "#/definitions/Test"
1378 definitions:
1379 Test:
1380 description: "spec3 has its own definition (the description doesn't match)"
1381 type: "object"
1382 `), &spec3)
1383
1384 yaml.Unmarshal([]byte(`
1385 swagger: "2.0"
1386 paths:
1387 /test:
1388 post:
1389 parameters:
1390 - name: "body"
1391 schema:
1392 $ref: "#/definitions/Test"
1393 /test2:
1394 post:
1395 parameters:
1396 - name: "body"
1397 schema:
1398 $ref: "#/definitions/Test"
1399 /test3:
1400 post:
1401 parameters:
1402 - name: "body"
1403 schema:
1404 $ref: "#/definitions/Test_v2"
1405 definitions:
1406 Test:
1407 description: "spec1 and spec2 use the same object definition, while spec3 doesn't"
1408 type: "object"
1409 Test_v2:
1410 description: "spec3 has its own definition (the description doesn't match)"
1411 type: "object"
1412 `), &expected)
1413
1414 ast := assert.New(t)
1415 orig_spec2, _ := cloneSpec(spec2)
1416 orig_spec3, _ := cloneSpec(spec3)
1417 if !ast.NoError(MergeSpecs(spec1, spec2)) {
1418 return
1419 }
1420 if !ast.NoError(MergeSpecs(spec1, spec3)) {
1421 return
1422 }
1423 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
1424 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of spec2 input")
1425 ast.Equal(DebugSpec{orig_spec3}, DebugSpec{spec3}, "unexpected mutation of spec3 input")
1426 }
1427
1428
1429
1430
1431 func TestTwoMergeSpecsLastTwoSchemasHaveSameDefinition(t *testing.T) {
1432 var spec1, spec2, spec3, expected *spec.Swagger
1433 yaml.Unmarshal([]byte(`
1434 swagger: "2.0"
1435 paths:
1436 /test:
1437 post:
1438 parameters:
1439 - name: "body"
1440 schema:
1441 $ref: "#/definitions/Test"
1442 definitions:
1443 Test:
1444 type: "object"
1445 `), &spec1)
1446
1447 yaml.Unmarshal([]byte(`
1448 swagger: "2.0"
1449 paths:
1450 /othertest:
1451 post:
1452 parameters:
1453 - name: "body"
1454 schema:
1455 $ref: "#/definitions/Test"
1456 definitions:
1457 Test:
1458 description: "spec2 and spec3 use the same object definition, while spec1 doesn't"
1459 type: "object"
1460 `), &spec2)
1461
1462 yaml.Unmarshal([]byte(`
1463 swagger: "2.0"
1464 paths:
1465 /othertest2:
1466 post:
1467 parameters:
1468 - name: "body"
1469 schema:
1470 $ref: "#/definitions/Test"
1471 definitions:
1472 Test:
1473 description: "spec2 and spec3 use the same object definition, while spec1 doesn't"
1474 type: "object"
1475 `), &spec3)
1476
1477 yaml.Unmarshal([]byte(`
1478 swagger: "2.0"
1479 paths:
1480 /test:
1481 post:
1482 parameters:
1483 - name: "body"
1484 schema:
1485 $ref: "#/definitions/Test"
1486 /othertest:
1487 post:
1488 parameters:
1489 - name: "body"
1490 schema:
1491 $ref: "#/definitions/Test_v2"
1492 /othertest2:
1493 post:
1494 parameters:
1495 - name: "body"
1496 schema:
1497 $ref: "#/definitions/Test_v2"
1498 definitions:
1499 Test:
1500 type: "object"
1501 Test_v2:
1502 description: "spec2 and spec3 use the same object definition, while spec1 doesn't"
1503 type: "object"
1504 `), &expected)
1505
1506 ast := assert.New(t)
1507 orig_spec2, _ := cloneSpec(spec2)
1508 orig_spec3, _ := cloneSpec(spec3)
1509 if !ast.NoError(MergeSpecs(spec1, spec2)) {
1510 return
1511 }
1512 if !ast.NoError(MergeSpecs(spec1, spec3)) {
1513 return
1514 }
1515 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
1516 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of spec2 input")
1517 ast.Equal(DebugSpec{orig_spec3}, DebugSpec{spec3}, "unexpected mutation of spec3 input")
1518
1519 }
1520
1521 func TestSafeMergeSpecsSimple(t *testing.T) {
1522 var fooSpec, barSpec, expected *spec.Swagger
1523 yaml.Unmarshal([]byte(`
1524 swagger: "2.0"
1525 paths:
1526 /foo:
1527 post:
1528 summary: "Foo API"
1529 operationId: "fooTest"
1530 parameters:
1531 - in: "body"
1532 name: "body"
1533 description: "foo object"
1534 required: true
1535 schema:
1536 $ref: "#/definitions/Foo"
1537 responses:
1538 200:
1539 description: "OK"
1540 definitions:
1541 Foo:
1542 type: "object"
1543 properties:
1544 id:
1545 type: "integer"
1546 format: "int64"
1547 `), &fooSpec)
1548
1549 yaml.Unmarshal([]byte(`
1550 swagger: "2.0"
1551 paths:
1552 /bar:
1553 post:
1554 summary: "Bar API"
1555 operationId: "barTest"
1556 parameters:
1557 - in: "body"
1558 name: "body"
1559 description: "bar object"
1560 required: true
1561 schema:
1562 $ref: "#/definitions/Bar"
1563 responses:
1564 200:
1565 description: "OK"
1566 definitions:
1567 Bar:
1568 type: "object"
1569 properties:
1570 id:
1571 type: "integer"
1572 format: "int64"
1573 `), &barSpec)
1574
1575 yaml.Unmarshal([]byte(`
1576 swagger: "2.0"
1577 paths:
1578 /foo:
1579 post:
1580 summary: "Foo API"
1581 operationId: "fooTest"
1582 parameters:
1583 - in: "body"
1584 name: "body"
1585 description: "foo object"
1586 required: true
1587 schema:
1588 $ref: "#/definitions/Foo"
1589 responses:
1590 200:
1591 description: "OK"
1592 /bar:
1593 post:
1594 summary: "Bar API"
1595 operationId: "barTest"
1596 parameters:
1597 - in: "body"
1598 name: "body"
1599 description: "bar object"
1600 required: true
1601 schema:
1602 $ref: "#/definitions/Bar"
1603 responses:
1604 200:
1605 description: "OK"
1606 definitions:
1607 Foo:
1608 type: "object"
1609 properties:
1610 id:
1611 type: "integer"
1612 format: "int64"
1613 Bar:
1614 type: "object"
1615 properties:
1616 id:
1617 type: "integer"
1618 format: "int64"
1619 `), &expected)
1620
1621 ast := assert.New(t)
1622 orig_barSpec, err := cloneSpec(barSpec)
1623 if !ast.NoError(err) {
1624 return
1625 }
1626 if !ast.NoError(MergeSpecsFailOnDefinitionConflict(fooSpec, barSpec)) {
1627 return
1628 }
1629 ast.Equal(DebugSpec{expected}, DebugSpec{fooSpec})
1630 ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
1631 }
1632
1633 func TestSafeMergeSpecsReuseModel(t *testing.T) {
1634 var fooSpec, barSpec, expected *spec.Swagger
1635 if err := yaml.Unmarshal([]byte(`
1636 swagger: "2.0"
1637 paths:
1638 /foo:
1639 post:
1640 summary: "Foo API"
1641 operationId: "fooTest"
1642 parameters:
1643 - in: "body"
1644 name: "body"
1645 description: "foo object"
1646 required: true
1647 schema:
1648 $ref: "#/definitions/Foo"
1649 responses:
1650 200:
1651 description: "OK"
1652 definitions:
1653 Foo:
1654 type: "object"
1655 properties:
1656 id:
1657 type: "integer"
1658 format: "int64"
1659 x-kubernetes-group-version-kind:
1660 - group: group1
1661 version: v1
1662 kind: Foo
1663 - group: group3
1664 version: v1
1665 kind: Foo
1666 `), &fooSpec); err != nil {
1667 t.Fatal(err)
1668 }
1669
1670 if err := yaml.Unmarshal([]byte(`
1671 swagger: "2.0"
1672 paths:
1673 /refoo:
1674 post:
1675 summary: "Refoo API"
1676 operationId: "refooTest"
1677 parameters:
1678 - in: "body"
1679 name: "body"
1680 description: "foo object"
1681 required: true
1682 schema:
1683 $ref: "#/definitions/Foo"
1684 responses:
1685 200:
1686 description: "OK"
1687 definitions:
1688 Foo:
1689 type: "object"
1690 properties:
1691 id:
1692 type: "integer"
1693 format: "int64"
1694 x-kubernetes-group-version-kind:
1695 - group: group2
1696 version: v1
1697 kind: Foo
1698 `), &barSpec); err != nil {
1699 t.Fatal(err)
1700 }
1701
1702 if err := yaml.Unmarshal([]byte(`
1703 swagger: "2.0"
1704 paths:
1705 /foo:
1706 post:
1707 summary: "Foo API"
1708 operationId: "fooTest"
1709 parameters:
1710 - in: "body"
1711 name: "body"
1712 description: "foo object"
1713 required: true
1714 schema:
1715 $ref: "#/definitions/Foo"
1716 responses:
1717 200:
1718 description: "OK"
1719 /refoo:
1720 post:
1721 summary: "Refoo API"
1722 operationId: "refooTest"
1723 parameters:
1724 - in: "body"
1725 name: "body"
1726 description: "foo object"
1727 required: true
1728 schema:
1729 $ref: "#/definitions/Foo"
1730 responses:
1731 200:
1732 description: "OK"
1733 definitions:
1734 Foo:
1735 type: "object"
1736 properties:
1737 id:
1738 type: "integer"
1739 format: "int64"
1740 x-kubernetes-group-version-kind:
1741 - group: group1
1742 version: v1
1743 kind: Foo
1744 - group: group2
1745 version: v1
1746 kind: Foo
1747 - group: group3
1748 version: v1
1749 kind: Foo
1750 `), &expected); err != nil {
1751 t.Fatal(err)
1752 }
1753
1754 ast := assert.New(t)
1755 orig_barSpec, err := cloneSpec(barSpec)
1756 if !ast.NoError(err) {
1757 return
1758 }
1759 if !ast.NoError(MergeSpecsFailOnDefinitionConflict(fooSpec, barSpec)) {
1760 return
1761 }
1762 ast.Equal(DebugSpec{expected}, DebugSpec{fooSpec})
1763 ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
1764 }
1765
1766 func TestSafeMergeSpecsReuseModelFails(t *testing.T) {
1767 var fooSpec, barSpec, expected *spec.Swagger
1768 yaml.Unmarshal([]byte(`
1769 swagger: "2.0"
1770 paths:
1771 /foo:
1772 post:
1773 summary: "Foo API"
1774 operationId: "fooTest"
1775 parameters:
1776 - in: "body"
1777 name: "body"
1778 description: "foo object"
1779 required: true
1780 schema:
1781 $ref: "#/definitions/Foo"
1782 responses:
1783 200:
1784 description: "OK"
1785 definitions:
1786 Foo:
1787 type: "object"
1788 properties:
1789 id:
1790 type: "integer"
1791 format: "int64"
1792 `), &fooSpec)
1793
1794 yaml.Unmarshal([]byte(`
1795 swagger: "2.0"
1796 paths:
1797 /refoo:
1798 post:
1799 summary: "Refoo API"
1800 operationId: "refooTest"
1801 parameters:
1802 - in: "body"
1803 name: "body"
1804 description: "foo object"
1805 required: true
1806 schema:
1807 $ref: "#/definitions/Foo"
1808 responses:
1809 200:
1810 description: "OK"
1811 definitions:
1812 Foo:
1813 type: "object"
1814 properties:
1815 id:
1816 type: "integer"
1817 format: "int64"
1818 new_field:
1819 type: "string"
1820 `), &barSpec)
1821
1822 yaml.Unmarshal([]byte(`
1823 swagger: "2.0"
1824 paths:
1825 /foo:
1826 post:
1827 summary: "Foo API"
1828 operationId: "fooTest"
1829 parameters:
1830 - in: "body"
1831 name: "body"
1832 description: "foo object"
1833 required: true
1834 schema:
1835 $ref: "#/definitions/Foo"
1836 responses:
1837 200:
1838 description: "OK"
1839 /refoo:
1840 post:
1841 summary: "Refoo API"
1842 operationId: "refooTest"
1843 parameters:
1844 - in: "body"
1845 name: "body"
1846 description: "foo object"
1847 required: true
1848 schema:
1849 $ref: "#/definitions/Foo"
1850 responses:
1851 200:
1852 description: "OK"
1853 definitions:
1854 Foo:
1855 type: "object"
1856 properties:
1857 id:
1858 type: "integer"
1859 format: "int64"
1860 `), &expected)
1861
1862 ast := assert.New(t)
1863 ast.Error(MergeSpecsFailOnDefinitionConflict(fooSpec, barSpec))
1864 }
1865
1866 func TestMergeSpecsIgnorePathConflicts(t *testing.T) {
1867 var fooSpec, barSpec, expected *spec.Swagger
1868 yaml.Unmarshal([]byte(`
1869 swagger: "2.0"
1870 paths:
1871 /foo:
1872 post:
1873 summary: "Foo API"
1874 operationId: "fooTest"
1875 parameters:
1876 - in: "body"
1877 name: "body"
1878 description: "foo object"
1879 required: true
1880 schema:
1881 $ref: "#/definitions/Foo"
1882 responses:
1883 200:
1884 description: "OK"
1885 definitions:
1886 Foo:
1887 type: "object"
1888 properties:
1889 id:
1890 type: "integer"
1891 format: "int64"
1892 `), &fooSpec)
1893
1894 yaml.Unmarshal([]byte(`
1895 swagger: "2.0"
1896 paths:
1897 /foo:
1898 post:
1899 summary: "Should be ignored"
1900 /bar:
1901 post:
1902 summary: "Bar API"
1903 operationId: "barTest"
1904 parameters:
1905 - in: "body"
1906 name: "body"
1907 description: "bar object"
1908 required: true
1909 schema:
1910 $ref: "#/definitions/Bar"
1911 responses:
1912 200:
1913 description: "OK"
1914 definitions:
1915 Bar:
1916 type: "object"
1917 properties:
1918 id:
1919 type: "integer"
1920 format: "int64"
1921 `), &barSpec)
1922
1923 yaml.Unmarshal([]byte(`
1924 swagger: "2.0"
1925 paths:
1926 /foo:
1927 post:
1928 summary: "Foo API"
1929 operationId: "fooTest"
1930 parameters:
1931 - in: "body"
1932 name: "body"
1933 description: "foo object"
1934 required: true
1935 schema:
1936 $ref: "#/definitions/Foo"
1937 responses:
1938 200:
1939 description: "OK"
1940 /bar:
1941 post:
1942 summary: "Bar API"
1943 operationId: "barTest"
1944 parameters:
1945 - in: "body"
1946 name: "body"
1947 description: "bar object"
1948 required: true
1949 schema:
1950 $ref: "#/definitions/Bar"
1951 responses:
1952 200:
1953 description: "OK"
1954 definitions:
1955 Foo:
1956 type: "object"
1957 properties:
1958 id:
1959 type: "integer"
1960 format: "int64"
1961 Bar:
1962 type: "object"
1963 properties:
1964 id:
1965 type: "integer"
1966 format: "int64"
1967 `), &expected)
1968
1969 ast := assert.New(t)
1970 actual, _ := cloneSpec(fooSpec)
1971 orig_barSpec, _ := cloneSpec(barSpec)
1972 if !ast.Error(MergeSpecs(actual, barSpec)) {
1973 return
1974 }
1975 ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
1976
1977 actual, _ = cloneSpec(fooSpec)
1978 if !ast.NoError(MergeSpecsIgnorePathConflictDeprecated(actual, barSpec)) {
1979 return
1980 }
1981 ast.Equal(DebugSpec{expected}, DebugSpec{actual})
1982 ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
1983 }
1984
1985 func TestMergeSpecsIgnorePathConflictsAllConflicting(t *testing.T) {
1986 var fooSpec *spec.Swagger
1987 yaml.Unmarshal([]byte(`
1988 swagger: "2.0"
1989 paths:
1990 /foo:
1991 post:
1992 summary: "Foo API"
1993 operationId: "fooTest"
1994 parameters:
1995 - in: "body"
1996 name: "body"
1997 description: "foo object"
1998 required: true
1999 schema:
2000 $ref: "#/definitions/Foo"
2001 responses:
2002 200:
2003 description: "OK"
2004 definitions:
2005 Foo:
2006 type: "object"
2007 properties:
2008 id:
2009 type: "integer"
2010 format: "int64"
2011 `), &fooSpec)
2012
2013 ast := assert.New(t)
2014 foo2Spec, _ := cloneSpec(fooSpec)
2015 actual, _ := cloneSpec(fooSpec)
2016 if !ast.NoError(MergeSpecsIgnorePathConflictRenamingDefinitionsAndParameters(actual, foo2Spec)) {
2017 return
2018 }
2019 ast.Equal(DebugSpec{fooSpec}, DebugSpec{actual})
2020 ast.Equal(DebugSpec{fooSpec}, DebugSpec{foo2Spec}, "unexpected mutation of input")
2021 }
2022
2023 func TestMergeSpecsIgnorePathConflictsWithKubeSpec(t *testing.T) {
2024 ast := assert.New(t)
2025
2026 specs, expected := loadTestData()
2027 sp, specs := specs[0], specs[1:]
2028
2029 origSpecs := make([]*spec.Swagger, len(specs))
2030 for i := range specs {
2031 cpy, err := cloneSpec(specs[i])
2032 if err != nil {
2033 t.Fatal(err)
2034 }
2035 ast.NoError(err)
2036 origSpecs[i] = cpy
2037 }
2038
2039 for i := range specs {
2040 if err := MergeSpecsIgnorePathConflictRenamingDefinitionsAndParameters(sp, specs[i]); err != nil {
2041 t.Fatalf("merging spec %d failed: %v", i, err)
2042 }
2043 }
2044
2045 ast.Equal(DebugSpec{expected}, DebugSpec{sp})
2046
2047 for i := range specs {
2048 ast.Equal(DebugSpec{origSpecs[i]}, DebugSpec{specs[i]}, "unexpected mutation of specs[%d]", i)
2049 }
2050 }
2051
2052 func BenchmarkMergeSpecsIgnorePathConflictsWithKubeSpec(b *testing.B) {
2053 b.StopTimer()
2054 b.ReportAllocs()
2055 b.ResetTimer()
2056
2057 specs, _ := loadTestData()
2058 start, specs := specs[0], specs[1:]
2059
2060 for n := 0; n < b.N; n++ {
2061 sp, err := cloneSpec(start)
2062 if err != nil {
2063 b.Fatal(err)
2064 }
2065
2066 b.StartTimer()
2067 for i := range specs {
2068 if err := MergeSpecsIgnorePathConflictRenamingDefinitionsAndParameters(sp, specs[i]); err != nil {
2069 panic(err)
2070 }
2071 }
2072
2073 specBytes, _ := sp.MarshalJSON()
2074 handler.ToProtoBinary(specBytes)
2075
2076 b.StopTimer()
2077 }
2078 }
2079
2080 func TestMergeSpecReplacesAllPossibleRefs(t *testing.T) {
2081 var spec1, spec2, expected *spec.Swagger
2082 yaml.Unmarshal([]byte(`
2083 swagger: "2.0"
2084 paths:
2085 /test:
2086 post:
2087 parameters:
2088 - name: "body"
2089 schema:
2090 $ref: "#/definitions/Test"
2091 definitions:
2092 Test:
2093 type: "object"
2094 properties:
2095 foo:
2096 $ref: "#/definitions/TestProperty"
2097 TestProperty:
2098 type: "object"
2099 `), &spec1)
2100
2101 yaml.Unmarshal([]byte(`
2102 swagger: "2.0"
2103 paths:
2104 /test2:
2105 post:
2106 parameters:
2107 - name: "test2"
2108 schema:
2109 $ref: "#/definitions/Test2"
2110 - name: "test3"
2111 schema:
2112 $ref: "#/definitions/Test3"
2113 - name: "test4"
2114 schema:
2115 $ref: "#/definitions/Test4"
2116 - name: "test5"
2117 schema:
2118 $ref: "#/definitions/Test5"
2119 definitions:
2120 Test2:
2121 $ref: "#/definitions/TestProperty"
2122 Test3:
2123 type: "object"
2124 properties:
2125 withRef:
2126 $ref: "#/definitions/TestProperty"
2127 withAllOf:
2128 type: "object"
2129 allOf:
2130 - $ref: "#/definitions/TestProperty"
2131 - type: object
2132 properties:
2133 test:
2134 $ref: "#/definitions/TestProperty"
2135 withAnyOf:
2136 type: "object"
2137 anyOf:
2138 - $ref: "#/definitions/TestProperty"
2139 - type: object
2140 properties:
2141 test:
2142 $ref: "#/definitions/TestProperty"
2143 withOneOf:
2144 type: "object"
2145 oneOf:
2146 - $ref: "#/definitions/TestProperty"
2147 - type: object
2148 properties:
2149 test:
2150 $ref: "#/definitions/TestProperty"
2151 withNot:
2152 type: "object"
2153 not:
2154 $ref: "#/definitions/TestProperty"
2155 patternProperties:
2156 "prefix.*":
2157 $ref: "#/definitions/TestProperty"
2158 additionalProperties:
2159 $ref: "#/definitions/TestProperty"
2160 definitions:
2161 SomeDefinition:
2162 $ref: "#/definitions/TestProperty"
2163 Test4:
2164 type: "array"
2165 items:
2166 $ref: "#/definitions/TestProperty"
2167 additionalItems:
2168 $ref: "#/definitions/TestProperty"
2169 Test5:
2170 type: "array"
2171 items:
2172 - $ref: "#/definitions/TestProperty"
2173 - $ref: "#/definitions/TestProperty"
2174 TestProperty:
2175 description: "This TestProperty is different from the one in spec1"
2176 type: "object"
2177 `), &spec2)
2178
2179 yaml.Unmarshal([]byte(`
2180 swagger: "2.0"
2181 paths:
2182 /test:
2183 post:
2184 parameters:
2185 - name: "body"
2186 schema:
2187 $ref: "#/definitions/Test"
2188 /test2:
2189 post:
2190 parameters:
2191 - name: "test2"
2192 schema:
2193 $ref: "#/definitions/Test2"
2194 - name: "test3"
2195 schema:
2196 $ref: "#/definitions/Test3"
2197 - name: "test4"
2198 schema:
2199 $ref: "#/definitions/Test4"
2200 - name: "test5"
2201 schema:
2202 $ref: "#/definitions/Test5"
2203 definitions:
2204 Test:
2205 type: "object"
2206 properties:
2207 foo:
2208 $ref: "#/definitions/TestProperty"
2209 TestProperty:
2210 type: "object"
2211 Test2:
2212 $ref: "#/definitions/TestProperty_v2"
2213 Test3:
2214 type: "object"
2215 properties:
2216 withRef:
2217 $ref: "#/definitions/TestProperty_v2"
2218 withAllOf:
2219 type: "object"
2220 allOf:
2221 - $ref: "#/definitions/TestProperty_v2"
2222 - type: object
2223 properties:
2224 test:
2225 $ref: "#/definitions/TestProperty_v2"
2226 withAnyOf:
2227 type: "object"
2228 anyOf:
2229 - $ref: "#/definitions/TestProperty_v2"
2230 - type: object
2231 properties:
2232 test:
2233 $ref: "#/definitions/TestProperty_v2"
2234 withOneOf:
2235 type: "object"
2236 oneOf:
2237 - $ref: "#/definitions/TestProperty_v2"
2238 - type: object
2239 properties:
2240 test:
2241 $ref: "#/definitions/TestProperty_v2"
2242 withNot:
2243 type: "object"
2244 not:
2245 $ref: "#/definitions/TestProperty_v2"
2246 patternProperties:
2247 "prefix.*":
2248 $ref: "#/definitions/TestProperty_v2"
2249 additionalProperties:
2250 $ref: "#/definitions/TestProperty_v2"
2251 definitions:
2252 SomeDefinition:
2253 $ref: "#/definitions/TestProperty_v2"
2254 Test4:
2255 type: "array"
2256 items:
2257 $ref: "#/definitions/TestProperty_v2"
2258 additionalItems:
2259 $ref: "#/definitions/TestProperty_v2"
2260 Test5:
2261 type: "array"
2262 items:
2263 - $ref: "#/definitions/TestProperty_v2"
2264 - $ref: "#/definitions/TestProperty_v2"
2265 TestProperty_v2:
2266 description: "This TestProperty is different from the one in spec1"
2267 type: "object"
2268 `), &expected)
2269
2270 ast := assert.New(t)
2271 orig_spec2, _ := cloneSpec(spec2)
2272 if !ast.NoError(MergeSpecs(spec1, spec2)) {
2273 return
2274 }
2275 ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
2276 ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
2277 }
2278
2279 func loadTestData() ([]*spec.Swagger, *spec.Swagger) {
2280 loadSpec := func(fileName string) *spec.Swagger {
2281 bs, err := os.ReadFile(filepath.Join("../../test/integration/testdata/aggregator", fileName))
2282 if err != nil {
2283 panic(err)
2284 }
2285 sp := spec.Swagger{}
2286
2287 if err := json.Unmarshal(bs, &sp); err != nil {
2288 panic(err)
2289 }
2290 return &sp
2291 }
2292
2293 specs := []*spec.Swagger{
2294 loadSpec("openapi-0.json"),
2295 loadSpec("openapi-1.json"),
2296 loadSpec("openapi-2.json"),
2297 }
2298 expected := loadSpec("openapi.json")
2299
2300 return specs, expected
2301 }
2302
2303 func TestCloneSpec(t *testing.T) {
2304 _, sp := loadTestData()
2305 clone, err := cloneSpec(sp)
2306 if err != nil {
2307 t.Fatalf("unexpected error: %v", err)
2308 }
2309 ast := assert.New(t)
2310 ast.Equal(DebugSpec{sp}, DebugSpec{clone})
2311 }
2312
2313 func cloneSpec(source *spec.Swagger) (*spec.Swagger, error) {
2314 bytes, err := source.MarshalJSON()
2315 if err != nil {
2316 return nil, err
2317 }
2318 var ret spec.Swagger
2319 err = json.Unmarshal(bytes, &ret)
2320 if err != nil {
2321 return nil, err
2322 }
2323 return &ret, nil
2324 }
2325
2326 func TestMergedGVKs(t *testing.T) {
2327 gvk1 := map[string]interface{}{"group": "group1", "version": "v1", "kind": "Foo"}
2328 gvk2 := map[string]interface{}{"group": "group2", "version": "v1", "kind": "Bar"}
2329 gvk3 := map[string]interface{}{"group": "group3", "version": "v1", "kind": "Abc"}
2330 gvk4 := map[string]interface{}{"group": "group4", "version": "v1", "kind": "Abc"}
2331
2332 tests := []struct {
2333 name string
2334 gvks1 interface{}
2335 gvks2 interface{}
2336 want interface{}
2337 wantChanged bool
2338 wantErr bool
2339 }{
2340 {"nil", nil, nil, nil, false, false},
2341 {"first only", []interface{}{gvk1, gvk2}, nil, []interface{}{gvk1, gvk2}, false, false},
2342 {"second only", nil, []interface{}{gvk1, gvk2}, []interface{}{gvk1, gvk2}, true, false},
2343 {"both", []interface{}{gvk1, gvk2}, []interface{}{gvk3}, []interface{}{gvk1, gvk2, gvk3}, true, false},
2344 {"equal, different order", []interface{}{gvk1, gvk2, gvk3}, []interface{}{gvk3, gvk2, gvk1}, []interface{}{gvk1, gvk2, gvk3}, false, false},
2345 {"ordered", []interface{}{gvk3, gvk1, gvk4}, []interface{}{gvk2}, []interface{}{gvk1, gvk2, gvk3, gvk4}, true, false},
2346 {"not ordered when not changed", []interface{}{gvk3, gvk1, gvk4}, []interface{}{}, []interface{}{gvk3, gvk1, gvk4}, false, false},
2347 {"empty", []interface{}{}, []interface{}{}, []interface{}{}, false, false},
2348 {"overlapping", []interface{}{gvk1, gvk2}, []interface{}{gvk2, gvk3}, []interface{}{gvk1, gvk2, gvk3}, true, false},
2349 {"first no slice", 42, []interface{}{gvk1}, nil, false, true},
2350 {"second no slice", []interface{}{gvk1}, 42, nil, false, true},
2351 {"no map in slice", []interface{}{42}, []interface{}{gvk1}, nil, false, true},
2352 }
2353 for _, tt := range tests {
2354 t.Run(tt.name, func(t *testing.T) {
2355 var ext1, ext2 map[string]interface{}
2356 if tt.gvks1 != nil {
2357 ext1 = map[string]interface{}{"x-kubernetes-group-version-kind": tt.gvks1}
2358 }
2359 if tt.gvks2 != nil {
2360 ext2 = map[string]interface{}{"x-kubernetes-group-version-kind": tt.gvks2}
2361 }
2362
2363 got, gotChanged, gotErr := mergedGVKs(
2364 &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: ext1}},
2365 &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: ext2}},
2366 )
2367 if (gotErr != nil) != tt.wantErr {
2368 t.Errorf("mergedGVKs() error = %v, wantErr %v", gotErr, tt.wantErr)
2369 return
2370 }
2371 if gotChanged != tt.wantChanged {
2372 t.Errorf("mergedGVKs() changed = %v, want %v", gotChanged, tt.wantChanged)
2373 }
2374 if !reflect.DeepEqual(got, tt.want) {
2375 t.Errorf("mergedGVKs() got = %v, want %v", got, tt.want)
2376 }
2377 })
2378 }
2379 }
2380
2381 func TestDeepEqualDefinitionsModuloGVKs(t *testing.T) {
2382 tests := []struct {
2383 name string
2384 s1 *spec.Schema
2385 s2 *spec.Schema
2386 equal bool
2387 }{
2388 {name: "nil", equal: true},
2389 {name: "nil, non-nil", s1: nil, s2: &spec.Schema{}},
2390 {name: "equal", s1: &spec.Schema{}, s2: &spec.Schema{}, equal: true},
2391 {name: "different", s1: &spec.Schema{SchemaProps: spec.SchemaProps{ID: "abc"}}, s2: &spec.Schema{}},
2392 {name: "equal modulo: nil, empty",
2393 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: nil}},
2394 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{}}},
2395 equal: true,
2396 },
2397 {name: "equal modulo: nil, gvk",
2398 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: nil}},
2399 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2400 gvkKey: true,
2401 }}},
2402 equal: true,
2403 },
2404 {name: "equal modulo: empty, gvk",
2405 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{}}},
2406 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2407 gvkKey: true,
2408 }}},
2409 equal: true,
2410 },
2411 {name: "equal modulo: non-empty, gvk",
2412 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{"foo": "bar"}}},
2413 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2414 gvkKey: true,
2415 "foo": "bar",
2416 }}},
2417 equal: true,
2418 },
2419 {name: "equal modulo: gvk, gvk",
2420 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2421 gvkKey: false,
2422 "foo": "bar",
2423 }}},
2424 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2425 gvkKey: true,
2426 "foo": "bar",
2427 }}},
2428 equal: true,
2429 },
2430 {name: "different values",
2431 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2432 gvkKey: false,
2433 "foo": "bar",
2434 }}},
2435 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2436 gvkKey: true,
2437 "foo": "abc",
2438 }}},
2439 },
2440 {name: "different sizes",
2441 s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2442 gvkKey: false,
2443 "foo": "bar",
2444 "xyz": "123",
2445 }}},
2446 s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
2447 gvkKey: true,
2448 "foo": "abc",
2449 }}},
2450 },
2451 }
2452 for _, tt := range tests {
2453 t.Run(tt.name, func(t *testing.T) {
2454 if got := deepEqualDefinitionsModuloGVKs(tt.s1, tt.s2); got != tt.equal {
2455 t.Errorf("deepEqualDefinitionsModuloGVKs(s1, v2) = %v, want %v", got, tt.equal)
2456 }
2457
2458 if got := deepEqualDefinitionsModuloGVKs(tt.s2, tt.s1); got != tt.equal {
2459 t.Errorf("deepEqualDefinitionsModuloGVKs(s2, s1) = %v, want %v", got, tt.equal)
2460 }
2461 })
2462 }
2463 }
2464
View as plain text