package terraform import ( "testing" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty" ) func TestProcessIgnoreChangesIndividual(t *testing.T) { tests := map[string]struct { Old, New cty.Value Ignore []string Want cty.Value }{ "string": { cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("a value"), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("new a value"), "b": cty.StringVal("new b value"), }), []string{"a"}, cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("a value"), "b": cty.StringVal("new b value"), }), }, "changed type": { cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("a value"), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.NumberIntVal(1), "b": cty.StringVal("new b value"), }), []string{"a"}, cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("a value"), "b": cty.StringVal("new b value"), }), }, "list": { cty.ObjectVal(map[string]cty.Value{ "a": cty.ListVal([]cty.Value{ cty.StringVal("a0 value"), cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.ListVal([]cty.Value{ cty.StringVal("new a0 value"), cty.StringVal("new a1 value"), }), "b": cty.StringVal("new b value"), }), []string{"a"}, cty.ObjectVal(map[string]cty.Value{ "a": cty.ListVal([]cty.Value{ cty.StringVal("a0 value"), cty.StringVal("a1 value"), }), "b": cty.StringVal("new b value"), }), }, "list_index": { cty.ObjectVal(map[string]cty.Value{ "a": cty.ListVal([]cty.Value{ cty.StringVal("a0 value"), cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.ListVal([]cty.Value{ cty.StringVal("new a0 value"), cty.StringVal("new a1 value"), }), "b": cty.StringVal("new b value"), }), []string{"a[1]"}, cty.ObjectVal(map[string]cty.Value{ "a": cty.ListVal([]cty.Value{ cty.StringVal("new a0 value"), cty.StringVal("a1 value"), }), "b": cty.StringVal("new b value"), }), }, "map_index": { cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("a0 value"), "a1": cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("new a0 value"), "a1": cty.StringVal("new a1 value"), }), "b": cty.StringVal("b value"), }), []string{`a["a1"]`}, cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("new a0 value"), "a1": cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), }, "map_index_no_config": { cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("a0 value"), "a1": cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.NullVal(cty.Map(cty.String)), "b": cty.StringVal("b value"), }), []string{`a["a1"]`}, cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a1": cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), }, "missing_map_index": { cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("a0 value"), "a1": cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.MapValEmpty(cty.String), "b": cty.StringVal("b value"), }), []string{`a["a1"]`}, cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a1": cty.StringVal("a1 value"), }), "b": cty.StringVal("b value"), }), }, "missing_map_index_empty": { cty.ObjectVal(map[string]cty.Value{ "a": cty.MapValEmpty(cty.String), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a": cty.StringVal("a0 value"), }), }), []string{`a["a"]`}, cty.ObjectVal(map[string]cty.Value{ "a": cty.MapValEmpty(cty.String), }), }, "missing_map_index_to_object": { cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a": cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("aa0"), "b": cty.StringVal("ab0"), }), "b": cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("ba0"), "b": cty.StringVal("bb0"), }), }), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.MapValEmpty( cty.Object(map[string]cty.Type{ "a": cty.String, "b": cty.String, }), ), }), // we expect the config to be used here, as the ignore changes was // `a["a"].b`, but the change was larger than that removing // `a["a"]` entirely. []string{`a["a"].b`}, cty.ObjectVal(map[string]cty.Value{ "a": cty.MapValEmpty( cty.Object(map[string]cty.Type{ "a": cty.String, "b": cty.String, }), ), }), }, "missing_prior_map_index": { cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("a0 value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("a0 value"), "a1": cty.StringVal("new a1 value"), }), "b": cty.StringVal("b value"), }), []string{`a["a1"]`}, cty.ObjectVal(map[string]cty.Value{ "a": cty.MapVal(map[string]cty.Value{ "a0": cty.StringVal("a0 value"), }), "b": cty.StringVal("b value"), }), }, "object attribute": { cty.ObjectVal(map[string]cty.Value{ "a": cty.ObjectVal(map[string]cty.Value{ "foo": cty.StringVal("a.foo value"), "bar": cty.StringVal("a.bar value"), }), "b": cty.StringVal("b value"), }), cty.ObjectVal(map[string]cty.Value{ "a": cty.ObjectVal(map[string]cty.Value{ "foo": cty.StringVal("new a.foo value"), "bar": cty.StringVal("new a.bar value"), }), "b": cty.StringVal("new b value"), }), []string{"a.bar"}, cty.ObjectVal(map[string]cty.Value{ "a": cty.ObjectVal(map[string]cty.Value{ "foo": cty.StringVal("new a.foo value"), "bar": cty.StringVal("a.bar value"), }), "b": cty.StringVal("new b value"), }), }, } for name, test := range tests { t.Run(name, func(t *testing.T) { ignore := make([]hcl.Traversal, len(test.Ignore)) for i, ignoreStr := range test.Ignore { trav, diags := hclsyntax.ParseTraversalAbs([]byte(ignoreStr), "", hcl.Pos{Line: 1, Column: 1}) if diags.HasErrors() { t.Fatalf("failed to parse %q: %s", ignoreStr, diags.Error()) } ignore[i] = trav } ret, diags := processIgnoreChangesIndividual(test.Old, test.New, ignore) if diags.HasErrors() { t.Fatal(diags.Err()) } if got, want := ret, test.Want; !want.RawEquals(got) { t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want) } }) } }