From 2b4101fdff6a2fc575e123134bf5c8e321c34921 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 23 Jul 2020 15:32:23 -0400 Subject: [PATCH] Unknown set blocks with dynamic may have 0 elems The couldHaveUnknownBlockPlaceholder helper was added to detect when a set block has a placeholder for an unknown number of values. This worked fine when the number increased from 1, but we were still attempting to validate the unknown placeholder against the empty set when the final count turned out to be 0. Since we can't differentiate the unknown dynamic placeholder value from an actual set value, we have to skip that object's validation altogether. --- plans/objchange/compatible.go | 12 +++---- plans/objchange/compatible_test.go | 53 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/plans/objchange/compatible.go b/plans/objchange/compatible.go index 8b3aeedbf..4f944775a 100644 --- a/plans/objchange/compatible.go +++ b/plans/objchange/compatible.go @@ -168,12 +168,6 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu continue } - setErrs := assertSetValuesCompatible(plannedV, actualV, path, func(plannedEV, actualEV cty.Value) bool { - errs := assertObjectCompatible(&blockS.Block, plannedEV, actualEV, append(path, cty.IndexStep{Key: actualEV})) - return len(errs) == 0 - }) - errs = append(errs, setErrs...) - if maybeUnknownBlocks { // When unknown blocks are present the final number of blocks // may be different, either because the unknown set values @@ -184,6 +178,12 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu continue } + setErrs := assertSetValuesCompatible(plannedV, actualV, path, func(plannedEV, actualEV cty.Value) bool { + errs := assertObjectCompatible(&blockS.Block, plannedEV, actualEV, append(path, cty.IndexStep{Key: actualEV})) + return len(errs) == 0 + }) + errs = append(errs, setErrs...) + // There can be fewer elements in a set after its elements are all // known (values that turn out to be equal will coalesce) but the // number of elements must never get larger. diff --git a/plans/objchange/compatible_test.go b/plans/objchange/compatible_test.go index 473ee5119..4c67e610d 100644 --- a/plans/objchange/compatible_test.go +++ b/plans/objchange/compatible_test.go @@ -1163,6 +1163,59 @@ func TestAssertObjectCompatible(t *testing.T) { }), nil, }, + // test a set with an unknown dynamic count going to 0 values + { + &configschema.Block{ + BlockTypes: map[string]*configschema.NestedBlock{ + "block2": { + Nesting: configschema.NestingSet, + Block: schemaWithFoo, + }, + }, + }, + cty.ObjectVal(map[string]cty.Value{ + "block2": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.UnknownVal(cty.String), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "block2": cty.SetValEmpty(cty.Object(map[string]cty.Type{ + "foo": cty.String, + })), + }), + nil, + }, + // test a set with a patially known dynamic count reducing it's values + { + &configschema.Block{ + BlockTypes: map[string]*configschema.NestedBlock{ + "block3": { + Nesting: configschema.NestingSet, + Block: schemaWithFoo, + }, + }, + }, + cty.ObjectVal(map[string]cty.Value{ + "block3": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("a"), + }), + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.UnknownVal(cty.String), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "block3": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("a"), + }), + }), + }), + nil, + }, { &configschema.Block{ BlockTypes: map[string]*configschema.NestedBlock{