core: Pass components through to the destroy transformers

These transformers both construct temporary graphs using many of the same
transformers used in the apply graph, and properly doing this now requires
access to the providers and provisioners in order to obtain their schemas.

Along with this, we also update the tests here to use the
simpleMockComponentFactory helper to get a mock provider with a schema
already configured, which means we also need to update the test fixtures
and assertions to use the resource type and attributes defined in that
mock factory.
This commit is contained in:
Martin Atkins 2018-05-09 17:05:18 -07:00
parent 1a9ee72ecb
commit bec0f56808
13 changed files with 254 additions and 170 deletions

View File

@ -289,10 +289,11 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags.
case GraphTypePlanDestroy:
return (&DestroyPlanGraphBuilder{
Config: c.config,
State: c.state,
Targets: c.targets,
Validate: opts.Validate,
Config: c.config,
State: c.state,
Components: c.components,
Targets: c.targets,
Validate: opts.Validate,
}).Build(addrs.RootModuleInstance)
case GraphTypeRefresh:

View File

@ -88,10 +88,18 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config),
// Destruction ordering
&DestroyEdgeTransformer{Config: b.Config, State: b.State},
&DestroyEdgeTransformer{
Config: b.Config,
State: b.State,
Components: b.Components,
},
GraphTransformIf(
func() bool { return !b.Destroy },
&CBDEdgeTransformer{Config: b.Config, State: b.State},
&CBDEdgeTransformer{
Config: b.Config,
State: b.State,
Components: b.Components,
},
),
// Provisioner-related transformations

View File

