opentofu/internal/terraform/transform_targets_test.go
Martin Atkins 3cd069900b core: Use DynamicExpand even for root module outputs
We previously had a special case in the graph transformer for output
values where it would directly create an individual output value node
instead of an "expand" node as we would do for output values in nested
modules.

While it's true that we do always know that expanding a root module
output value will always produce exactly one instance, treating this case
as special creates the risk of those two codepaths diverging in other
ways.

Instead, we'll let the expand node also deal with root modules and
minimize the special case only to how we look up any changes for the
output values, since the design of plans.Changes is a bit awkward and
requires us to ask the question differently for root module output values.
Otherwise, the behavior will now be consistent across all output values
regardless of module.
2022-07-22 15:25:22 -07:00

203 lines
4.9 KiB
Go

package terraform
import (
"strings"
"testing"
"github.com/hashicorp/terraform/internal/addrs"
)
func TestTargetsTransformer(t *testing.T) {
mod := testModule(t, "transform-targets-basic")
g := Graph{Path: addrs.RootModuleInstance}
{
tf := &ConfigTransformer{Config: mod}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
{
transform := &AttachResourceConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
{
transform := &ReferenceTransformer{}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
{
transform := &TargetsTransformer{
Targets: []addrs.Targetable{
addrs.RootModuleInstance.Resource(
addrs.ManagedResourceMode, "aws_instance", "me",
),
},
}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
aws_instance.me
aws_subnet.me
aws_subnet.me
aws_vpc.me
aws_vpc.me
`)
if actual != expected {
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}
func TestTargetsTransformer_downstream(t *testing.T) {
mod := testModule(t, "transform-targets-downstream")
g := Graph{Path: addrs.RootModuleInstance}
{
transform := &ConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &AttachResourceConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &AttachResourceConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &OutputTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &ReferenceTransformer{}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
{
transform := &TargetsTransformer{
Targets: []addrs.Targetable{
addrs.RootModuleInstance.
Child("child", addrs.NoKey).
Child("grandchild", addrs.NoKey).
Resource(
addrs.ManagedResourceMode, "aws_instance", "foo",
),
},
}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
actual := strings.TrimSpace(g.String())
// Even though we only asked to target the grandchild resource, all of the
// outputs that descend from it are also targeted.
expected := strings.TrimSpace(`
module.child.module.grandchild.aws_instance.foo
module.child.module.grandchild.output.id (expand)
module.child.module.grandchild.aws_instance.foo
module.child.output.grandchild_id (expand)
module.child.module.grandchild.output.id (expand)
output.grandchild_id (expand)
module.child.output.grandchild_id (expand)
`)
if actual != expected {
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}
// This tests the TargetsTransformer targeting a whole module,
// rather than a resource within a module instance.
func TestTargetsTransformer_wholeModule(t *testing.T) {
mod := testModule(t, "transform-targets-downstream")
g := Graph{Path: addrs.RootModuleInstance}
{
transform := &ConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &AttachResourceConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &AttachResourceConfigTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &OutputTransformer{Config: mod}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
{
transform := &ReferenceTransformer{}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
{
transform := &TargetsTransformer{
Targets: []addrs.Targetable{
addrs.RootModule.
Child("child").
Child("grandchild"),
},
}
if err := transform.Transform(&g); err != nil {
t.Fatalf("%T failed: %s", transform, err)
}
}
actual := strings.TrimSpace(g.String())
// Even though we only asked to target the grandchild module, all of the
// outputs that descend from it are also targeted.
expected := strings.TrimSpace(`
module.child.module.grandchild.aws_instance.foo
module.child.module.grandchild.output.id (expand)
module.child.module.grandchild.aws_instance.foo
module.child.output.grandchild_id (expand)
module.child.module.grandchild.output.id (expand)
output.grandchild_id (expand)
module.child.output.grandchild_id (expand)
`)
if actual != expected {
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}