Skip to content

Commit 6f64f84

Browse files
committed
sets
1 parent c03e37b commit 6f64f84

File tree

4 files changed

+227
-44
lines changed

4 files changed

+227
-44
lines changed

internal/fwserver/attribute_plan_modification_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,44 @@ func TestAttributeModifyPlan(t *testing.T) {
15911591
},
15921592
},
15931593
),
1594+
State: tfsdk.State{
1595+
Raw: tftypes.NewValue(
1596+
tftypes.Object{
1597+
AttributeTypes: map[string]tftypes.Type{
1598+
"test": tftypes.Set{
1599+
ElementType: tftypes.Object{
1600+
AttributeTypes: map[string]tftypes.Type{
1601+
"nested_computed": tftypes.String,
1602+
},
1603+
},
1604+
},
1605+
},
1606+
},
1607+
map[string]tftypes.Value{
1608+
"test": tftypes.NewValue(
1609+
tftypes.Set{
1610+
ElementType: tftypes.Object{
1611+
AttributeTypes: map[string]tftypes.Type{
1612+
"nested_computed": tftypes.String,
1613+
},
1614+
},
1615+
},
1616+
[]tftypes.Value{
1617+
tftypes.NewValue(
1618+
tftypes.Object{
1619+
AttributeTypes: map[string]tftypes.Type{
1620+
"nested_computed": tftypes.String,
1621+
},
1622+
},
1623+
map[string]tftypes.Value{
1624+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
1625+
},
1626+
),
1627+
},
1628+
),
1629+
},
1630+
),
1631+
},
15941632
AttributeState: types.SetValueMust(
15951633
types.ObjectType{
15961634
AttrTypes: map[string]attr.Type{
@@ -1673,6 +1711,44 @@ func TestAttributeModifyPlan(t *testing.T) {
16731711
},
16741712
),
16751713
},
1714+
State: tfsdk.State{
1715+
Raw: tftypes.NewValue(
1716+
tftypes.Object{
1717+
AttributeTypes: map[string]tftypes.Type{
1718+
"test": tftypes.Set{
1719+
ElementType: tftypes.Object{
1720+
AttributeTypes: map[string]tftypes.Type{
1721+
"nested_computed": tftypes.String,
1722+
},
1723+
},
1724+
},
1725+
},
1726+
},
1727+
map[string]tftypes.Value{
1728+
"test": tftypes.NewValue(
1729+
tftypes.Set{
1730+
ElementType: tftypes.Object{
1731+
AttributeTypes: map[string]tftypes.Type{
1732+
"nested_computed": tftypes.String,
1733+
},
1734+
},
1735+
},
1736+
[]tftypes.Value{
1737+
tftypes.NewValue(
1738+
tftypes.Object{
1739+
AttributeTypes: map[string]tftypes.Type{
1740+
"nested_computed": tftypes.String,
1741+
},
1742+
},
1743+
map[string]tftypes.Value{
1744+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
1745+
},
1746+
),
1747+
},
1748+
),
1749+
},
1750+
),
1751+
},
16761752
AttributeState: testtypes.SetValueWithSemanticEquals{
16771753
SetValue: types.SetValueMust(
16781754
types.ObjectType{

internal/fwserver/block_plan_modification_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3045,6 +3045,44 @@ func TestBlockModifyPlan(t *testing.T) {
30453045
},
30463046
},
30473047
),
3048+
State: tfsdk.State{
3049+
Raw: tftypes.NewValue(
3050+
tftypes.Object{
3051+
AttributeTypes: map[string]tftypes.Type{
3052+
"test": tftypes.Set{
3053+
ElementType: tftypes.Object{
3054+
AttributeTypes: map[string]tftypes.Type{
3055+
"nested_computed": tftypes.String,
3056+
},
3057+
},
3058+
},
3059+
},
3060+
},
3061+
map[string]tftypes.Value{
3062+
"test": tftypes.NewValue(
3063+
tftypes.Set{
3064+
ElementType: tftypes.Object{
3065+
AttributeTypes: map[string]tftypes.Type{
3066+
"nested_computed": tftypes.String,
3067+
},
3068+
},
3069+
},
3070+
[]tftypes.Value{
3071+
tftypes.NewValue(
3072+
tftypes.Object{
3073+
AttributeTypes: map[string]tftypes.Type{
3074+
"nested_computed": tftypes.String,
3075+
},
3076+
},
3077+
map[string]tftypes.Value{
3078+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
3079+
},
3080+
),
3081+
},
3082+
),
3083+
},
3084+
),
3085+
},
30483086
AttributeState: types.SetValueMust(
30493087
types.ObjectType{
30503088
AttrTypes: map[string]attr.Type{
@@ -3124,6 +3162,44 @@ func TestBlockModifyPlan(t *testing.T) {
31243162
},
31253163
),
31263164
},
3165+
State: tfsdk.State{
3166+
Raw: tftypes.NewValue(
3167+
tftypes.Object{
3168+
AttributeTypes: map[string]tftypes.Type{
3169+
"test": tftypes.Set{
3170+
ElementType: tftypes.Object{
3171+
AttributeTypes: map[string]tftypes.Type{
3172+
"nested_computed": tftypes.String,
3173+
},
3174+
},
3175+
},
3176+
},
3177+
},
3178+
map[string]tftypes.Value{
3179+
"test": tftypes.NewValue(
3180+
tftypes.Set{
3181+
ElementType: tftypes.Object{
3182+
AttributeTypes: map[string]tftypes.Type{
3183+
"nested_computed": tftypes.String,
3184+
},
3185+
},
3186+
},
3187+
[]tftypes.Value{
3188+
tftypes.NewValue(
3189+
tftypes.Object{
3190+
AttributeTypes: map[string]tftypes.Type{
3191+
"nested_computed": tftypes.String,
3192+
},
3193+
},
3194+
map[string]tftypes.Value{
3195+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
3196+
},
3197+
),
3198+
},
3199+
),
3200+
},
3201+
),
3202+
},
31273203
AttributeState: testtypes.SetValueWithSemanticEquals{
31283204
SetValue: types.SetValueMust(
31293205
types.ObjectType{

resource/schema/setplanmodifier/use_state_for_unknown.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ func (m useStateForUnknownModifier) MarkdownDescription(_ context.Context) strin
3636

3737
// PlanModifySet implements the plan modification logic.
3838
func (m useStateForUnknownModifier) PlanModifySet(_ context.Context, req planmodifier.SetRequest, resp *planmodifier.SetResponse) {
39-
// Do nothing if there is no state value.
40-
if req.StateValue.IsNull() {
39+
// Do nothing if there is no state (resource is being created).
40+
if req.State.Raw.IsNull() {
4141
return
4242
}
4343

resource/schema/setplanmodifier/use_state_for_unknown_test.go

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import (
99

1010
"github.com/google/go-cmp/cmp"
1111
"github.com/hashicorp/terraform-plugin-framework/attr"
12-
"github.com/hashicorp/terraform-plugin-framework/path"
1312
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1413
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
14+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
1515
"github.com/hashicorp/terraform-plugin-framework/types"
16+
"github.com/hashicorp/terraform-plugin-go/tftypes"
1617
)
1718

1819
func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) {
@@ -26,6 +27,16 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) {
2627
// when we first create the resource, use the unknown
2728
// value
2829
request: planmodifier.SetRequest{
30+
State: tfsdk.State{
31+
Raw: tftypes.NewValue(
32+
tftypes.Object{
33+
AttributeTypes: map[string]tftypes.Type{
34+
"attr": tftypes.Set{ElementType: tftypes.String},
35+
},
36+
},
37+
nil,
38+
),
39+
},
2940
StateValue: types.SetNull(types.StringType),
3041
PlanValue: types.SetUnknown(types.StringType),
3142
ConfigValue: types.SetNull(types.StringType),
@@ -42,6 +53,23 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) {
4253
// but we still want to preserve that value, in this
4354
// case
4455
request: planmodifier.SetRequest{
56+
State: tfsdk.State{
57+
Raw: tftypes.NewValue(
58+
tftypes.Object{
59+
AttributeTypes: map[string]tftypes.Type{
60+
"attr": tftypes.Set{ElementType: tftypes.String},
61+
},
62+
},
63+
map[string]tftypes.Value{
64+
"attr": tftypes.NewValue(
65+
tftypes.Set{ElementType: tftypes.String},
66+
[]tftypes.Value{
67+
tftypes.NewValue(tftypes.String, "other"),
68+
},
69+
),
70+
},
71+
),
72+
},
4573
StateValue: types.SetValueMust(types.StringType, []attr.Value{types.StringValue("other")}),
4674
PlanValue: types.SetValueMust(types.StringType, []attr.Value{types.StringValue("test")}),
4775
ConfigValue: types.SetNull(types.StringType),
@@ -50,10 +78,27 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) {
5078
PlanValue: types.SetValueMust(types.StringType, []attr.Value{types.StringValue("test")}),
5179
},
5280
},
53-
"non-null-state-unknown-plan": {
81+
"non-null-state-value-unknown-plan": {
5482
// this is the situation we want to preserve the state
5583
// in
5684
request: planmodifier.SetRequest{
85+
State: tfsdk.State{
86+
Raw: tftypes.NewValue(
87+
tftypes.Object{
88+
AttributeTypes: map[string]tftypes.Type{
89+
"attr": tftypes.Set{ElementType: tftypes.String},
90+
},
91+
},
92+
map[string]tftypes.Value{
93+
"attr": tftypes.NewValue(
94+
tftypes.Set{ElementType: tftypes.String},
95+
[]tftypes.Value{
96+
tftypes.NewValue(tftypes.String, "test"),
97+
},
98+
),
99+
},
100+
),
101+
},
57102
StateValue: types.SetValueMust(types.StringType, []attr.Value{types.StringValue("test")}),
58103
PlanValue: types.SetUnknown(types.StringType),
59104
ConfigValue: types.SetNull(types.StringType),
@@ -62,6 +107,32 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) {
62107
PlanValue: types.SetValueMust(types.StringType, []attr.Value{types.StringValue("test")}),
63108
},
64109
},
110+
"null-state-value-unknown-plan": {
111+
// Null state values are still known, so we should preserve this as well.
112+
request: planmodifier.SetRequest{
113+
State: tfsdk.State{
114+
Raw: tftypes.NewValue(
115+
tftypes.Object{
116+
AttributeTypes: map[string]tftypes.Type{
117+
"attr": tftypes.Set{ElementType: tftypes.String},
118+
},
119+
},
120+
map[string]tftypes.Value{
121+
"attr": tftypes.NewValue(
122+
tftypes.Set{ElementType: tftypes.String},
123+
nil,
124+
),
125+
},
126+
),
127+
},
128+
StateValue: types.SetNull(types.StringType),
129+
PlanValue: types.SetUnknown(types.StringType),
130+
ConfigValue: types.SetNull(types.StringType),
131+
},
132+
expected: &planmodifier.SetResponse{
133+
PlanValue: types.SetNull(types.StringType),
134+
},
135+
},
65136
"unknown-config": {
66137
// this is the situation in which a user is
67138
// interpolating into a field. We want that to still
@@ -78,46 +149,6 @@ func TestUseStateForUnknownModifierPlanModifySet(t *testing.T) {
78149
PlanValue: types.SetUnknown(types.StringType),
79150
},
80151
},
81-
"under-list": {
82-
request: planmodifier.SetRequest{
83-
ConfigValue: types.SetNull(types.StringType),
84-
Path: path.Root("test").AtListIndex(0).AtName("nested_test"),
85-
PlanValue: types.SetUnknown(types.StringType),
86-
StateValue: types.SetNull(types.StringType),
87-
},
88-
expected: &planmodifier.SetResponse{
89-
PlanValue: types.SetUnknown(types.StringType),
90-
},
91-
},
92-
"under-set": {
93-
request: planmodifier.SetRequest{
94-
ConfigValue: types.SetNull(types.StringType),
95-
Path: path.Root("test").AtSetValue(
96-
types.SetValueMust(
97-
types.ObjectType{
98-
AttrTypes: map[string]attr.Type{
99-
"nested_test": types.SetType{ElemType: types.StringType},
100-
},
101-
},
102-
[]attr.Value{
103-
types.ObjectValueMust(
104-
map[string]attr.Type{
105-
"nested_test": types.SetType{ElemType: types.StringType},
106-
},
107-
map[string]attr.Value{
108-
"nested_test": types.SetUnknown(types.StringType),
109-
},
110-
),
111-
},
112-
),
113-
).AtName("nested_test"),
114-
PlanValue: types.SetUnknown(types.StringType),
115-
StateValue: types.SetNull(types.StringType),
116-
},
117-
expected: &planmodifier.SetResponse{
118-
PlanValue: types.SetUnknown(types.StringType),
119-
},
120-
},
121152
}
122153

123154
for name, testCase := range testCases {

0 commit comments

Comments
 (0)