From 3e64311dc22605652653e63bf71fa9e614df0796 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Wed, 30 May 2018 16:07:52 -0700 Subject: [PATCH] core: Update TestContext2Apply_multiVarComprehensive for new assumptions This comprehensive test was covering a few different behaviors that are intentionally different for v0.12: - Applying the splat operator to a list of resource instances that haven't been created yet produces a list of unknown values rather than a single unknown list as before. This is important because it allows that list to be passed into length(). - Wrapping a splat expression in another round of brackets now produces a list of lists, whereas before we had a special case (for compatibility with prior to v0.10) that would flatten this away in the schema layer. --- terraform/context_apply_test.go | 97 ++++++++++++------- .../child/child.tf | 10 +- .../apply-multi-var-comprehensive/root.tf | 50 +++++----- 3 files changed, 92 insertions(+), 65 deletions(-) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index d3689d14a4..a2e606650b 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/davecgh/go-spew/spew" + "github.com/go-test/deep" "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/addrs" @@ -3514,8 +3515,8 @@ func TestContext2Apply_multiVarComprehensive(t *testing.T) { "source_names": {Type: cty.List(cty.String), Optional: true}, "source_ids_from_func": {Type: cty.List(cty.String), Optional: true}, "source_names_from_func": {Type: cty.List(cty.String), Optional: true}, - "source_ids_wrapped": {Type: cty.List(cty.String), Optional: true}, - "source_names_wrapped": {Type: cty.List(cty.String), Optional: true}, + "source_ids_wrapped": {Type: cty.List(cty.List(cty.String)), Optional: true}, + "source_names_wrapped": {Type: cty.List(cty.List(cty.String)), Optional: true}, "id": {Type: cty.String, Computed: true}, "name": {Type: cty.String, Computed: true}, @@ -3546,32 +3547,45 @@ func TestContext2Apply_multiVarComprehensive(t *testing.T) { checkConfig := func(name string, want map[string]interface{}) { got := configs[name].Config - if !reflect.DeepEqual(got, want) { - t.Errorf( - "wrong config for %s\ngot: %s\nwant: %s", - name, spew.Sdump(got), spew.Sdump(want), - ) - } + t.Run("config for "+name, func(t *testing.T) { + for _, problem := range deep.Equal(got, want) { + t.Errorf(problem) + } + }) } checkConfig("test_thing.multi_count_var.0", map[string]interface{}{ + "id": unknownValue(), + "name": unknownValue(), "source_id": unknownValue(), "source_name": "test_thing.source.0", }) checkConfig("test_thing.multi_count_var.2", map[string]interface{}{ + "id": unknownValue(), + "name": unknownValue(), "source_id": unknownValue(), "source_name": "test_thing.source.2", }) checkConfig("test_thing.multi_count_derived.0", map[string]interface{}{ + "id": unknownValue(), + "name": unknownValue(), "source_id": unknownValue(), "source_name": "test_thing.source.0", }) checkConfig("test_thing.multi_count_derived.2", map[string]interface{}{ + "id": unknownValue(), + "name": unknownValue(), "source_id": unknownValue(), "source_name": "test_thing.source.2", }) checkConfig("test_thing.whole_splat", map[string]interface{}{ - "source_ids": unknownValue(), + "id": unknownValue(), + "name": unknownValue(), + "source_ids": []interface{}{ + unknownValue(), + unknownValue(), + unknownValue(), + }, "source_names": []interface{}{ "test_thing.source.0", "test_thing.source.1", @@ -3584,47 +3598,60 @@ func TestContext2Apply_multiVarComprehensive(t *testing.T) { "test_thing.source.2", }, - // This one ends up being a list with a single unknown value at this - // layer, but is fixed up inside helper/schema. There is a test for - // this inside the "test" provider, since core tests can't exercise - // helper/schema functionality. - "source_ids_wrapped": []interface{}{unknownValue()}, - - "source_names_wrapped": []interface{}{ - "test_thing.source.0", - "test_thing.source.1", - "test_thing.source.2", + "source_ids_wrapped": []interface{}{ + []interface{}{ + unknownValue(), + unknownValue(), + unknownValue(), + }, }, + "source_names_wrapped": []interface{}{ + []interface{}{ + "test_thing.source.0", + "test_thing.source.1", + "test_thing.source.2", + }, + }, + "first_source_id": unknownValue(), "first_source_name": "test_thing.source.0", }) checkConfig("module.child.test_thing.whole_splat", map[string]interface{}{ - "source_ids": unknownValue(), + "id": unknownValue(), + "name": unknownValue(), + "source_ids": []interface{}{ + unknownValue(), + unknownValue(), + unknownValue(), + }, "source_names": []interface{}{ "test_thing.source.0", "test_thing.source.1", "test_thing.source.2", }, - // This one ends up being a list with a single unknown value at this - // layer, but is fixed up inside helper/schema. There is a test for - // this inside the "test" provider, since core tests can't exercise - // helper/schema functionality. - "source_ids_wrapped": []interface{}{unknownValue()}, - + "source_ids_wrapped": []interface{}{ + []interface{}{ + unknownValue(), + unknownValue(), + unknownValue(), + }, + }, "source_names_wrapped": []interface{}{ - "test_thing.source.0", - "test_thing.source.1", - "test_thing.source.2", + []interface{}{ + "test_thing.source.0", + "test_thing.source.1", + "test_thing.source.2", + }, }, }) - state, diags := ctx.Apply() - if diags.HasErrors() { - t.Fatalf("error during apply: %s", diags.Err()) - } + t.Run("apply", func(t *testing.T) { + state, diags := ctx.Apply() + if diags.HasErrors() { + t.Fatalf("error during apply: %s", diags.Err()) + } - { want := map[string]interface{}{ "source_ids": []interface{}{"foo", "foo", "foo"}, "source_names": []interface{}{ @@ -3643,7 +3670,7 @@ func TestContext2Apply_multiVarComprehensive(t *testing.T) { spew.Sdump(got), spew.Sdump(want), ) } - } + }) } // Test that multi-var (splat) access is ordered by count, not by diff --git a/terraform/test-fixtures/apply-multi-var-comprehensive/child/child.tf b/terraform/test-fixtures/apply-multi-var-comprehensive/child/child.tf index 5355c79941..5ab54019d1 100644 --- a/terraform/test-fixtures/apply-multi-var-comprehensive/child/child.tf +++ b/terraform/test-fixtures/apply-multi-var-comprehensive/child/child.tf @@ -10,16 +10,16 @@ variable "source_names" { } resource "test_thing" "multi_count_var" { - count = "${var.num}" + count = var.num # Can pluck a single item out of a multi-var - source_id = "${var.source_ids[count.index]}" + source_id = var.source_ids[count.index] } resource "test_thing" "whole_splat" { # Can "splat" the ids directly into an attribute of type list. - source_ids = "${var.source_ids}" - source_names = "${var.source_names}" - source_ids_wrapped = ["${var.source_ids}"] + source_ids = var.source_ids + source_names = var.source_names + source_ids_wrapped = ["${var.source_ids}"] source_names_wrapped = ["${var.source_names}"] } diff --git a/terraform/test-fixtures/apply-multi-var-comprehensive/root.tf b/terraform/test-fixtures/apply-multi-var-comprehensive/root.tf index 511843c3d9..3358fc63b1 100644 --- a/terraform/test-fixtures/apply-multi-var-comprehensive/root.tf +++ b/terraform/test-fixtures/apply-multi-var-comprehensive/root.tf @@ -2,48 +2,48 @@ variable "num" { } resource "test_thing" "source" { - count = "${var.num}" + count = var.num # The diffFunc in the test exports "name" here too, which we can use # to test values that are known during plan. } resource "test_thing" "multi_count_var" { - count = "${var.num}" + count = var.num # Can pluck a single item out of a multi-var - source_id = "${test_thing.source.*.id[count.index]}" - source_name = "${test_thing.source.*.name[count.index]}" + source_id = test_thing.source.*.id[count.index] + source_name = test_thing.source.*.name[count.index] } resource "test_thing" "multi_count_derived" { # Can use the source to get the count - count = "${length(test_thing.source)}" + count = length(test_thing.source) - source_id = "${test_thing.source.*.id[count.index]}" - source_name = "${test_thing.source.*.name[count.index]}" + source_id = test_thing.source.*.id[count.index] + source_name = test_thing.source.*.name[count.index] } resource "test_thing" "whole_splat" { # Can "splat" the ids directly into an attribute of type list. - source_ids = "${test_thing.source.*.id}" - source_names = "${test_thing.source.*.name}" + source_ids = test_thing.source.*.id + source_names = test_thing.source.*.name # Accessing through a function should work. - source_ids_from_func = "${split(" ", join(" ", test_thing.source.*.id))}" - source_names_from_func = "${split(" ", join(" ", test_thing.source.*.name))}" + source_ids_from_func = split(" ", join(" ", test_thing.source.*.id)) + source_names_from_func = split(" ", join(" ", test_thing.source.*.name)) # A common pattern of selecting with a default. - first_source_id = "${element(concat(test_thing.source.*.id, list("default")), 0)}" - first_source_name = "${element(concat(test_thing.source.*.name, list("default")), 0)}" + first_source_id = element(concat(test_thing.source.*.id, ["default"]), 0) + first_source_name = element(concat(test_thing.source.*.name, ["default"]), 0) - # Legacy form: Prior to Terraform having comprehensive list support, - # splats were treated as a special case and required to be presented - # in a wrapping list. This is no longer the suggested form, but we - # need it to keep working for compatibility. - # - # This should result in exactly the same result as the above, even - # though it looks like it would result in a list of lists. + # Prior to v0.12 we were handling lists containing list interpolations as + # a special case, flattening the result, for compatibility with behavior + # prior to v0.10. This deprecated handling is now removed, and so these + # each produce a list of lists. We're still using the interpolation syntax + # here, rather than the splat expression directly, to properly mimic how + # this would've looked prior to v0.12 to be explicit about what the new + # behavior is for this old syntax. source_ids_wrapped = ["${test_thing.source.*.id}"] source_names_wrapped = ["${test_thing.source.*.name}"] @@ -52,15 +52,15 @@ resource "test_thing" "whole_splat" { module "child" { source = "./child" - num = "${var.num}" - source_ids = "${test_thing.source.*.id}" - source_names = "${test_thing.source.*.name}" + num = var.num + source_ids = test_thing.source.*.id + source_names = test_thing.source.*.name } output "source_ids" { - value = "${test_thing.source.*.id}" + value = test_thing.source.*.id } output "source_names" { - value = "${test_thing.source.*.name}" + value = test_thing.source.*.name }