opentofu/internal/plans/changes_test.go
Alisdair McDiarmid 29999c1d6f command: Render "moved" annotations in plan UI
For resources which are planned to move, render the previous run address
as additional information in the plan UI. For the case of a move-only
resource (which otherwise is unchanged), we also render that as a
planned change, but without any corresponding action symbol.

If all changes in the plan are moves without changes, the plan is no
longer considered "empty". In this case, we skip rendering the action
symbols in the UI.
2021-09-03 17:44:07 -04:00

160 lines
3.4 KiB
Go

package plans
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/zclconf/go-cty/cty"
)
func TestChangesEmpty(t *testing.T) {
testCases := map[string]struct {
changes *Changes
want bool
}{
"no changes": {
&Changes{},
true,
},
"resource change": {
&Changes{
Resources: []*ResourceInstanceChangeSrc{
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
PrevRunAddr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
ChangeSrc: ChangeSrc{
Action: Update,
},
},
},
},
false,
},
"resource change with no-op action": {
&Changes{
Resources: []*ResourceInstanceChangeSrc{
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
PrevRunAddr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
ChangeSrc: ChangeSrc{
Action: NoOp,
},
},
},
},
true,
},
"resource moved with no-op change": {
&Changes{
Resources: []*ResourceInstanceChangeSrc{
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
PrevRunAddr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "toot",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
ChangeSrc: ChangeSrc{
Action: NoOp,
},
},
},
},
false,
},
"output change": {
&Changes{
Outputs: []*OutputChangeSrc{
{
Addr: addrs.OutputValue{
Name: "result",
}.Absolute(addrs.RootModuleInstance),
ChangeSrc: ChangeSrc{
Action: Update,
},
},
},
},
false,
},
"output change no-op": {
&Changes{
Outputs: []*OutputChangeSrc{
{
Addr: addrs.OutputValue{
Name: "result",
}.Absolute(addrs.RootModuleInstance),
ChangeSrc: ChangeSrc{
Action: NoOp,
},
},
},
},
true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
if got, want := tc.changes.Empty(), tc.want; got != want {
t.Fatalf("unexpected result: got %v, want %v", got, want)
}
})
}
}
func TestChangeEncodeSensitive(t *testing.T) {
testVals := []cty.Value{
cty.ObjectVal(map[string]cty.Value{
"ding": cty.StringVal("dong").Mark(marks.Sensitive),
}),
cty.StringVal("bleep").Mark("bloop"),
cty.ListVal([]cty.Value{cty.UnknownVal(cty.String).Mark("sup?")}),
}
for _, v := range testVals {
t.Run(fmt.Sprintf("%#v", v), func(t *testing.T) {
change := Change{
Before: cty.NullVal(v.Type()),
After: v,
}
encoded, err := change.Encode(v.Type())
if err != nil {
t.Fatal(err)
}
decoded, err := encoded.Decode(v.Type())
if err != nil {
t.Fatal(err)
}
if !v.RawEquals(decoded.After) {
t.Fatalf("%#v != %#v\n", decoded.After, v)
}
})
}
}