github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/terraform/reduce_plan_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package terraform 5 6 import ( 7 "testing" 8 9 "github.com/hashicorp/hcl/v2" 10 "github.com/hashicorp/hcl/v2/hclsyntax" 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 func TestProcessIgnoreChangesIndividual(t *testing.T) { 15 tests := map[string]struct { 16 Old, New cty.Value 17 Ignore []string 18 Want cty.Value 19 }{ 20 "string": { 21 cty.ObjectVal(map[string]cty.Value{ 22 "a": cty.StringVal("a value"), 23 "b": cty.StringVal("b value"), 24 }), 25 cty.ObjectVal(map[string]cty.Value{ 26 "a": cty.StringVal("new a value"), 27 "b": cty.StringVal("new b value"), 28 }), 29 []string{"a"}, 30 cty.ObjectVal(map[string]cty.Value{ 31 "a": cty.StringVal("a value"), 32 "b": cty.StringVal("new b value"), 33 }), 34 }, 35 "changed type": { 36 cty.ObjectVal(map[string]cty.Value{ 37 "a": cty.StringVal("a value"), 38 "b": cty.StringVal("b value"), 39 }), 40 cty.ObjectVal(map[string]cty.Value{ 41 "a": cty.NumberIntVal(1), 42 "b": cty.StringVal("new b value"), 43 }), 44 []string{"a"}, 45 cty.ObjectVal(map[string]cty.Value{ 46 "a": cty.StringVal("a value"), 47 "b": cty.StringVal("new b value"), 48 }), 49 }, 50 "list": { 51 cty.ObjectVal(map[string]cty.Value{ 52 "a": cty.ListVal([]cty.Value{ 53 cty.StringVal("a0 value"), 54 cty.StringVal("a1 value"), 55 }), 56 "b": cty.StringVal("b value"), 57 }), 58 cty.ObjectVal(map[string]cty.Value{ 59 "a": cty.ListVal([]cty.Value{ 60 cty.StringVal("new a0 value"), 61 cty.StringVal("new a1 value"), 62 }), 63 "b": cty.StringVal("new b value"), 64 }), 65 []string{"a"}, 66 cty.ObjectVal(map[string]cty.Value{ 67 "a": cty.ListVal([]cty.Value{ 68 cty.StringVal("a0 value"), 69 cty.StringVal("a1 value"), 70 }), 71 "b": cty.StringVal("new b value"), 72 }), 73 }, 74 "list_index": { 75 cty.ObjectVal(map[string]cty.Value{ 76 "a": cty.ListVal([]cty.Value{ 77 cty.StringVal("a0 value"), 78 cty.StringVal("a1 value"), 79 }), 80 "b": cty.StringVal("b value"), 81 }), 82 cty.ObjectVal(map[string]cty.Value{ 83 "a": cty.ListVal([]cty.Value{ 84 cty.StringVal("new a0 value"), 85 cty.StringVal("new a1 value"), 86 }), 87 "b": cty.StringVal("new b value"), 88 }), 89 []string{"a[1]"}, 90 cty.ObjectVal(map[string]cty.Value{ 91 "a": cty.ListVal([]cty.Value{ 92 cty.StringVal("new a0 value"), 93 cty.StringVal("a1 value"), 94 }), 95 "b": cty.StringVal("new b value"), 96 }), 97 }, 98 "map": { 99 cty.ObjectVal(map[string]cty.Value{ 100 "a": cty.MapVal(map[string]cty.Value{ 101 "a0": cty.StringVal("a0 value"), 102 "a1": cty.StringVal("a1 value"), 103 }), 104 "b": cty.StringVal("b value"), 105 }), 106 cty.ObjectVal(map[string]cty.Value{ 107 "a": cty.MapVal(map[string]cty.Value{ 108 "a0": cty.StringVal("new a0 value"), 109 "a1": cty.UnknownVal(cty.String), 110 }), 111 "b": cty.StringVal("b value"), 112 }), 113 []string{`a`}, 114 cty.ObjectVal(map[string]cty.Value{ 115 "a": cty.MapVal(map[string]cty.Value{ 116 "a0": cty.StringVal("a0 value"), 117 "a1": cty.StringVal("a1 value"), 118 }), 119 "b": cty.StringVal("b value"), 120 }), 121 }, 122 "map_index": { 123 cty.ObjectVal(map[string]cty.Value{ 124 "a": cty.MapVal(map[string]cty.Value{ 125 "a0": cty.StringVal("a0 value"), 126 "a1": cty.StringVal("a1 value"), 127 }), 128 "b": cty.StringVal("b value"), 129 }), 130 cty.ObjectVal(map[string]cty.Value{ 131 "a": cty.MapVal(map[string]cty.Value{ 132 "a0": cty.StringVal("new a0 value"), 133 "a1": cty.StringVal("new a1 value"), 134 }), 135 "b": cty.StringVal("b value"), 136 }), 137 []string{`a["a1"]`}, 138 cty.ObjectVal(map[string]cty.Value{ 139 "a": cty.MapVal(map[string]cty.Value{ 140 "a0": cty.StringVal("new a0 value"), 141 "a1": cty.StringVal("a1 value"), 142 }), 143 "b": cty.StringVal("b value"), 144 }), 145 }, 146 "map_index_no_config": { 147 cty.ObjectVal(map[string]cty.Value{ 148 "a": cty.MapVal(map[string]cty.Value{ 149 "a0": cty.StringVal("a0 value"), 150 "a1": cty.StringVal("a1 value"), 151 }), 152 "b": cty.StringVal("b value"), 153 }), 154 cty.ObjectVal(map[string]cty.Value{ 155 "a": cty.NullVal(cty.Map(cty.String)), 156 "b": cty.StringVal("b value"), 157 }), 158 []string{`a["a1"]`}, 159 cty.ObjectVal(map[string]cty.Value{ 160 "a": cty.MapVal(map[string]cty.Value{ 161 "a1": cty.StringVal("a1 value"), 162 }), 163 "b": cty.StringVal("b value"), 164 }), 165 }, 166 "map_index_unknown_value": { 167 cty.ObjectVal(map[string]cty.Value{ 168 "a": cty.MapVal(map[string]cty.Value{ 169 "a0": cty.StringVal("a0 value"), 170 "a1": cty.StringVal("a1 value"), 171 }), 172 "b": cty.StringVal("b value"), 173 }), 174 cty.ObjectVal(map[string]cty.Value{ 175 "a": cty.MapVal(map[string]cty.Value{ 176 "a0": cty.StringVal("a0 value"), 177 "a1": cty.UnknownVal(cty.String), 178 }), 179 "b": cty.StringVal("b value"), 180 }), 181 []string{`a["a1"]`}, 182 cty.ObjectVal(map[string]cty.Value{ 183 "a": cty.MapVal(map[string]cty.Value{ 184 "a0": cty.StringVal("a0 value"), 185 "a1": cty.StringVal("a1 value"), 186 }), 187 "b": cty.StringVal("b value"), 188 }), 189 }, 190 "map_index_multiple_keys": { 191 cty.ObjectVal(map[string]cty.Value{ 192 "a": cty.MapVal(map[string]cty.Value{ 193 "a0": cty.StringVal("a0 value"), 194 "a1": cty.StringVal("a1 value"), 195 "a2": cty.StringVal("a2 value"), 196 "a3": cty.StringVal("a3 value"), 197 }), 198 "b": cty.StringVal("b value"), 199 }), 200 cty.ObjectVal(map[string]cty.Value{ 201 "a": cty.NullVal(cty.Map(cty.String)), 202 "b": cty.StringVal("new b value"), 203 }), 204 []string{`a["a1"]`, `a["a2"]`, `a["a3"]`, `b`}, 205 cty.ObjectVal(map[string]cty.Value{ 206 "a": cty.MapVal(map[string]cty.Value{ 207 "a1": cty.StringVal("a1 value"), 208 "a2": cty.StringVal("a2 value"), 209 "a3": cty.StringVal("a3 value"), 210 }), 211 "b": cty.StringVal("b value"), 212 }), 213 }, 214 "map_index_redundant": { 215 cty.ObjectVal(map[string]cty.Value{ 216 "a": cty.MapVal(map[string]cty.Value{ 217 "a0": cty.StringVal("a0 value"), 218 "a1": cty.StringVal("a1 value"), 219 "a2": cty.StringVal("a2 value"), 220 }), 221 "b": cty.StringVal("b value"), 222 }), 223 cty.ObjectVal(map[string]cty.Value{ 224 "a": cty.NullVal(cty.Map(cty.String)), 225 "b": cty.StringVal("new b value"), 226 }), 227 []string{`a["a1"]`, `a`, `b`}, 228 cty.ObjectVal(map[string]cty.Value{ 229 "a": cty.MapVal(map[string]cty.Value{ 230 "a0": cty.StringVal("a0 value"), 231 "a1": cty.StringVal("a1 value"), 232 "a2": cty.StringVal("a2 value"), 233 }), 234 "b": cty.StringVal("b value"), 235 }), 236 }, 237 "missing_map_index": { 238 cty.ObjectVal(map[string]cty.Value{ 239 "a": cty.MapVal(map[string]cty.Value{ 240 "a0": cty.StringVal("a0 value"), 241 "a1": cty.StringVal("a1 value"), 242 }), 243 "b": cty.StringVal("b value"), 244 }), 245 cty.ObjectVal(map[string]cty.Value{ 246 "a": cty.MapValEmpty(cty.String), 247 "b": cty.StringVal("b value"), 248 }), 249 []string{`a["a1"]`}, 250 cty.ObjectVal(map[string]cty.Value{ 251 "a": cty.MapVal(map[string]cty.Value{ 252 "a1": cty.StringVal("a1 value"), 253 }), 254 "b": cty.StringVal("b value"), 255 }), 256 }, 257 "missing_map_index_empty": { 258 cty.ObjectVal(map[string]cty.Value{ 259 "a": cty.MapValEmpty(cty.String), 260 }), 261 cty.ObjectVal(map[string]cty.Value{ 262 "a": cty.MapVal(map[string]cty.Value{ 263 "a": cty.StringVal("a0 value"), 264 }), 265 }), 266 []string{`a["a"]`}, 267 cty.ObjectVal(map[string]cty.Value{ 268 "a": cty.MapValEmpty(cty.String), 269 }), 270 }, 271 "missing_map_index_to_object": { 272 cty.ObjectVal(map[string]cty.Value{ 273 "a": cty.MapVal(map[string]cty.Value{ 274 "a": cty.ObjectVal(map[string]cty.Value{ 275 "a": cty.StringVal("aa0"), 276 "b": cty.StringVal("ab0"), 277 }), 278 "b": cty.ObjectVal(map[string]cty.Value{ 279 "a": cty.StringVal("ba0"), 280 "b": cty.StringVal("bb0"), 281 }), 282 }), 283 }), 284 cty.ObjectVal(map[string]cty.Value{ 285 "a": cty.MapValEmpty( 286 cty.Object(map[string]cty.Type{ 287 "a": cty.String, 288 "b": cty.String, 289 }), 290 ), 291 }), 292 // we expect the config to be used here, as the ignore changes was 293 // `a["a"].b`, but the change was larger than that removing 294 // `a["a"]` entirely. 295 []string{`a["a"].b`}, 296 cty.ObjectVal(map[string]cty.Value{ 297 "a": cty.MapValEmpty( 298 cty.Object(map[string]cty.Type{ 299 "a": cty.String, 300 "b": cty.String, 301 }), 302 ), 303 }), 304 }, 305 "missing_prior_map_index": { 306 cty.ObjectVal(map[string]cty.Value{ 307 "a": cty.MapVal(map[string]cty.Value{ 308 "a0": cty.StringVal("a0 value"), 309 }), 310 "b": cty.StringVal("b value"), 311 }), 312 cty.ObjectVal(map[string]cty.Value{ 313 "a": cty.MapVal(map[string]cty.Value{ 314 "a0": cty.StringVal("a0 value"), 315 "a1": cty.StringVal("new a1 value"), 316 }), 317 "b": cty.StringVal("b value"), 318 }), 319 []string{`a["a1"]`}, 320 cty.ObjectVal(map[string]cty.Value{ 321 "a": cty.MapVal(map[string]cty.Value{ 322 "a0": cty.StringVal("a0 value"), 323 }), 324 "b": cty.StringVal("b value"), 325 }), 326 }, 327 "object attribute": { 328 cty.ObjectVal(map[string]cty.Value{ 329 "a": cty.ObjectVal(map[string]cty.Value{ 330 "foo": cty.StringVal("a.foo value"), 331 "bar": cty.StringVal("a.bar value"), 332 }), 333 "b": cty.StringVal("b value"), 334 }), 335 cty.ObjectVal(map[string]cty.Value{ 336 "a": cty.ObjectVal(map[string]cty.Value{ 337 "foo": cty.StringVal("new a.foo value"), 338 "bar": cty.StringVal("new a.bar value"), 339 }), 340 "b": cty.StringVal("new b value"), 341 }), 342 []string{"a.bar"}, 343 cty.ObjectVal(map[string]cty.Value{ 344 "a": cty.ObjectVal(map[string]cty.Value{ 345 "foo": cty.StringVal("new a.foo value"), 346 "bar": cty.StringVal("a.bar value"), 347 }), 348 "b": cty.StringVal("new b value"), 349 }), 350 }, 351 "unknown_object_attribute": { 352 cty.ObjectVal(map[string]cty.Value{ 353 "a": cty.ObjectVal(map[string]cty.Value{ 354 "foo": cty.StringVal("a.foo value"), 355 "bar": cty.StringVal("a.bar value"), 356 }), 357 "b": cty.StringVal("b value"), 358 }), 359 cty.ObjectVal(map[string]cty.Value{ 360 "a": cty.ObjectVal(map[string]cty.Value{ 361 "foo": cty.StringVal("new a.foo value"), 362 "bar": cty.UnknownVal(cty.String), 363 }), 364 "b": cty.StringVal("new b value"), 365 }), 366 []string{"a.bar"}, 367 cty.ObjectVal(map[string]cty.Value{ 368 "a": cty.ObjectVal(map[string]cty.Value{ 369 "foo": cty.StringVal("new a.foo value"), 370 "bar": cty.StringVal("a.bar value"), 371 }), 372 "b": cty.StringVal("new b value"), 373 }), 374 }, 375 "null_map": { 376 cty.ObjectVal(map[string]cty.Value{ 377 "a": cty.StringVal("ok"), 378 "list": cty.ListVal([]cty.Value{ 379 cty.ObjectVal(map[string]cty.Value{ 380 "s": cty.StringVal("ok"), 381 "map": cty.NullVal(cty.Map(cty.String)), 382 }), 383 }), 384 }), 385 cty.ObjectVal(map[string]cty.Value{ 386 "a": cty.NullVal(cty.String), 387 "list": cty.ListVal([]cty.Value{ 388 cty.ObjectVal(map[string]cty.Value{ 389 "s": cty.StringVal("ok"), 390 "map": cty.NullVal(cty.Map(cty.String)), 391 }), 392 }), 393 }), 394 []string{"a"}, 395 cty.ObjectVal(map[string]cty.Value{ 396 "a": cty.StringVal("ok"), 397 "list": cty.ListVal([]cty.Value{ 398 cty.ObjectVal(map[string]cty.Value{ 399 "s": cty.StringVal("ok"), 400 "map": cty.NullVal(cty.Map(cty.String)), 401 }), 402 }), 403 }), 404 }, 405 "marked_map": { 406 cty.ObjectVal(map[string]cty.Value{ 407 "map": cty.MapVal(map[string]cty.Value{ 408 "key": cty.StringVal("val"), 409 }).Mark("marked"), 410 }), 411 cty.ObjectVal(map[string]cty.Value{ 412 "map": cty.MapVal(map[string]cty.Value{ 413 "key": cty.StringVal("new val"), 414 }).Mark("marked"), 415 }), 416 []string{`map["key"]`}, 417 cty.ObjectVal(map[string]cty.Value{ 418 "map": cty.MapVal(map[string]cty.Value{ 419 "key": cty.StringVal("val"), 420 }).Mark("marked"), 421 }), 422 }, 423 } 424 425 for name, test := range tests { 426 t.Run(name, func(t *testing.T) { 427 ignore := make([]hcl.Traversal, len(test.Ignore)) 428 for i, ignoreStr := range test.Ignore { 429 trav, diags := hclsyntax.ParseTraversalAbs([]byte(ignoreStr), "", hcl.Pos{Line: 1, Column: 1}) 430 if diags.HasErrors() { 431 t.Fatalf("failed to parse %q: %s", ignoreStr, diags.Error()) 432 } 433 ignore[i] = trav 434 } 435 436 ret, diags := processIgnoreChangesIndividual(test.Old, test.New, traversalsToPaths(ignore)) 437 if diags.HasErrors() { 438 t.Fatal(diags.Err()) 439 } 440 441 if got, want := ret, test.Want; !want.RawEquals(got) { 442 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want) 443 } 444 }) 445 } 446 }