Skip to content

Commit e391030

Browse files
committed
list
1 parent 6f64f84 commit e391030

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
@@ -641,6 +641,44 @@ func TestAttributeModifyPlan(t *testing.T) {
641641
},
642642
},
643643
),
644+
State: tfsdk.State{
645+
Raw: tftypes.NewValue(
646+
tftypes.Object{
647+
AttributeTypes: map[string]tftypes.Type{
648+
"test": tftypes.List{
649+
ElementType: tftypes.Object{
650+
AttributeTypes: map[string]tftypes.Type{
651+
"nested_computed": tftypes.String,
652+
},
653+
},
654+
},
655+
},
656+
},
657+
map[string]tftypes.Value{
658+
"test": tftypes.NewValue(
659+
tftypes.List{
660+
ElementType: tftypes.Object{
661+
AttributeTypes: map[string]tftypes.Type{
662+
"nested_computed": tftypes.String,
663+
},
664+
},
665+
},
666+
[]tftypes.Value{
667+
tftypes.NewValue(
668+
tftypes.Object{
669+
AttributeTypes: map[string]tftypes.Type{
670+
"nested_computed": tftypes.String,
671+
},
672+
},
673+
map[string]tftypes.Value{
674+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
675+
},
676+
),
677+
},
678+
),
679+
},
680+
),
681+
},
644682
AttributeState: types.ListValueMust(
645683
types.ObjectType{
646684
AttrTypes: map[string]attr.Type{
@@ -723,6 +761,44 @@ func TestAttributeModifyPlan(t *testing.T) {
723761
},
724762
),
725763
},
764+
State: tfsdk.State{
765+
Raw: tftypes.NewValue(
766+
tftypes.Object{
767+
AttributeTypes: map[string]tftypes.Type{
768+
"test": tftypes.List{
769+
ElementType: tftypes.Object{
770+
AttributeTypes: map[string]tftypes.Type{
771+
"nested_computed": tftypes.String,
772+
},
773+
},
774+
},
775+
},
776+
},
777+
map[string]tftypes.Value{
778+
"test": tftypes.NewValue(
779+
tftypes.List{
780+
ElementType: tftypes.Object{
781+
AttributeTypes: map[string]tftypes.Type{
782+
"nested_computed": tftypes.String,
783+
},
784+
},
785+
},
786+
[]tftypes.Value{
787+
tftypes.NewValue(
788+
tftypes.Object{
789+
AttributeTypes: map[string]tftypes.Type{
790+
"nested_computed": tftypes.String,
791+
},
792+
},
793+
map[string]tftypes.Value{
794+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
795+
},
796+
),
797+
},
798+
),
799+
},
800+
),
801+
},
726802
AttributeState: testtypes.ListValueWithSemanticEquals{
727803
ListValue: types.ListValueMust(
728804
types.ObjectType{

internal/fwserver/block_plan_modification_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,44 @@ func TestBlockModifyPlan(t *testing.T) {
996996
},
997997
},
998998
),
999+
State: tfsdk.State{
1000+
Raw: tftypes.NewValue(
1001+
tftypes.Object{
1002+
AttributeTypes: map[string]tftypes.Type{
1003+
"test": tftypes.List{
1004+
ElementType: tftypes.Object{
1005+
AttributeTypes: map[string]tftypes.Type{
1006+
"nested_computed": tftypes.String,
1007+
},
1008+
},
1009+
},
1010+
},
1011+
},
1012+
map[string]tftypes.Value{
1013+
"test": tftypes.NewValue(
1014+
tftypes.List{
1015+
ElementType: tftypes.Object{
1016+
AttributeTypes: map[string]tftypes.Type{
1017+
"nested_computed": tftypes.String,
1018+
},
1019+
},
1020+
},
1021+
[]tftypes.Value{
1022+
tftypes.NewValue(
1023+
tftypes.Object{
1024+
AttributeTypes: map[string]tftypes.Type{
1025+
"nested_computed": tftypes.String,
1026+
},
1027+
},
1028+
map[string]tftypes.Value{
1029+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
1030+
},
1031+
),
1032+
},
1033+
),
1034+
},
1035+
),
1036+
},
9991037
AttributeState: types.ListValueMust(
10001038
types.ObjectType{
10011039
AttrTypes: map[string]attr.Type{
@@ -1075,6 +1113,44 @@ func TestBlockModifyPlan(t *testing.T) {
10751113
},
10761114
),
10771115
},
1116+
State: tfsdk.State{
1117+
Raw: tftypes.NewValue(
1118+
tftypes.Object{
1119+
AttributeTypes: map[string]tftypes.Type{
1120+
"test": tftypes.List{
1121+
ElementType: tftypes.Object{
1122+
AttributeTypes: map[string]tftypes.Type{
1123+
"nested_computed": tftypes.String,
1124+
},
1125+
},
1126+
},
1127+
},
1128+
},
1129+
map[string]tftypes.Value{
1130+
"test": tftypes.NewValue(
1131+
tftypes.List{
1132+
ElementType: tftypes.Object{
1133+
AttributeTypes: map[string]tftypes.Type{
1134+
"nested_computed": tftypes.String,
1135+
},
1136+
},
1137+
},
1138+
[]tftypes.Value{
1139+
tftypes.NewValue(
1140+
tftypes.Object{
1141+
AttributeTypes: map[string]tftypes.Type{
1142+
"nested_computed": tftypes.String,
1143+
},
1144+
},
1145+
map[string]tftypes.Value{
1146+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
1147+
},
1148+
),
1149+
},
1150+
),
1151+
},
1152+
),
1153+
},
10781154
AttributeState: testtypes.ListValueWithSemanticEquals{
10791155
ListValue: types.ListValueMust(
10801156
types.ObjectType{

resource/schema/listplanmodifier/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
// PlanModifyList implements the plan modification logic.
3838
func (m useStateForUnknownModifier) PlanModifyList(_ context.Context, req planmodifier.ListRequest, resp *planmodifier.ListResponse) {
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/listplanmodifier/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/listplanmodifier"
1413
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
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 TestUseStateForUnknownModifierPlanModifyList(t *testing.T) {
@@ -26,6 +27,16 @@ func TestUseStateForUnknownModifierPlanModifyList(t *testing.T) {
2627
// when we first create the resource, use the unknown
2728
// value
2829
request: planmodifier.ListRequest{
30+
State: tfsdk.State{
31+
Raw: tftypes.NewValue(
32+
tftypes.Object{
33+
AttributeTypes: map[string]tftypes.Type{
34+
"attr": tftypes.List{ElementType: tftypes.String},
35+
},
36+
},
37+
nil,
38+
),
39+
},
2940
StateValue: types.ListNull(types.StringType),
3041
PlanValue: types.ListUnknown(types.StringType),
3142
ConfigValue: types.ListNull(types.StringType),
@@ -42,6 +53,23 @@ func TestUseStateForUnknownModifierPlanModifyList(t *testing.T) {
4253
// but we still want to preserve that value, in this
4354
// case
4455
request: planmodifier.ListRequest{
56+
State: tfsdk.State{
57+
Raw: tftypes.NewValue(
58+
tftypes.Object{
59+
AttributeTypes: map[string]tftypes.Type{
60+
"attr": tftypes.List{ElementType: tftypes.String},
61+
},
62+
},
63+
map[string]tftypes.Value{
64+
"attr": tftypes.NewValue(
65+
tftypes.List{ElementType: tftypes.String},
66+
[]tftypes.Value{
67+
tftypes.NewValue(tftypes.String, "other"),
68+
},
69+
),
70+
},
71+
),
72+
},
4573
StateValue: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("other")}),
4674
PlanValue: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("test")}),
4775
ConfigValue: types.ListNull(types.StringType),
@@ -50,10 +78,27 @@ func TestUseStateForUnknownModifierPlanModifyList(t *testing.T) {
5078
PlanValue: types.ListValueMust(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.ListRequest{
85+
State: tfsdk.State{
86+
Raw: tftypes.NewValue(
87+
tftypes.Object{
88+
AttributeTypes: map[string]tftypes.Type{
89+
"attr": tftypes.List{ElementType: tftypes.String},
90+
},
91+
},
92+
map[string]tftypes.Value{
93+
"attr": tftypes.NewValue(
94+
tftypes.List{ElementType: tftypes.String},
95+
[]tftypes.Value{
96+
tftypes.NewValue(tftypes.String, "test"),
97+
},
98+
),
99+
},
100+
),
101+
},
57102
StateValue: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("test")}),
58103
PlanValue: types.ListUnknown(types.StringType),
59104
ConfigValue: types.ListNull(types.StringType),
@@ -62,6 +107,32 @@ func TestUseStateForUnknownModifierPlanModifyList(t *testing.T) {
62107
PlanValue: types.ListValueMust(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.ListRequest{
113+
State: tfsdk.State{
114+
Raw: tftypes.NewValue(
115+
tftypes.Object{
116+
AttributeTypes: map[string]tftypes.Type{
117+
"attr": tftypes.List{ElementType: tftypes.String},
118+
},
119+
},
120+
map[string]tftypes.Value{
121+
"attr": tftypes.NewValue(
122+
tftypes.List{ElementType: tftypes.String},
123+
nil,
124+
),
125+
},
126+
),
127+
},
128+
StateValue: types.ListNull(types.StringType),
129+
PlanValue: types.ListUnknown(types.StringType),
130+
ConfigValue: types.ListNull(types.StringType),
131+
},
132+
expected: &planmodifier.ListResponse{
133+
PlanValue: types.ListNull(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 TestUseStateForUnknownModifierPlanModifyList(t *testing.T) {
78149
PlanValue: types.ListUnknown(types.StringType),
79150
},
80151
},
81-
"under-list": {
82-
request: planmodifier.ListRequest{
83-
ConfigValue: types.ListNull(types.StringType),
84-
Path: path.Root("test").AtListIndex(0).AtName("nested_test"),
85-
PlanValue: types.ListUnknown(types.StringType),
86-
StateValue: types.ListNull(types.StringType),
87-
},
88-
expected: &planmodifier.ListResponse{
89-
PlanValue: types.ListUnknown(types.StringType),
90-
},
91-
},
92-
"under-set": {
93-
request: planmodifier.ListRequest{
94-
ConfigValue: types.ListNull(types.StringType),
95-
Path: path.Root("test").AtSetValue(
96-
types.SetValueMust(
97-
types.ObjectType{
98-
AttrTypes: map[string]attr.Type{
99-
"nested_test": types.ListType{ElemType: types.StringType},
100-
},
101-
},
102-
[]attr.Value{
103-
types.ObjectValueMust(
104-
map[string]attr.Type{
105-
"nested_test": types.ListType{ElemType: types.StringType},
106-
},
107-
map[string]attr.Value{
108-
"nested_test": types.ListUnknown(types.StringType),
109-
},
110-
),
111-
},
112-
),
113-
).AtName("nested_test"),
114-
PlanValue: types.ListUnknown(types.StringType),
115-
StateValue: types.ListNull(types.StringType),
116-
},
117-
expected: &planmodifier.ListResponse{
118-
PlanValue: types.ListUnknown(types.StringType),
119-
},
120-
},
121152
}
122153

123154
for name, testCase := range testCases {

0 commit comments

Comments
 (0)