Files
opentf/internal/plans/plan_test.go
Christian Mesh be433be96f Support for static variables used with encrypted plans (#1998)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
Signed-off-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
Co-authored-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
2025-07-28 12:11:43 -04:00

157 lines
4.4 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package plans
import (
"testing"
"github.com/go-test/deep"
"github.com/opentofu/opentofu/internal/configs"
"github.com/zclconf/go-cty/cty"
ctymsgpack "github.com/zclconf/go-cty/cty/msgpack"
"github.com/opentofu/opentofu/internal/addrs"
)
func TestProviderAddrs(t *testing.T) {
plan := &Plan{
VariableValues: map[string]DynamicValue{},
Changes: &Changes{
Resources: []*ResourceInstanceChangeSrc{
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
ProviderAddr: addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
},
},
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
DeposedKey: "foodface",
ProviderAddr: addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
},
},
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "what",
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
ProviderAddr: addrs.AbsProviderConfig{
Module: addrs.RootModule.Child("foo"),
Provider: addrs.NewDefaultProvider("test"),
},
},
},
},
}
got := plan.ProviderAddrs()
want := []addrs.AbsProviderConfig{
addrs.AbsProviderConfig{
Module: addrs.RootModule.Child("foo"),
Provider: addrs.NewDefaultProvider("test"),
},
addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
},
}
for _, problem := range deep.Equal(got, want) {
t.Error(problem)
}
}
// Module outputs should not effect the result of Empty
func TestModuleOutputChangesEmpty(t *testing.T) {
changes := &Changes{
Outputs: []*OutputChangeSrc{
{
Addr: addrs.AbsOutputValue{
Module: addrs.RootModuleInstance.Child("child", addrs.NoKey),
OutputValue: addrs.OutputValue{
Name: "output",
},
},
ChangeSrc: ChangeSrc{
Action: Update,
Before: []byte("a"),
After: []byte("b"),
},
},
},
}
if !changes.Empty() {
t.Fatal("plan has no visible changes")
}
}
// TestVariableMapper checks that the mapper is decoding types correctly from the plan
func TestVariableMapper(t *testing.T) {
val1 := cty.StringVal("string value")
val2 := cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("bar")})
val3 := cty.MapVal(map[string]cty.Value{
"inner": cty.SetVal([]cty.Value{cty.StringVal("baz")}),
})
val4 := cty.ListVal([]cty.Value{cty.BoolVal(false)})
val5 := cty.SetVal([]cty.Value{
cty.ObjectVal(
map[string]cty.Value{
"inner": cty.ObjectVal(map[string]cty.Value{"foo": cty.NumberIntVal(25)}),
},
),
})
p := Plan{VariableValues: map[string]DynamicValue{
"raw_string": encodeDynamicValueWithType(t, val1, cty.DynamicPseudoType),
"object_of_strings": encodeDynamicValueWithType(t, val2, cty.DynamicPseudoType),
"map_of_sets_of_strings": encodeDynamicValueWithType(t, val3, cty.DynamicPseudoType),
"list_of_bools": encodeDynamicValueWithType(t, val4, cty.DynamicPseudoType),
"set_of_obj_of_obj_of_number": encodeDynamicValueWithType(t, val5, cty.DynamicPseudoType),
}}
vm := p.VariableMapper()
cases := map[string]cty.Value{
"raw_string": val1,
"object_of_strings": val2,
"map_of_sets_of_strings": val3,
"list_of_bools": val4,
"set_of_obj_of_obj_of_number": val5,
}
for varName, wantVal := range cases {
t.Run(varName, func(t *testing.T) {
val, diag := vm(&configs.Variable{Name: varName})
if diag.HasErrors() {
t.Fatalf("unexpected diagnostics from the variable mapper: %s", diag)
}
if !val.RawEquals(wantVal) {
t.Fatalf("returned value is not equal with the expected one.\n\twant:%s\n\tgot:%s\n", wantVal, val)
}
})
}
}
func encodeDynamicValueWithType(t *testing.T, value cty.Value, ty cty.Type) []byte {
data, err := ctymsgpack.Marshal(value, ty)
if err != nil {
t.Fatalf("failed to marshal JSON: %s", err)
}
return data
}