From b68ab92392ba52d145e4f145068ec8b0573b8c0f Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 19 Aug 2020 10:59:19 -0400 Subject: [PATCH] more complicated for_each destroy --- terraform/context_apply_test.go | 109 ++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index ee5d7622d..d67019f65 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -11645,3 +11645,112 @@ output "output" { t.Fatalf("destroy apply errors: %s", diags.Err()) } } + +// Destroying properly requires pruning out all unneeded config nodes to +// prevent incorrect expansion evaluation. +func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) { + m := testModuleInline(t, map[string]string{ + "main.tf": ` +data "test_data_source" "a" { + for_each = { + one = "thing" + } +} + +locals { + module_input = { + for k, v in data.test_data_source.a : k => v.id + } +} + +module "mod1" { + source = "./mod" + input = local.module_input +} + +module "mod2" { + source = "./mod" + input = module.mod1.outputs +} + +resource "test_instance" "bar" { + for_each = module.mod2.outputs +} + +output "module_output" { + value = module.mod2.outputs +} +output "test_instances" { + value = test_instance.bar +} +`, + "mod/main.tf": ` +variable "input" { +} + +data "test_data_source" "foo" { + for_each = var.input +} + +output "outputs" { + value = data.test_data_source.foo +} +`}) + + p := testProvider("test") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { + return providers.ReadDataSourceResponse{ + State: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("data_source"), + "foo": cty.StringVal("output"), + }), + } + } + + ctx := testContext2(t, &ContextOpts{ + Config: m, + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + }) + + if _, diags := ctx.Plan(); diags.HasErrors() { + t.Fatalf("plan errors: %s", diags.Err()) + } + + state, diags := ctx.Apply() + if diags.HasErrors() { + t.Fatalf("apply errors: %s", diags.Err()) + } + + destroy := func() { + ctx = testContext2(t, &ContextOpts{ + Config: m, + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), + }, + + State: state, + Destroy: true, + }) + + if _, diags := ctx.Refresh(); diags.HasErrors() { + t.Fatalf("destroy plan errors: %s", diags.Err()) + } + + if _, diags := ctx.Plan(); diags.HasErrors() { + t.Fatalf("destroy plan errors: %s", diags.Err()) + } + + state, diags = ctx.Apply() + if diags.HasErrors() { + t.Fatalf("destroy apply errors: %s", diags.Err()) + } + } + + destroy() + // Destroying again from the empty state should not cause any errors either + destroy() +}