github.com/opentofu/opentofu@v1.7.1/internal/legacy/helper/schema/field_reader_multi_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package schema
     7  
     8  import (
     9  	"reflect"
    10  	"strconv"
    11  	"testing"
    12  
    13  	"github.com/opentofu/opentofu/internal/legacy/tofu"
    14  )
    15  
    16  func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
    17  	cases := map[string]struct {
    18  		Addr    []string
    19  		Readers []FieldReader
    20  		Level   string
    21  		Result  FieldReadResult
    22  	}{
    23  		"specific": {
    24  			Addr: []string{"foo"},
    25  
    26  			Readers: []FieldReader{
    27  				&MapFieldReader{
    28  					Schema: map[string]*Schema{
    29  						"foo": &Schema{Type: TypeString},
    30  					},
    31  					Map: BasicMapReader(map[string]string{
    32  						"foo": "bar",
    33  					}),
    34  				},
    35  				&MapFieldReader{
    36  					Schema: map[string]*Schema{
    37  						"foo": &Schema{Type: TypeString},
    38  					},
    39  					Map: BasicMapReader(map[string]string{
    40  						"foo": "baz",
    41  					}),
    42  				},
    43  				&MapFieldReader{
    44  					Schema: map[string]*Schema{
    45  						"foo": &Schema{Type: TypeString},
    46  					},
    47  					Map: BasicMapReader(map[string]string{}),
    48  				},
    49  			},
    50  
    51  			Level: "1",
    52  			Result: FieldReadResult{
    53  				Value:  "baz",
    54  				Exists: true,
    55  			},
    56  		},
    57  	}
    58  
    59  	for name, tc := range cases {
    60  		readers := make(map[string]FieldReader)
    61  		levels := make([]string, len(tc.Readers))
    62  		for i, r := range tc.Readers {
    63  			is := strconv.FormatInt(int64(i), 10)
    64  			readers[is] = r
    65  			levels[i] = is
    66  		}
    67  
    68  		r := &MultiLevelFieldReader{
    69  			Readers: readers,
    70  			Levels:  levels,
    71  		}
    72  
    73  		out, err := r.ReadFieldExact(tc.Addr, tc.Level)
    74  		if err != nil {
    75  			t.Fatalf("%s: err: %s", name, err)
    76  		}
    77  
    78  		if !reflect.DeepEqual(tc.Result, out) {
    79  			t.Fatalf("%s: bad: %#v", name, out)
    80  		}
    81  	}
    82  }
    83  
    84  func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
    85  	cases := map[string]struct {
    86  		Addr    []string
    87  		Readers []FieldReader
    88  		Result  FieldReadResult
    89  	}{
    90  		"stringInDiff": {
    91  			Addr: []string{"availability_zone"},
    92  
    93  			Readers: []FieldReader{
    94  				&DiffFieldReader{
    95  					Schema: map[string]*Schema{
    96  						"availability_zone": &Schema{Type: TypeString},
    97  					},
    98  
    99  					Source: &MapFieldReader{
   100  						Schema: map[string]*Schema{
   101  							"availability_zone": &Schema{Type: TypeString},
   102  						},
   103  						Map: BasicMapReader(map[string]string{
   104  							"availability_zone": "foo",
   105  						}),
   106  					},
   107  
   108  					Diff: &tofu.InstanceDiff{
   109  						Attributes: map[string]*tofu.ResourceAttrDiff{
   110  							"availability_zone": &tofu.ResourceAttrDiff{
   111  								Old:         "foo",
   112  								New:         "bar",
   113  								RequiresNew: true,
   114  							},
   115  						},
   116  					},
   117  				},
   118  			},
   119  
   120  			Result: FieldReadResult{
   121  				Value:  "bar",
   122  				Exists: true,
   123  			},
   124  		},
   125  
   126  		"lastLevelComputed": {
   127  			Addr: []string{"availability_zone"},
   128  
   129  			Readers: []FieldReader{
   130  				&MapFieldReader{
   131  					Schema: map[string]*Schema{
   132  						"availability_zone": &Schema{Type: TypeString},
   133  					},
   134  
   135  					Map: BasicMapReader(map[string]string{
   136  						"availability_zone": "foo",
   137  					}),
   138  				},
   139  
   140  				&DiffFieldReader{
   141  					Schema: map[string]*Schema{
   142  						"availability_zone": &Schema{Type: TypeString},
   143  					},
   144  
   145  					Source: &MapFieldReader{
   146  						Schema: map[string]*Schema{
   147  							"availability_zone": &Schema{Type: TypeString},
   148  						},
   149  
   150  						Map: BasicMapReader(map[string]string{
   151  							"availability_zone": "foo",
   152  						}),
   153  					},
   154  
   155  					Diff: &tofu.InstanceDiff{
   156  						Attributes: map[string]*tofu.ResourceAttrDiff{
   157  							"availability_zone": &tofu.ResourceAttrDiff{
   158  								Old:         "foo",
   159  								New:         "bar",
   160  								NewComputed: true,
   161  							},
   162  						},
   163  					},
   164  				},
   165  			},
   166  
   167  			Result: FieldReadResult{
   168  				Value:    "",
   169  				Exists:   true,
   170  				Computed: true,
   171  			},
   172  		},
   173  
   174  		"list of maps with removal in diff": {
   175  			Addr: []string{"config_vars"},
   176  
   177  			Readers: []FieldReader{
   178  				&DiffFieldReader{
   179  					Schema: map[string]*Schema{
   180  						"config_vars": &Schema{
   181  							Type: TypeList,
   182  							Elem: &Schema{Type: TypeMap},
   183  						},
   184  					},
   185  
   186  					Source: &MapFieldReader{
   187  						Schema: map[string]*Schema{
   188  							"config_vars": &Schema{
   189  								Type: TypeList,
   190  								Elem: &Schema{Type: TypeMap},
   191  							},
   192  						},
   193  
   194  						Map: BasicMapReader(map[string]string{
   195  							"config_vars.#":     "2",
   196  							"config_vars.0.foo": "bar",
   197  							"config_vars.0.bar": "bar",
   198  							"config_vars.1.bar": "baz",
   199  						}),
   200  					},
   201  
   202  					Diff: &tofu.InstanceDiff{
   203  						Attributes: map[string]*tofu.ResourceAttrDiff{
   204  							"config_vars.0.bar": &tofu.ResourceAttrDiff{
   205  								NewRemoved: true,
   206  							},
   207  						},
   208  					},
   209  				},
   210  			},
   211  
   212  			Result: FieldReadResult{
   213  				Value: []interface{}{
   214  					map[string]interface{}{
   215  						"foo": "bar",
   216  					},
   217  					map[string]interface{}{
   218  						"bar": "baz",
   219  					},
   220  				},
   221  				Exists: true,
   222  			},
   223  		},
   224  
   225  		"first level only": {
   226  			Addr: []string{"foo"},
   227  
   228  			Readers: []FieldReader{
   229  				&MapFieldReader{
   230  					Schema: map[string]*Schema{
   231  						"foo": &Schema{Type: TypeString},
   232  					},
   233  					Map: BasicMapReader(map[string]string{
   234  						"foo": "bar",
   235  					}),
   236  				},
   237  				&MapFieldReader{
   238  					Schema: map[string]*Schema{
   239  						"foo": &Schema{Type: TypeString},
   240  					},
   241  					Map: BasicMapReader(map[string]string{}),
   242  				},
   243  			},
   244  
   245  			Result: FieldReadResult{
   246  				Value:  "bar",
   247  				Exists: true,
   248  			},
   249  		},
   250  	}
   251  
   252  	for name, tc := range cases {
   253  		readers := make(map[string]FieldReader)
   254  		levels := make([]string, len(tc.Readers))
   255  		for i, r := range tc.Readers {
   256  			is := strconv.FormatInt(int64(i), 10)
   257  			readers[is] = r
   258  			levels[i] = is
   259  		}
   260  
   261  		r := &MultiLevelFieldReader{
   262  			Readers: readers,
   263  			Levels:  levels,
   264  		}
   265  
   266  		out, err := r.ReadFieldMerge(tc.Addr, levels[len(levels)-1])
   267  		if err != nil {
   268  			t.Fatalf("%s: err: %s", name, err)
   269  		}
   270  
   271  		if !reflect.DeepEqual(tc.Result, out) {
   272  			t.Fatalf("%s: bad: %#v", name, out)
   273  		}
   274  	}
   275  }