@ -22,6 +22,10 @@ type DestroyPlanGraphBuilder struct {
// Targets are resources to target
Targets []addrs.Targetable
// Components is a factory for the plug-in components (providers and
// provisioners) available for use.
Components contextComponentFactory
// Validate will do structural validation of the graph.
Validate bool
}
@ -55,7 +59,11 @@ func (b *DestroyPlanGraphBuilder) Steps() []GraphTransformer {
// Destruction ordering. We require this only so that
// targeting below will prune the correct things.
&DestroyEdgeTransformer{Config: b.Config, State: b.State},
&DestroyEdgeTransformer{
Config: b.Config,
State: b.State,
Components: b.Components,
},
// Target. Note we don't set "Destroy: true" here since we already
// created proper destroy ordering.

View File

@ -1,5 +1,5 @@
resource "test" "A" {}
resource "test_object" "A" {}
resource "test" "B" {
value = "${test.A.value}"
resource "test_object" "B" {
test_string = "${test_object.A.test_string}"
}

View File

@ -1,8 +1,9 @@
resource "aws_instance" "a" {}
resource "aws_instance" "b" {
value = "${aws_instance.a.id}"
resource "test_object" "a" {}
resource "test_object" "b" {
test_string = "${test_object.a.test_string}"
}
resource "aws_instance" "c" {
value = "${aws_instance.b.id}"
resource "test_object" "c" {
test_string = "${test_object.b.test_string}"
}

View File

@ -1,7 +1,7 @@
resource "aws_instance" "b" {
value = "foo"
resource "test_object" "b" {
test_string = "foo"
}
output "output" {
value = "${aws_instance.b.value}"
value = "${test_object.b.test_string}"
}

View File

@ -1,7 +1,7 @@
resource "aws_instance" "a" {
value = "${module.child.output}"
resource "test_object" "a" {
test_string = "${module.child.output}"
}
module "child" {
source = "./child"
source = "./child"
}

View File

@ -1,9 +1,9 @@
resource "test" "A" {}
resource "test_object" "A" {}
resource "test" "B" {
value = "${test.A.value}"
resource "test_object" "B" {
test_string = "${test_object.A.test_string}"
}
resource "test" "C" {
value = "${test.B.value}"
resource "test_object" "C" {
test_string = "${test_object.B.test_string}"
}

View File

@ -1,5 +1,6 @@
resource "test" "A" {}
resource "test" "B" {
count = 2
value = "${test.A.*.value}"
resource "test_object" "A" {}
resource "test_object" "B" {
count = 2
test_string = "${test_object.A.*.test_string}"
}

View File

@ -40,11 +40,14 @@ type CBDEdgeTransformer struct {
// any way possible. Either can be nil if not availabile.
Config *configs.Config
State *State
// If configuration is present then Components is required in order to
// obtain schema information from providers and provisioners in order
// to properly resolve implicit dependencies.
Components contextComponentFactory
}
func (t *CBDEdgeTransformer) Transform(g *Graph) error {
log.Printf("[TRACE] CBDEdgeTransformer: Beginning CBD transformation...")
// Go through and reverse any destroy edges
destroyMap := make(map[string][]dag.Vertex)
for _, v := range g.Vertices() {
@ -64,6 +67,7 @@ func (t *CBDEdgeTransformer) Transform(g *Graph) error {
// and we need to auto-upgrade this node to CBD. We do this because
// a CBD node depending on non-CBD will result in cycles. To avoid this,
// we always attempt to upgrade it.
log.Printf("[TRACE] CBDEdgeTransformer: forcing create_before_destroy on for %q (%T)", dag.VertexName(v), v)
if err := dn.ModifyCreateBeforeDestroy(true); err != nil {
return fmt.Errorf(
"%s: must have create before destroy enabled because "+
@ -174,6 +178,7 @@ func (t *CBDEdgeTransformer) depMap(destroyMap map[string][]dag.Vertex) (map[str
&FlatConfigTransformer{Config: t.Config},
&AttachResourceConfigTransformer{Config: t.Config},
&AttachStateTransformer{State: t.State},
&AttachSchemaTransformer{Components: t.Components},
&ReferenceTransformer{},
},
Name: "CBDEdgeTransformer",

View File

@ -9,15 +9,16 @@ import (
func TestCBDEdgeTransformer(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeCreatorTest{AddrString: "test.A"})
g.Add(&graphNodeCreatorTest{AddrString: "test.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.A", CBD: true})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A", CBD: true})
module := testModule(t, "transform-destroy-edge-basic")
{
tf := &DestroyEdgeTransformer{
Config: module,
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -25,7 +26,10 @@ func TestCBDEdgeTransformer(t *testing.T) {
}
{
tf := &CBDEdgeTransformer{Config: module}
tf := &CBDEdgeTransformer{
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
@ -34,22 +38,23 @@ func TestCBDEdgeTransformer(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformCBDEdgeBasicStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestCBDEdgeTransformer_depNonCBD(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeCreatorTest{AddrString: "test.A"})
g.Add(&graphNodeCreatorTest{AddrString: "test.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.B", CBD: true})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B", CBD: true})
module := testModule(t, "transform-destroy-edge-basic")
{
tf := &DestroyEdgeTransformer{
Config: module,
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -57,7 +62,10 @@ func TestCBDEdgeTransformer_depNonCBD(t *testing.T) {
}
{
tf := &CBDEdgeTransformer{Config: module}
tf := &CBDEdgeTransformer{
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
@ -66,22 +74,23 @@ func TestCBDEdgeTransformer_depNonCBD(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformCBDEdgeDepNonCBDStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeCreatorTest{AddrString: "test.A"})
g.Add(&graphNodeCreatorTest{AddrString: "test.B[0]"})
g.Add(&graphNodeCreatorTest{AddrString: "test.B[1]"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.A", CBD: true})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[0]"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[1]"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A", CBD: true})
module := testModule(t, "transform-destroy-edge-splat")
{
tf := &DestroyEdgeTransformer{
Config: module,
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -89,7 +98,10 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
}
{
tf := &CBDEdgeTransformer{Config: module}
tf := &CBDEdgeTransformer{
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
@ -97,33 +109,34 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
test.A
test.A (destroy)
test.A
test.B[0]
test.B[1]
test.B[0]
test.B[1]
test_object.A
test_object.A (destroy)
test_object.A
test_object.B[0]
test_object.B[1]
test_object.B[0]
test_object.B[1]
`)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeCreatorTest{AddrString: "test.A[0]"})
g.Add(&graphNodeCreatorTest{AddrString: "test.A[1]"})
g.Add(&graphNodeCreatorTest{AddrString: "test.B[0]"})
g.Add(&graphNodeCreatorTest{AddrString: "test.B[1]"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.A[0]", CBD: true})
g.Add(&graphNodeDestroyerTest{AddrString: "test.A[1]", CBD: true})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.A[0]"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.A[1]"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[0]"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[1]"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A[0]", CBD: true})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A[1]", CBD: true})
module := testModule(t, "transform-destroy-edge-splat")
{
tf := &DestroyEdgeTransformer{
Config: module,
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -131,7 +144,10 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
}
{
tf := &CBDEdgeTransformer{Config: module}
tf := &CBDEdgeTransformer{
Config: module,
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
@ -139,39 +155,39 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
test.A[0]
test.A[0] (destroy)
test.A[0]
test.B[0]
test.B[1]
test.A[1]
test.A[1] (destroy)
test.A[1]
test.B[0]
test.B[1]
test.B[0]
test.B[1]
test_object.A[0]
test_object.A[0] (destroy)
test_object.A[0]
test_object.B[0]
test_object.B[1]
test_object.A[1]
test_object.A[1] (destroy)
test_object.A[1]
test_object.B[0]
test_object.B[1]
test_object.B[0]
test_object.B[1]
`)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
const testTransformCBDEdgeBasicStr = `
test.A
test.A (destroy)
test.A
test.B
test.B
test_object.A
test_object.A (destroy)
test_object.A
test_object.B
test_object.B
`
const testTransformCBDEdgeDepNonCBDStr = `
test.A
test.A (destroy) (modified)
test.A
test.B
test.B (destroy)
test.B
test.B (destroy)
test.B
test_object.A
test_object.A (destroy) (modified)
test_object.A
test_object.B
test_object.B (destroy)
test_object.B
test_object.B (destroy)
test_object.B
`

View File

@ -44,11 +44,14 @@ type DestroyEdgeTransformer struct {
// to determine what a destroy node depends on. Any of these can be nil.
Config *configs.Config
State *State
// If configuration is present then Components is required in order to
// obtain schema information from providers and provisioners in order
// to properly resolve implicit dependencies.
Components contextComponentFactory
}
func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
log.Printf("[TRACE] DestroyEdgeTransformer: Beginning destroy edge transformation...")
// Build a map of what is being destroyed (by address string) to
// the list of destroyers. In general there will only be one destroyer
// but to make it more robust we support multiple.
@ -67,7 +70,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
addr := *addrP
key := addr.String()
log.Printf("[TRACE] DestroyEdgeTransformer: %s will destroy %s", dag.VertexName(dn), key)
log.Printf("[TRACE] DestroyEdgeTransformer: %q (%T) destroys %s", dag.VertexName(dn), v, key)
destroyers[key] = append(destroyers[key], dn)
destroyerAddrs[key] = addr
}
@ -103,7 +106,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
a := v
log.Printf(
"[TRACE] DestroyEdgeTransformer: connecting creator/destroyer: %s, %s",
"[TRACE] DestroyEdgeTransformer: connecting creator %q with destroyer %q",
dag.VertexName(a), dag.VertexName(a_d))
g.Connect(&DestroyEdge{S: a, T: a_d})
@ -138,6 +141,10 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
&RootVariableTransformer{Config: t.Config},
&ModuleVariableTransformer{Config: t.Config},
// Must be before ReferenceTransformer, since schema is required to
// extract references from config.
&AttachSchemaTransformer{Components: t.Components},
&ReferenceTransformer{},
}
@ -157,12 +164,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
// This part is a little bit weird but is the best way to
// find the dependencies we need to: build a graph and use the
// attach config and state transformers then ask for references.
abstract := &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
Addr: addr.ContainingResource(),
},
InstanceKey: addr.Resource.Key,
}
abstract := NewNodeAbstractResourceInstance(addr)
tempG.Add(abstract)
tempDestroyed = append(tempDestroyed, abstract)
@ -175,13 +177,15 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
// Run the graph transforms so we have the information we need to
// build references.
log.Println("[TRACE] DestroyEdgeTransformer: constructing temporary graph for analysis of references")
for _, s := range steps {
log.Printf("[TRACE] DestroyEdgeTransformer: running %T on temporary graph", s)
if err := s.Transform(&tempG); err != nil {
log.Printf("[TRACE] DestroyEdgeTransformer: %T failed: %s", s, err)
return err
}
}
log.Printf("[TRACE] DestroyEdgeTransformer: reference graph: %s", tempG.String())
log.Printf("[TRACE] DestroyEdgeTransformer: temporary reference graph: %s", tempG.String())
// Go through all the nodes in the graph and determine what they
// depend on.

View File

@ -9,10 +9,11 @@ import (
func TestDestroyEdgeTransformer_basic(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeDestroyerTest{AddrString: "test.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B"})
tf := &DestroyEdgeTransformer{
Config: testModule(t, "transform-destroy-edge-basic"),
Config: testModule(t, "transform-destroy-edge-basic"),
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -21,17 +22,18 @@ func TestDestroyEdgeTransformer_basic(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformDestroyEdgeBasicStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestDestroyEdgeTransformer_create(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeDestroyerTest{AddrString: "test.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.B"})
g.Add(&graphNodeCreatorTest{AddrString: "test.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B"})
g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"})
tf := &DestroyEdgeTransformer{
Config: testModule(t, "transform-destroy-edge-basic"),
Config: testModule(t, "transform-destroy-edge-basic"),
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -40,17 +42,18 @@ func TestDestroyEdgeTransformer_create(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformDestroyEdgeCreatorStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestDestroyEdgeTransformer_multi(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeDestroyerTest{AddrString: "test.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test.C"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.C"})
tf := &DestroyEdgeTransformer{
Config: testModule(t, "transform-destroy-edge-multi"),
Config: testModule(t, "transform-destroy-edge-multi"),
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -59,15 +62,16 @@ func TestDestroyEdgeTransformer_multi(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformDestroyEdgeMultiStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestDestroyEdgeTransformer_selfRef(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeDestroyerTest{AddrString: "test.A"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"})
tf := &DestroyEdgeTransformer{
Config: testModule(t, "transform-destroy-edge-self-ref"),
Config: testModule(t, "transform-destroy-edge-self-ref"),
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -76,16 +80,17 @@ func TestDestroyEdgeTransformer_selfRef(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformDestroyEdgeSelfRefStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestDestroyEdgeTransformer_module(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.b"})
g.Add(&graphNodeDestroyerTest{AddrString: "aws_instance.a"})
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.b"})
g.Add(&graphNodeDestroyerTest{AddrString: "test_object.a"})
tf := &DestroyEdgeTransformer{
Config: testModule(t, "transform-destroy-edge-module"),
Config: testModule(t, "transform-destroy-edge-module"),
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -94,17 +99,18 @@ func TestDestroyEdgeTransformer_module(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformDestroyEdgeModuleStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.a"})
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.b"})
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.c"})
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.a"})
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.b"})
g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.c"})
tf := &DestroyEdgeTransformer{
Config: testModule(t, "transform-destroy-edge-module-only"),
Config: testModule(t, "transform-destroy-edge-module-only"),
Components: simpleMockComponentFactory(),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
@ -112,15 +118,15 @@ func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
module.child.aws_instance.a (destroy)
module.child.aws_instance.b (destroy)
module.child.aws_instance.c (destroy)
module.child.aws_instance.b (destroy)
module.child.aws_instance.c (destroy)
module.child.aws_instance.c (destroy)
module.child.test_object.a (destroy)
module.child.test_object.b (destroy)
module.child.test_object.c (destroy)
module.child.test_object.b (destroy)
module.child.test_object.c (destroy)
module.child.test_object.c (destroy)
`)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
@ -129,17 +135,43 @@ type graphNodeCreatorTest struct {
Refs []string
}
func (n *graphNodeCreatorTest) Name() string { return n.CreateAddr().String() }
func (n *graphNodeCreatorTest) CreateAddr() *ResourceAddress {
addr, err := ParseResourceAddress(n.AddrString)
if err != nil {
panic(err)
}
var (
_ GraphNodeCreator = (*graphNodeCreatorTest)(nil)
_ GraphNodeReferencer = (*graphNodeCreatorTest)(nil)
)
func (n *graphNodeCreatorTest) Name() string {
return n.CreateAddr().String()
}
func (n *graphNodeCreatorTest) mustAddr() addrs.AbsResourceInstance {
addr, diags := addrs.ParseAbsResourceInstanceStr(n.AddrString)
if diags.HasErrors() {
panic(diags.Err())
}
return addr
}
func (n *graphNodeCreatorTest) References() []string { return n.Refs }
func (n *graphNodeCreatorTest) Path() addrs.ModuleInstance {
return n.mustAddr().Module
}
func (n *graphNodeCreatorTest) CreateAddr() *addrs.AbsResourceInstance {
addr := n.mustAddr()
return &addr
}
func (n *graphNodeCreatorTest) References() []*addrs.Reference {
ret := make([]*addrs.Reference, len(n.Refs))
for i, str := range n.Refs {
ref, diags := addrs.ParseRefStr(str)
if diags.HasErrors() {
panic(diags.Err())
}
ret[i] = ref
}
return ret
}
type graphNodeDestroyerTest struct {
AddrString string
@ -147,6 +179,8 @@ type graphNodeDestroyerTest struct {
Modified bool
}
var _ GraphNodeDestroyer = (*graphNodeDestroyerTest)(nil)
func (n *graphNodeDestroyerTest) Name() string {
result := n.DestroyAddr().String() + " (destroy)"
if n.Modified {
@ -156,51 +190,57 @@ func (n *graphNodeDestroyerTest) Name() string {
return result
}
func (n *graphNodeDestroyerTest) CreateBeforeDestroy() bool { return n.CBD }
func (n *graphNodeDestroyerTest) mustAddr() addrs.AbsResourceInstance {
addr, diags := addrs.ParseAbsResourceInstanceStr(n.AddrString)
if diags.HasErrors() {
panic(diags.Err())
}
return addr
}
func (n *graphNodeDestroyerTest) CreateBeforeDestroy() bool {
return n.CBD
}
func (n *graphNodeDestroyerTest) ModifyCreateBeforeDestroy(v bool) error {
n.Modified = true
return nil
}
func (n *graphNodeDestroyerTest) DestroyAddr() *ResourceAddress {
addr, err := ParseResourceAddress(n.AddrString)
if err != nil {
panic(err)
}
return addr
func (n *graphNodeDestroyerTest) DestroyAddr() *addrs.AbsResourceInstance {
addr := n.mustAddr()
return &addr
}
const testTransformDestroyEdgeBasicStr = `
test.A (destroy)
test.B (destroy)
test.B (destroy)
test_object.A (destroy)
test_object.B (destroy)
test_object.B (destroy)
`
const testTransformDestroyEdgeCreatorStr = `
test.A
test.A (destroy)
test.A (destroy)
test.B (destroy)
test.B (destroy)
test_object.A
test_object.A (destroy)
test_object.A (destroy)
test_object.B (destroy)
test_object.B (destroy)
`
const testTransformDestroyEdgeMultiStr = `
test.A (destroy)
test.B (destroy)
test.C (destroy)
test.B (destroy)
test.C (destroy)
test.C (destroy)
test_object.A (destroy)
test_object.B (destroy)
test_object.C (destroy)
test_object.B (destroy)
test_object.C (destroy)
test_object.C (destroy)
`
const testTransformDestroyEdgeSelfRefStr = `
test.A (destroy)
test_object.A (destroy)
`
const testTransformDestroyEdgeModuleStr = `
aws_instance.a (destroy)
module.child.aws_instance.b (destroy)
aws_instance.a (destroy)
module.child.test_object.b (destroy)
test_object.a (destroy)
test_object.a (destroy)
`