command/format: test for diff rendering with dynamic-typed subattrs
We use cty a little differently when a nested list block contains a dynamically-typed attribute: it appears as a tuple value instead of a list value so that we can retain the individual types of each element. Here we introduce a test for that case, but doing so required also making the runTestCases function handle types in a stricter way so that it will produce planned values that match how Terraform Core would do it, including the necessary late-bound type information for the dynamically-typed attribute.
This commit is contained in:
parent
c5aa5c68bc
commit
69772b11b1
|
@ -1965,9 +1965,11 @@ func TestResourceChange_nestedList(t *testing.T) {
|
|||
Action: plans.Update,
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Before: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-BEFORE"),
|
||||
"root_block_device": cty.ListValEmpty(cty.EmptyObject),
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-BEFORE"),
|
||||
"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
||||
"volume_type": cty.String,
|
||||
})),
|
||||
}),
|
||||
After: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
|
@ -2013,9 +2015,11 @@ func TestResourceChange_nestedList(t *testing.T) {
|
|||
Action: plans.Update,
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Before: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-BEFORE"),
|
||||
"root_block_device": cty.ListValEmpty(cty.EmptyObject),
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-BEFORE"),
|
||||
"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
||||
"volume_type": cty.String,
|
||||
})),
|
||||
}),
|
||||
After: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
|
@ -2249,9 +2253,12 @@ func TestResourceChange_nestedList(t *testing.T) {
|
|||
}),
|
||||
}),
|
||||
After: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-AFTER"),
|
||||
"root_block_device": cty.ListValEmpty(cty.EmptyObject),
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-AFTER"),
|
||||
"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
||||
"volume_type": cty.String,
|
||||
"new_field": cty.String,
|
||||
})),
|
||||
}),
|
||||
RequiredReplace: cty.NewPathSet(),
|
||||
Tainted: false,
|
||||
|
@ -2290,6 +2297,47 @@ func TestResourceChange_nestedList(t *testing.T) {
|
|||
- volume_type = "gp2" -> null
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
"with dynamically-typed attribute": {
|
||||
Action: plans.Update,
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Before: cty.ObjectVal(map[string]cty.Value{
|
||||
"block": cty.EmptyTupleVal,
|
||||
}),
|
||||
After: cty.ObjectVal(map[string]cty.Value{
|
||||
"block": cty.TupleVal([]cty.Value{
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("foo"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.True,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
RequiredReplace: cty.NewPathSet(),
|
||||
Tainted: false,
|
||||
Schema: &configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"block": {
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"attr": {Type: cty.DynamicPseudoType, Optional: true},
|
||||
},
|
||||
},
|
||||
Nesting: configschema.NestingList,
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedOutput: ` # test_instance.example will be updated in-place
|
||||
~ resource "test_instance" "example" {
|
||||
+ block {
|
||||
+ attr = "foo"
|
||||
}
|
||||
+ block {
|
||||
+ attr = true
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
@ -2302,9 +2350,11 @@ func TestResourceChange_nestedSet(t *testing.T) {
|
|||
Action: plans.Update,
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Before: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-BEFORE"),
|
||||
"root_block_device": cty.SetValEmpty(cty.EmptyObject),
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-BEFORE"),
|
||||
"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
|
||||
"volume_type": cty.String,
|
||||
})),
|
||||
}),
|
||||
After: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
|
@ -2486,9 +2536,12 @@ func TestResourceChange_nestedSet(t *testing.T) {
|
|||
}),
|
||||
}),
|
||||
After: cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-AFTER"),
|
||||
"root_block_device": cty.SetValEmpty(cty.EmptyObject),
|
||||
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
||||
"ami": cty.StringVal("ami-AFTER"),
|
||||
"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
|
||||
"volume_type": cty.String,
|
||||
"new_field": cty.String,
|
||||
})),
|
||||
}),
|
||||
RequiredReplace: cty.NewPathSet(),
|
||||
Tainted: false,
|
||||
|
@ -2549,14 +2602,28 @@ func runTestCases(t *testing.T, testCases map[string]testCase) {
|
|||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ty := tc.Schema.ImpliedType()
|
||||
|
||||
beforeVal := tc.Before
|
||||
before, err := plans.NewDynamicValue(beforeVal, beforeVal.Type())
|
||||
switch { // Some fixups to make the test cases a little easier to write
|
||||
case beforeVal.IsNull():
|
||||
beforeVal = cty.NullVal(ty) // allow mistyped nulls
|
||||
case !beforeVal.IsKnown():
|
||||
beforeVal = cty.UnknownVal(ty) // allow mistyped unknowns
|
||||
}
|
||||
before, err := plans.NewDynamicValue(beforeVal, ty)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
afterVal := tc.After
|
||||
after, err := plans.NewDynamicValue(afterVal, afterVal.Type())
|
||||
switch { // Some fixups to make the test cases a little easier to write
|
||||
case afterVal.IsNull():
|
||||
afterVal = cty.NullVal(ty) // allow mistyped nulls
|
||||
case !afterVal.IsKnown():
|
||||
afterVal = cty.UnknownVal(ty) // allow mistyped unknowns
|
||||
}
|
||||
after, err := plans.NewDynamicValue(afterVal, ty)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue