diff --git a/.changes/unreleased/BUG FIXES-20230313-114526.yaml b/.changes/unreleased/BUG FIXES-20230313-114526.yaml new file mode 100644 index 00000000..c3d85f85 --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20230313-114526.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: 'all: Prevent `keepers` from triggering an in-place update following import' +time: 2023-03-13T11:45:26.616828Z +custom: + Issue: "385" diff --git a/internal/provider/resource_id.go b/internal/provider/resource_id.go index 4613fc91..c632174e 100644 --- a/internal/provider/resource_id.go +++ b/internal/provider/resource_id.go @@ -221,8 +221,7 @@ func (r *idResource) ImportState(ctx context.Context, req resource.ImportStateRe state.ID = types.StringValue(id) state.ByteLength = types.Int64Value(int64(len(bytes))) - // Using types.MapValueMust to ensure map is known. - state.Keepers = types.MapValueMust(types.StringType, nil) + state.Keepers = types.MapNull(types.StringType) state.B64Std = types.StringValue(prefix + b64Std) state.B64URL = types.StringValue(prefix + id) state.Hex = types.StringValue(prefix + hexStr) diff --git a/internal/provider/resource_id_test.go b/internal/provider/resource_id_test.go index 46735ef0..f847a9fe 100644 --- a/internal/provider/resource_id_test.go +++ b/internal/provider/resource_id_test.go @@ -56,6 +56,29 @@ func TestAccResourceID_ImportWithPrefix(t *testing.T) { }) } +func TestAccResourceID_ImportWithoutKeepersProducesNoPlannedChanges(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: `resource "random_id" "foo" { + byte_length = 4 + }`, + ResourceName: "random_id.foo", + ImportStateId: "p-9hUg", + ImportState: true, + ImportStatePersist: true, + }, + { + Config: `resource "random_id" "foo" { + byte_length = 4 + }`, + PlanOnly: true, + }, + }, + }) +} + func TestAccResourceID_UpgradeFromVersion3_3_2(t *testing.T) { resource.Test(t, resource.TestCase{ Steps: []resource.TestStep{ diff --git a/internal/provider/resource_integer.go b/internal/provider/resource_integer.go index 6a059c11..5169db15 100644 --- a/internal/provider/resource_integer.go +++ b/internal/provider/resource_integer.go @@ -199,8 +199,7 @@ func (r *integerResource) ImportState(ctx context.Context, req resource.ImportSt var state integerModelV0 state.ID = types.StringValue(parts[0]) - // Using types.MapValueMust to ensure map is known. - state.Keepers = types.MapValueMust(types.StringType, nil) + state.Keepers = types.MapNull(types.StringType) state.Result = types.Int64Value(result) state.Min = types.Int64Value(min) state.Max = types.Int64Value(max) diff --git a/internal/provider/resource_integer_test.go b/internal/provider/resource_integer_test.go index 4600c91d..19460f01 100644 --- a/internal/provider/resource_integer_test.go +++ b/internal/provider/resource_integer_test.go @@ -33,6 +33,33 @@ func TestAccResourceInteger(t *testing.T) { }) } +func TestAccResourceInteger_ImportWithoutKeepersProducesNoPlannedChanges(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: `resource "random_integer" "integer_1" { + min = 1 + max = 3 + seed = "12345" + }`, + ResourceName: "random_integer.integer_1", + ImportStateId: "3,1,3,12345", + ImportState: true, + ImportStatePersist: true, + }, + { + Config: `resource "random_integer" "integer_1" { + min = 1 + max = 3 + seed = "12345" + }`, + PlanOnly: true, + }, + }, + }) +} + func TestAccResourceInteger_ChangeSeed(t *testing.T) { t.Parallel() resource.UnitTest(t, resource.TestCase{ diff --git a/internal/provider/resource_password_test.go b/internal/provider/resource_password_test.go index cd9a41df..4330fa51 100644 --- a/internal/provider/resource_password_test.go +++ b/internal/provider/resource_password_test.go @@ -280,6 +280,29 @@ func TestAccResourcePassword_OverrideSpecial_FromVersion3_4_2(t *testing.T) { }) } +func TestAccResourcePassword_ImportWithoutKeepersProducesNoPlannedChanges(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: `resource "random_password" "test" { + length = 12 + }`, + ResourceName: "random_password.test", + ImportStateId: "Z=:cbrJE?Ltg", + ImportState: true, + ImportStatePersist: true, + }, + { + Config: `resource "random_password" "test" { + length = 12 + }`, + PlanOnly: true, + }, + }, + }) +} + // TestAccResourcePassword_Import_FromVersion3_1_3 verifies behaviour when resource has been imported and stores // null for length, lower, number, special, upper, min_lower, min_numeric, min_special, min_upper attributes in state. // v3.1.3 was selected as this is the last provider version using schema version 0. diff --git a/internal/provider/resource_string_test.go b/internal/provider/resource_string_test.go index 74fc548a..6b566e6b 100644 --- a/internal/provider/resource_string_test.go +++ b/internal/provider/resource_string_test.go @@ -34,6 +34,29 @@ func TestAccResourceString_Import(t *testing.T) { }) } +func TestAccResourceString_ImportWithoutKeepersProducesNoPlannedChanges(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: `resource "random_string" "basic" { + length = 12 + }`, + ResourceName: "random_string.basic", + ImportStateId: "Z=:cbrJE?Ltg", + ImportState: true, + ImportStatePersist: true, + }, + { + Config: `resource "random_string" "basic" { + length = 12 + }`, + PlanOnly: true, + }, + }, + }) +} + func TestAccResourceString_Keepers_Keep_EmptyMap(t *testing.T) { var id1, id2 string diff --git a/internal/provider/resource_uuid.go b/internal/provider/resource_uuid.go index c6a9f419..0e2030b4 100644 --- a/internal/provider/resource_uuid.go +++ b/internal/provider/resource_uuid.go @@ -147,7 +147,7 @@ func (r *uuidResource) ImportState(ctx context.Context, req resource.ImportState state.ID = types.StringValue(result) state.Result = types.StringValue(result) - state.Keepers = types.MapValueMust(types.StringType, nil) + state.Keepers = types.MapNull(types.StringType) diags := resp.State.Set(ctx, &state) resp.Diagnostics.Append(diags...) diff --git a/internal/provider/resource_uuid_test.go b/internal/provider/resource_uuid_test.go index 7c550416..6d93ab97 100644 --- a/internal/provider/resource_uuid_test.go +++ b/internal/provider/resource_uuid_test.go @@ -27,6 +27,27 @@ func TestAccResourceUUID(t *testing.T) { }) } +func TestAccResourceUUID_ImportWithoutKeepersProducesNoPlannedChanges(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: `resource "random_uuid" "basic" { + }`, + ResourceName: "random_uuid.basic", + ImportStateId: "6b0f8e7c-3ea6-4523-88a2-5a70419ee954", + ImportState: true, + ImportStatePersist: true, + }, + { + Config: `resource "random_uuid" "basic" { + }`, + PlanOnly: true, + }, + }, + }) +} + func TestAccResourceUUID_Keepers_Keep_EmptyMap(t *testing.T) { var id1, id2 string