Skip to content

Commit ae39da3

Browse files
committed
map
1 parent e391030 commit ae39da3

File tree

3 files changed

+151
-44
lines changed

3 files changed

+151
-44
lines changed

internal/fwserver/attribute_plan_modification_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2949,6 +2949,44 @@ func TestAttributeModifyPlan(t *testing.T) {
29492949
},
29502950
},
29512951
),
2952+
State: tfsdk.State{
2953+
Raw: tftypes.NewValue(
2954+
tftypes.Object{
2955+
AttributeTypes: map[string]tftypes.Type{
2956+
"test": tftypes.Map{
2957+
ElementType: tftypes.Object{
2958+
AttributeTypes: map[string]tftypes.Type{
2959+
"nested_computed": tftypes.String,
2960+
},
2961+
},
2962+
},
2963+
},
2964+
},
2965+
map[string]tftypes.Value{
2966+
"test": tftypes.NewValue(
2967+
tftypes.Map{
2968+
ElementType: tftypes.Object{
2969+
AttributeTypes: map[string]tftypes.Type{
2970+
"nested_computed": tftypes.String,
2971+
},
2972+
},
2973+
},
2974+
map[string]tftypes.Value{
2975+
"key1": tftypes.NewValue(
2976+
tftypes.Object{
2977+
AttributeTypes: map[string]tftypes.Type{
2978+
"nested_computed": tftypes.String,
2979+
},
2980+
},
2981+
map[string]tftypes.Value{
2982+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
2983+
},
2984+
),
2985+
},
2986+
),
2987+
},
2988+
),
2989+
},
29522990
AttributeState: types.MapValueMust(
29532991
types.ObjectType{
29542992
AttrTypes: map[string]attr.Type{
@@ -3031,6 +3069,44 @@ func TestAttributeModifyPlan(t *testing.T) {
30313069
},
30323070
),
30333071
},
3072+
State: tfsdk.State{
3073+
Raw: tftypes.NewValue(
3074+
tftypes.Object{
3075+
AttributeTypes: map[string]tftypes.Type{
3076+
"test": tftypes.Map{
3077+
ElementType: tftypes.Object{
3078+
AttributeTypes: map[string]tftypes.Type{
3079+
"nested_computed": tftypes.String,
3080+
},
3081+
},
3082+
},
3083+
},
3084+
},
3085+
map[string]tftypes.Value{
3086+
"test": tftypes.NewValue(
3087+
tftypes.Map{
3088+
ElementType: tftypes.Object{
3089+
AttributeTypes: map[string]tftypes.Type{
3090+
"nested_computed": tftypes.String,
3091+
},
3092+
},
3093+
},
3094+
map[string]tftypes.Value{
3095+
"key1": tftypes.NewValue(
3096+
tftypes.Object{
3097+
AttributeTypes: map[string]tftypes.Type{
3098+
"nested_computed": tftypes.String,
3099+
},
3100+
},
3101+
map[string]tftypes.Value{
3102+
"nested_computed": tftypes.NewValue(tftypes.String, "statevalue1"),
3103+
},
3104+
),
3105+
},
3106+
),
3107+
},
3108+
),
3109+
},
30343110
AttributeState: testtypes.MapValueWithSemanticEquals{
30353111
MapValue: types.MapValueMust(
30363112
types.ObjectType{

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

123154
for name, testCase := range testCases {

0 commit comments

Comments
 (0)