From dd7dcf7fa561266fd06436fea5e2288a085619ca Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 5 Mar 2025 11:31:01 +0100 Subject: [PATCH 1/5] add test file for import block with id --- .../testing_new_import_block_id_test.go | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 helper/resource/testing_new_import_block_id_test.go diff --git a/helper/resource/testing_new_import_block_id_test.go b/helper/resource/testing_new_import_block_id_test.go new file mode 100644 index 000000000..377882cff --- /dev/null +++ b/helper/resource/testing_new_import_block_id_test.go @@ -0,0 +1,104 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-go/tftypes" + + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver" + "github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestTest_TestStep_ImportBlockId(t *testing.T) { + t.Parallel() + + UnitTest(t, TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_5_0), // ProtoV6ProviderFactories + }, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "examplecloud": providerserver.NewProviderServer(testprovider.Provider{ + Resources: map[string]testprovider.Resource{ + "examplecloud_container": { + CreateResponse: &resource.CreateResponse{ + NewState: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "location": tftypes.String, + "name": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"), + "location": tftypes.NewValue(tftypes.String, "westeurope"), + "name": tftypes.NewValue(tftypes.String, "somevalue"), + }, + ), + }, + ImportStateResponse: &resource.ImportStateResponse{ + State: tftypes.NewValue( + tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "location": tftypes.String, + "name": tftypes.String, + }, + }, + map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"), + "location": tftypes.NewValue(tftypes.String, "westeurope"), + "name": tftypes.NewValue(tftypes.String, "somevalue"), + }, + ), + }, + SchemaResponse: &resource.SchemaResponse{ + Schema: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "id", + Type: tftypes.String, + Computed: true, + }, + { + Name: "location", + Type: tftypes.String, + Required: true, + }, + { + Name: "name", + Type: tftypes.String, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }), + }, + Steps: []TestStep{ + { + Config: ` + resource "examplecloud_container" "test" { + location = "westeurope" + name = "somevalue" + }`, + }, + { + ResourceName: "examplecloud_container.test", + ImportState: true, + ImportStateKind: ImportBlockWithId, + ImportStateVerify: true, + }, + }, + }) +} From c884dead5432bed5b50e69962cb052df6afe67a1 Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 5 Mar 2025 11:32:09 +0100 Subject: [PATCH 2/5] update testing of new import states to support generating import blocks with an id string and calling apply --- helper/resource/testing.go | 10 ++++ helper/resource/testing_new.go | 16 +----- helper/resource/testing_new_import_state.go | 55 ++++++++++++++++++--- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/helper/resource/testing.go b/helper/resource/testing.go index 9e1961a46..e0cd642d8 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -454,6 +454,14 @@ type ExternalProvider struct { Source string // the provider source } +type ImportStateKind byte + +const ( + ImportCommandWithId ImportStateKind = iota + ImportBlockWithId + ImportBlockWithResourceIdentity +) + // TestStep is a single apply sequence of a test, done within the // context of a state. // @@ -633,6 +641,8 @@ type TestStep struct { // ID of that resource. ImportState bool + ImportStateKind ImportStateKind + // ImportStateId is the ID to perform an ImportState operation with. // This is optional. If it isn't set, then the resource ID is automatically // determined by inspecting the state for ResourceName's ID. diff --git a/helper/resource/testing_new.go b/helper/resource/testing_new.go index 0a7c7e7f7..8adeeb18c 100644 --- a/helper/resource/testing_new.go +++ b/helper/resource/testing_new.go @@ -133,7 +133,7 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest // use this to track last step successfully applied // acts as default for import tests - var appliedCfg teststep.Config + var appliedCfg string var stepNumber int for stepIndex, step := range c.Steps { @@ -426,7 +426,7 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest } } - mergedConfig, err := step.mergedConfig(ctx, c, hasTerraformBlock, hasProviderBlock, helper.TerraformVersion()) + appliedCfg, err = step.mergedConfig(ctx, c, hasTerraformBlock, hasProviderBlock, helper.TerraformVersion()) if err != nil { logging.HelperResourceError(ctx, @@ -436,18 +436,6 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest t.Fatalf("Error generating merged configuration: %s", err) } - confRequest := teststep.PrepareConfigurationRequest{ - Directory: step.ConfigDirectory, - File: step.ConfigFile, - Raw: mergedConfig, - TestStepConfigRequest: config.TestStepConfigRequest{ - StepNumber: stepIndex + 1, - TestName: t.Name(), - }, - }.Exec() - - appliedCfg = teststep.Configuration(confRequest) - logging.HelperResourceDebug(ctx, "Finished TestStep") continue diff --git a/helper/resource/testing_new_import_state.go b/helper/resource/testing_new_import_state.go index 7dbc0b800..232e2cf46 100644 --- a/helper/resource/testing_new_import_state.go +++ b/helper/resource/testing_new_import_state.go @@ -6,6 +6,7 @@ package resource import ( "context" "fmt" + "github.com/hashicorp/terraform-exec/tfexec" "reflect" "strings" @@ -20,7 +21,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/internal/plugintest" ) -func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest.Helper, wd *plugintest.WorkingDir, step TestStep, cfg teststep.Config, providers *providerFactories, stepIndex int) error { +func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest.Helper, wd *plugintest.WorkingDir, step TestStep, cfgRaw string, providers *providerFactories, stepIndex int) error { t.Helper() configRequest := teststep.PrepareConfigurationRequest{ @@ -93,11 +94,40 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest logging.HelperResourceTrace(ctx, fmt.Sprintf("Using import identifier: %s", importId)) + if testStepConfig == nil { + logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import") + } + // Create working directory for import tests if testStepConfig == nil { logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import") - testStepConfig = cfg + switch step.ImportStateKind { + case ImportBlockWithResourceIdentity: + t.Fatalf("TODO implement me") + case ImportBlockWithId: + cfgRaw += fmt.Sprintf(` + import { + to = %s + id = %q + } + `, step.ResourceName, importId) + default: + // Not an import block test so nothing to do here + } + + confRequest := teststep.PrepareConfigurationRequest{ + Directory: step.ConfigDirectory, + File: step.ConfigFile, + Raw: cfgRaw, + TestStepConfigRequest: config.TestStepConfigRequest{ + StepNumber: stepIndex + 1, + TestName: t.Name(), + }, + }.Exec() + + testStepConfig = teststep.Configuration(confRequest) + //testStepConfig = cfg if testStepConfig == nil { t.Fatal("Cannot import state with no specified config") } @@ -129,11 +159,22 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest } } - err = runProviderCommand(ctx, t, func() error { - return importWd.Import(ctx, step.ResourceName, importId) - }, importWd, providers) - if err != nil { - return err + if step.ImportStateKind == ImportBlockWithResourceIdentity || step.ImportStateKind == ImportBlockWithId { + var opts []tfexec.ApplyOption + + err = runProviderCommand(ctx, t, func() error { + return importWd.Apply(ctx, opts...) + }, importWd, providers) + if err != nil { + return err + } + } else { + err = runProviderCommand(ctx, t, func() error { + return importWd.Import(ctx, step.ResourceName, importId) + }, importWd, providers) + if err != nil { + return err + } } var importState *terraform.State From 7c757b2fc2b3e6fc6c52ad3824374574563b8ef2 Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 5 Mar 2025 11:49:59 +0100 Subject: [PATCH 3/5] import ordering --- helper/resource/testing_new_import_state.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/helper/resource/testing_new_import_state.go b/helper/resource/testing_new_import_state.go index 232e2cf46..0d5ae795f 100644 --- a/helper/resource/testing_new_import_state.go +++ b/helper/resource/testing_new_import_state.go @@ -6,19 +6,18 @@ package resource import ( "context" "fmt" - "github.com/hashicorp/terraform-exec/tfexec" "reflect" "strings" "github.com/google/go-cmp/cmp" "github.com/mitchellh/go-testing-interface" + "github.com/hashicorp/terraform-exec/tfexec" "github.com/hashicorp/terraform-plugin-testing/config" - "github.com/hashicorp/terraform-plugin-testing/internal/teststep" - "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-plugin-testing/internal/logging" "github.com/hashicorp/terraform-plugin-testing/internal/plugintest" + "github.com/hashicorp/terraform-plugin-testing/internal/teststep" + "github.com/hashicorp/terraform-plugin-testing/terraform" ) func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest.Helper, wd *plugintest.WorkingDir, step TestStep, cfgRaw string, providers *providerFactories, stepIndex int) error { From 4dd7265cb12af22b29966bb63bd0ae9fd3d57ba4 Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 5 Mar 2025 11:52:20 +0100 Subject: [PATCH 4/5] remove duplicate nil check on testStepConfig --- helper/resource/testing_new_import_state.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/helper/resource/testing_new_import_state.go b/helper/resource/testing_new_import_state.go index 0d5ae795f..09cb40af1 100644 --- a/helper/resource/testing_new_import_state.go +++ b/helper/resource/testing_new_import_state.go @@ -93,10 +93,6 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest logging.HelperResourceTrace(ctx, fmt.Sprintf("Using import identifier: %s", importId)) - if testStepConfig == nil { - logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import") - } - // Create working directory for import tests if testStepConfig == nil { logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import") From 1f979e2835112f1f229658b163196e4c738033aa Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 5 Mar 2025 11:55:00 +0100 Subject: [PATCH 5/5] update comment --- helper/resource/testing_new_import_state.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helper/resource/testing_new_import_state.go b/helper/resource/testing_new_import_state.go index 09cb40af1..0c83e6432 100644 --- a/helper/resource/testing_new_import_state.go +++ b/helper/resource/testing_new_import_state.go @@ -93,7 +93,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest logging.HelperResourceTrace(ctx, fmt.Sprintf("Using import identifier: %s", importId)) - // Create working directory for import tests + // Prepare the test config dependent on the kind of import test being performed if testStepConfig == nil { logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import") @@ -122,7 +122,6 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest }.Exec() testStepConfig = teststep.Configuration(confRequest) - //testStepConfig = cfg if testStepConfig == nil { t.Fatal("Cannot import state with no specified config") }