mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-08 07:03:16 -06:00
817a593280
Fixes #10729 Destruction ordering wasn't taking into account ordering implied through variables across module boundaries. This is because to build the destruction ordering we create a non-destruction graph to determine the _creation_ ordering (to properly flip edges). This creation graph we create wasn't including module variables. This PR adds that transform to the graph.
296 lines
6.2 KiB
Go
296 lines
6.2 KiB
Go
package terraform
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestApplyGraphBuilder_impl(t *testing.T) {
|
|
var _ GraphBuilder = new(ApplyGraphBuilder)
|
|
}
|
|
|
|
func TestApplyGraphBuilder(t *testing.T) {
|
|
diff := &Diff{
|
|
Modules: []*ModuleDiff{
|
|
&ModuleDiff{
|
|
Path: []string{"root"},
|
|
Resources: map[string]*InstanceDiff{
|
|
// Verify noop doesn't show up in graph
|
|
"aws_instance.noop": &InstanceDiff{},
|
|
|
|
"aws_instance.create": &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
|
|
"aws_instance.other": &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
&ModuleDiff{
|
|
Path: []string{"root", "child"},
|
|
Resources: map[string]*InstanceDiff{
|
|
"aws_instance.create": &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
|
|
"aws_instance.other": &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
b := &ApplyGraphBuilder{
|
|
Module: testModule(t, "graph-builder-apply-basic"),
|
|
Diff: diff,
|
|
Providers: []string{"aws"},
|
|
Provisioners: []string{"exec"},
|
|
DisableReduce: true,
|
|
}
|
|
|
|
g, err := b.Build(RootModulePath)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(g.Path, RootModulePath) {
|
|
t.Fatalf("bad: %#v", g.Path)
|
|
}
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
expected := strings.TrimSpace(testApplyGraphBuilderStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: %s", actual)
|
|
}
|
|
}
|
|
|
|
// This tests the ordering of two resources that are both CBD that
|
|
// require destroy/create.
|
|
func TestApplyGraphBuilder_doubleCBD(t *testing.T) {
|
|
diff := &Diff{
|
|
Modules: []*ModuleDiff{
|
|
&ModuleDiff{
|
|
Path: []string{"root"},
|
|
Resources: map[string]*InstanceDiff{
|
|
"aws_instance.A": &InstanceDiff{
|
|
Destroy: true,
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
|
|
"aws_instance.B": &InstanceDiff{
|
|
Destroy: true,
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
b := &ApplyGraphBuilder{
|
|
Module: testModule(t, "graph-builder-apply-double-cbd"),
|
|
Diff: diff,
|
|
Providers: []string{"aws"},
|
|
Provisioners: []string{"exec"},
|
|
DisableReduce: true,
|
|
}
|
|
|
|
g, err := b.Build(RootModulePath)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(g.Path, RootModulePath) {
|
|
t.Fatalf("bad: %#v", g.Path)
|
|
}
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
expected := strings.TrimSpace(testApplyGraphBuilderDoubleCBDStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: %s", actual)
|
|
}
|
|
}
|
|
|
|
// This tests the ordering of destroying a single count of a resource.
|
|
func TestApplyGraphBuilder_destroyCount(t *testing.T) {
|
|
diff := &Diff{
|
|
Modules: []*ModuleDiff{
|
|
&ModuleDiff{
|
|
Path: []string{"root"},
|
|
Resources: map[string]*InstanceDiff{
|
|
"aws_instance.A.1": &InstanceDiff{
|
|
Destroy: true,
|
|
},
|
|
|
|
"aws_instance.B": &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"name": &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
b := &ApplyGraphBuilder{
|
|
Module: testModule(t, "graph-builder-apply-count"),
|
|
Diff: diff,
|
|
Providers: []string{"aws"},
|
|
Provisioners: []string{"exec"},
|
|
DisableReduce: true,
|
|
}
|
|
|
|
g, err := b.Build(RootModulePath)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(g.Path, RootModulePath) {
|
|
t.Fatalf("bad: %#v", g.Path)
|
|
}
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
expected := strings.TrimSpace(testApplyGraphBuilderDestroyCountStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: %s", actual)
|
|
}
|
|
}
|
|
|
|
func TestApplyGraphBuilder_moduleDestroy(t *testing.T) {
|
|
diff := &Diff{
|
|
Modules: []*ModuleDiff{
|
|
&ModuleDiff{
|
|
Path: []string{"root", "A"},
|
|
Resources: map[string]*InstanceDiff{
|
|
"null_resource.foo": &InstanceDiff{
|
|
Destroy: true,
|
|
},
|
|
},
|
|
},
|
|
|
|
&ModuleDiff{
|
|
Path: []string{"root", "B"},
|
|
Resources: map[string]*InstanceDiff{
|
|
"null_resource.foo": &InstanceDiff{
|
|
Destroy: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
b := &ApplyGraphBuilder{
|
|
Module: testModule(t, "graph-builder-apply-module-destroy"),
|
|
Diff: diff,
|
|
Providers: []string{"null"},
|
|
}
|
|
|
|
g, err := b.Build(RootModulePath)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
testGraphHappensBefore(
|
|
t, g,
|
|
"module.B.null_resource.foo (destroy)",
|
|
"module.A.null_resource.foo (destroy)")
|
|
}
|
|
|
|
const testApplyGraphBuilderStr = `
|
|
aws_instance.create
|
|
provider.aws
|
|
aws_instance.other
|
|
aws_instance.create
|
|
provider.aws
|
|
meta.count-boundary (count boundary fixup)
|
|
aws_instance.create
|
|
aws_instance.other
|
|
module.child.aws_instance.create
|
|
module.child.aws_instance.other
|
|
module.child.provider.aws
|
|
module.child.provisioner.exec
|
|
provider.aws
|
|
module.child.aws_instance.create
|
|
module.child.provider.aws
|
|
module.child.provisioner.exec
|
|
module.child.aws_instance.other
|
|
module.child.aws_instance.create
|
|
module.child.provider.aws
|
|
module.child.provider.aws
|
|
provider.aws
|
|
module.child.provisioner.exec
|
|
provider.aws
|
|
`
|
|
|
|
const testApplyGraphBuilderDoubleCBDStr = `
|
|
aws_instance.A
|
|
provider.aws
|
|
aws_instance.A (destroy)
|
|
aws_instance.A
|
|
aws_instance.B
|
|
aws_instance.B (destroy)
|
|
provider.aws
|
|
aws_instance.B
|
|
aws_instance.A
|
|
provider.aws
|
|
aws_instance.B (destroy)
|
|
aws_instance.B
|
|
provider.aws
|
|
meta.count-boundary (count boundary fixup)
|
|
aws_instance.A
|
|
aws_instance.A (destroy)
|
|
aws_instance.B
|
|
aws_instance.B (destroy)
|
|
provider.aws
|
|
provider.aws
|
|
`
|
|
|
|
const testApplyGraphBuilderDestroyCountStr = `
|
|
aws_instance.A[1] (destroy)
|
|
provider.aws
|
|
aws_instance.B
|
|
aws_instance.A[1] (destroy)
|
|
provider.aws
|
|
meta.count-boundary (count boundary fixup)
|
|
aws_instance.A[1] (destroy)
|
|
aws_instance.B
|
|
provider.aws
|
|
provider.aws
|
|
`
|