Skip to content

Commit

Permalink
Merge pull request #33377 from hashicorp/jbardin/nesting-set-length
Browse files Browse the repository at this point in the history
objchange: set length is unknown with partially known elements
  • Loading branch information
jbardin committed Jun 15, 2023
2 parents 8f6fd86 + 3c8a163 commit 0be4a38
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 11 deletions.
17 changes: 10 additions & 7 deletions internal/plans/objchange/plan_valid.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ func assertPlannedObjectValid(schema *configschema.Object, prior, config, planne
errs = append(errs, path.NewErrorf("planned for existence but config wants absence"))
return errs
}
if !config.IsNull() && !planned.IsKnown() {
errs = append(errs, path.NewErrorf("planned unknown for configured value"))
return errs
}

if planned.IsNull() {
// No further checks possible if the planned value is null
return errs
Expand Down Expand Up @@ -442,16 +447,14 @@ func assertPlannedObjectValid(schema *configschema.Object, prior, config, planne
}

case configschema.NestingSet:
plannedL := planned.Length()
configL := config.Length()

// config wasn't known, then planned should be unknown too
if !plannedL.IsKnown() && !configL.IsKnown() {
if !planned.IsKnown() || !config.IsKnown() {
// if either is unknown we cannot check the lengths
return errs
}

lenEqual := plannedL.Equals(configL)
if !lenEqual.IsKnown() || lenEqual.False() {
plannedL := planned.LengthInt()
configL := config.LengthInt()
if plannedL != configL {
errs = append(errs, path.NewErrorf("count in plan (%#v) disagrees with count in config (%#v)", plannedL, configL))
return errs
}
Expand Down
70 changes: 66 additions & 4 deletions internal/plans/objchange/plan_valid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1700,7 +1700,7 @@ func TestAssertPlanValid(t *testing.T) {
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"set": {
Computed: true,
//Computed: true,
Optional: true,
NestedType: &configschema.Object{
Nesting: configschema.NestingSet,
Expand Down Expand Up @@ -1796,9 +1796,9 @@ func TestAssertPlanValid(t *testing.T) {
)),
}),
[]string{
`.set: count in plan (cty.UnknownVal(cty.Number).Refine().NotNull().NumberLowerBound(cty.NumberIntVal(0), true).NumberUpperBound(cty.NumberIntVal(9.223372036854775807e+18), true).NewValue()) disagrees with count in config (cty.NumberIntVal(1))`,
`.list: count in plan (cty.UnknownVal(cty.Number).Refine().NotNull().NumberLowerBound(cty.NumberIntVal(0), true).NumberUpperBound(cty.NumberIntVal(9.223372036854775807e+18), true).NewValue()) disagrees with count in config (cty.NumberIntVal(1))`,
`.map: count in plan (cty.UnknownVal(cty.Number).Refine().NotNull().NumberLowerBound(cty.NumberIntVal(0), true).NumberUpperBound(cty.NumberIntVal(9.223372036854775807e+18), true).NewValue()) disagrees with count in config (cty.NumberIntVal(1))`,
`.set: planned unknown for configured value`,
`.list: planned unknown for configured value`,
`.map: planned unknown for configured value`,
},
},

Expand Down Expand Up @@ -1829,6 +1829,68 @@ func TestAssertPlanValid(t *testing.T) {
}),
nil,
},

"nested set values can contain computed unknown": {
&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"set": {
Optional: true,
NestedType: &configschema.Object{
Nesting: configschema.NestingSet,
Attributes: map[string]*configschema.Attribute{
"input": {
Type: cty.String,
Optional: true,
},
"computed": {
Type: cty.String,
Computed: true,
Optional: true,
},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"set": cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"input": cty.StringVal("a"),
"computed": cty.NullVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"input": cty.StringVal("b"),
"computed": cty.NullVal(cty.String),
}),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"set": cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"input": cty.StringVal("a"),
"computed": cty.NullVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"input": cty.StringVal("b"),
"computed": cty.NullVal(cty.String),
}),
}),
}),
// Plan can mark the null computed values as unknown
cty.ObjectVal(map[string]cty.Value{
"set": cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"input": cty.StringVal("a"),
"computed": cty.UnknownVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"input": cty.StringVal("b"),
"computed": cty.UnknownVal(cty.String),
}),
}),
}),
[]string{},
},
}

for name, test := range tests {
Expand Down

0 comments on commit 0be4a38

Please sign in to comment.