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 }