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 9ad4bfa7..8daed501 100644 --- a/internal/provider/resource_id.go +++ b/internal/provider/resource_id.go @@ -226,8 +226,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 a6fb758b..9c207698 100644 --- a/internal/provider/resource_id_test.go +++ b/internal/provider/resource_id_test.go @@ -59,6 +59,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 a70e53c1..91293e09 100644 --- a/internal/provider/resource_integer.go +++ b/internal/provider/resource_integer.go @@ -202,8 +202,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 2d71b6bc..b224e999 100644 --- a/internal/provider/resource_integer_test.go +++ b/internal/provider/resource_integer_test.go @@ -36,6 +36,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 1553f356..c3400c1b 100644 --- a/internal/provider/resource_password_test.go +++ b/internal/provider/resource_password_test.go @@ -324,6 +324,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 1b3dec10..84af2fc8 100644 --- a/internal/provider/resource_string_test.go +++ b/internal/provider/resource_string_test.go @@ -37,6 +37,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 75e0167b..c54dd279 100644 --- a/internal/provider/resource_uuid.go +++ b/internal/provider/resource_uuid.go @@ -150,7 +150,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 d86d901a..6e492854 100644 --- a/internal/provider/resource_uuid_test.go +++ b/internal/provider/resource_uuid_test.go @@ -30,6 +30,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