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