hashicorp / hashicorp/terraform-plugin-framework

Non-empty PostApplyPreRefresh plan of optional & computed ListNestedObject attribute with Required NestedAttribute

Open
#1,101 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
Go
Stars
384
Forks
107
Avg merge
3m
Merged PRs (30d)
1

Description

### Module version

```
v1.14.1
```

### Relevant provider source code

```go

"monitoring_metrics": schema.ListNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Required: true,
},
"type": schema.StringAttribute{
Required: true,
},
},
CustomType: MonitoringMetricsType{
ObjectType: types.ObjectType{
AttrTypes: MonitoringMetricsValue{}.AttributeTypes(ctx),
},
},
},
Optional: true,
Computed: true,
},

```

### Terraform Configuration Files

```hcl
resource "statsig_gate" "my_gate" {
name = "my_gate"
description = "A short description of what this Gate is used for."
is_enabled = true
id_type = "userID"
rules = [
{
name = "All Conditions"
pass_percentage = 10
environments = ["production"]
conditions = [
{
type = "public"
target_value = []
},
{
type = "user_id"
target_value = [
"1", "2"
]
operator = "any"
},
{
type = "email"
target_value = ["@outlook.com", "@gmail.com"]
operator = "str_contains_any"
},
{
type = "custom_field"
target_value = [31]
operator = "gt"
field = "age"
},
{
type = "app_version"
target_value = ["1.1.1"]
operator = "version_gt"
},
{
type = "browser_name"
target_value = ["Firefox", "Chrome"]
operator = "any"
},
{
type = "browser_version"
target_value = ["94.0.4606.81", "94.0.4606.92"]
operator = "any"
},
{
type = "os_name"
target_value = ["Android", "Windows"]
operator = "none"
},
{
type = "os_version"
target_value = ["11.0.0"]
operator = "version_lte"
},
{
type = "country"
target_value = ["NZ", "US"]
operator = "any"
},
{
type = "passes_gate"
target_value = ["my_gate_2"]
},
{
type = "fails_gate"
target_value = ["a_failing_gate"]
},
{
type = "time"
target_value = [1643070357193]
operator = "after"
},
{
type = "environment_tier"
target_value = ["production"]
operator = "any"
},
{
type = "passes_segment"
target_value = ["growth_org"]
},
{
type = "fails_segment"
target_value = ["promo_id_list"]
},
{
type = "ip_address"
target_value = ["1.1.1.1", "8.8.8.8"]
operator = "any"
}
]
},
{
name = "Development Conditions"
pass_percentage = 10
conditions = [
{
type = "public"
target_value = []
}
]
environments = ["development"]
}
]
}

output "my_gate" {
value = statsig_gate.my_gate
}

```

### Debug Output

https://gist.github.com/kenny-statsig/520dfc886304df384b44d816bfa179ff

### Expected Behavior

The provider should have an empty non-refresh plan

### Actual Behavior

The acceptance test fails due to a non-empty plan. The prior state doesn't match the planned state because the planned state is null for `monitoring_metrics` even though the state is being set properly upon `Create` (output of `resp.State.Raw` https://gist.github.com/kenny-statsig/83a940eed74ef791d56ef824bf0076f2)
Prior: `"monitoring_metrics":tftypes.List[tftypes.Object["name":tftypes.String, "type":tftypes.String]], "type":tftypes.String<"user">>>`
Planned: `"monitoring_metrics":tftypes.List[tftypes.Object["name":tftypes.String, "type":tftypes.String]]`
Full diff: https://www.diffchecker.com/YT9HvE9p/

Here are some code snippets of the provider's implementation
`gate.go` https://gist.github.com/kenny-statsig/d5a3f43021df0b0d5fd30216103ee70b
`util.go` https://gist.github.com/kenny-statsig/dad3239d769dc967a44ef061b0d566dd
`gate_resource.go` https://gist.github.com/kenny-statsig/b3b9843e27fed30f0c90b018e428e4e1

### Steps to Reproduce

Provider is still in development so cannot be reproduced externally.
But it's a simple acceptance test

```go
func TestAccGateFull_MUX(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: protoV6ProviderFactories(),
PreCheck: func() { testAccPreCheck(t) },
Steps: []resource.TestStep{
{
ConfigFile: config.StaticFile("test_resources/gate_full.tf"),
Check: resource.ComposeTestCheckFunc(
verifyFullGateSetup(t, "statsig_gate.my_gate"),
verifyFullGateOutput(t),
),
},
{
ConfigFile: config.StaticFile("test_resources/gate_full.tf"),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})
}
```

### References

Seems to be the same issue described here https://discuss.hashicorp.com/t/computed-attributes-and-plan-modifiers/45830/20

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.