Skip to content

Commit a36cde2

Browse files
committed
wip
1 parent f45d8fe commit a36cde2

File tree

5 files changed

+62
-76
lines changed

5 files changed

+62
-76
lines changed

helper/resource/importstate/import_block_as_first_step_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func Test_ImportBlock_AsFirstStep(t *testing.T) {
2323

2424
r.UnitTest(t, r.TestCase{
2525
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
26-
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithId requires Terraform 1.5.0 or later
26+
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithID requires Terraform 1.5.0 or later
2727
},
2828
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
2929
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
@@ -37,7 +37,7 @@ func Test_ImportBlock_AsFirstStep(t *testing.T) {
3737
ResourceName: "examplecloud_container.test",
3838
ImportStateId: "examplecloud_container.test",
3939
ImportState: true,
40-
ImportStateKind: r.ImportBlockWithId,
40+
ImportStateKind: r.ImportBlockWithID,
4141
// ImportStateVerify: true,
4242
Config: `resource "examplecloud_container" "test" {
4343
name = "somevalue"

helper/resource/importstate/import_block_with_id_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func Test_TestStep_ImportBlockId(t *testing.T) {
2626

2727
r.UnitTest(t, r.TestCase{
2828
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
29-
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithId requires Terraform 1.5.0 or later
29+
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithID requires Terraform 1.5.0 or later
3030
},
3131
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
3232
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
@@ -46,7 +46,7 @@ func Test_TestStep_ImportBlockId(t *testing.T) {
4646
{
4747
ResourceName: "examplecloud_container.test",
4848
ImportState: true,
49-
ImportStateKind: r.ImportBlockWithId,
49+
ImportStateKind: r.ImportBlockWithID,
5050
ImportStateVerify: true,
5151
},
5252
},
@@ -58,7 +58,7 @@ func TestTest_TestStep_ImportBlockId_ExpectError(t *testing.T) {
5858

5959
r.UnitTest(t, r.TestCase{
6060
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
61-
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithId requires Terraform 1.5.0 or later
61+
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithID requires Terraform 1.5.0 or later
6262
},
6363
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
6464
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
@@ -83,9 +83,9 @@ func TestTest_TestStep_ImportBlockId_ExpectError(t *testing.T) {
8383
}`,
8484
ResourceName: "examplecloud_container.test",
8585
ImportState: true,
86-
ImportStateKind: r.ImportBlockWithId,
86+
ImportStateKind: r.ImportBlockWithID,
8787
ImportStateVerify: true,
88-
ExpectError: regexp.MustCompile(`importing resource examplecloud_container.test should be a no-op, but got action update with plan(.?)`),
88+
ExpectError: regexp.MustCompile(`importing resource examplecloud_container.test: expected a no-op resource action, got "update" action with plan(.?)`),
8989
},
9090
},
9191
})
@@ -122,7 +122,7 @@ func TestTest_TestStep_ImportBlockId_FailWhenPlannableImportIsNotSupported(t *te
122122
}`,
123123
ResourceName: "examplecloud_container.test",
124124
ImportState: true,
125-
ImportStateKind: r.ImportBlockWithId,
125+
ImportStateKind: r.ImportBlockWithID,
126126
ImportStateVerify: true,
127127
ExpectError: regexp.MustCompile(`Terraform 1.5.0`),
128128
},
@@ -135,7 +135,7 @@ func TestTest_TestStep_ImportBlockId_SkipDataSourceState(t *testing.T) {
135135

136136
r.UnitTest(t, r.TestCase{
137137
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
138-
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithId requires Terraform 1.5.0 or later
138+
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithID requires Terraform 1.5.0 or later
139139

140140
},
141141
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
@@ -161,7 +161,7 @@ func TestTest_TestStep_ImportBlockId_SkipDataSourceState(t *testing.T) {
161161
{
162162
ResourceName: "examplecloud_thing.test",
163163
ImportState: true,
164-
ImportStateKind: r.ImportBlockWithId,
164+
ImportStateKind: r.ImportBlockWithID,
165165
ImportStateCheck: func(is []*terraform.InstanceState) error {
166166
if len(is) > 1 {
167167
return fmt.Errorf("expected 1 state, got: %d", len(is))
@@ -204,7 +204,7 @@ func TestTest_TestStep_ImportBlockId_ImportStateVerifyIgnore_Real_Example(t *tes
204204

205205
r.UnitTest(t, r.TestCase{
206206
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
207-
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithId requires Terraform 1.5.0 or later
207+
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithID requires Terraform 1.5.0 or later
208208
},
209209
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
210210
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
@@ -292,7 +292,7 @@ func TestTest_TestStep_ImportBlockId_ImportStateVerifyIgnore_Real_Example(t *tes
292292
}`,
293293
ResourceName: "examplecloud_container.test",
294294
ImportState: true,
295-
ImportStateKind: r.ImportBlockWithId,
295+
ImportStateKind: r.ImportBlockWithID,
296296
ImportStateVerify: true,
297297
ImportStateVerifyIgnore: []string{"password"},
298298
},
@@ -305,7 +305,7 @@ func TestTest_TestStep_ImportBlockId_ImportStateVerifyIgnore(t *testing.T) {
305305

306306
r.UnitTest(t, r.TestCase{
307307
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
308-
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithId requires Terraform 1.5.0 or later
308+
tfversion.SkipBelow(tfversion.Version1_5_0), // ImportBlockWithID requires Terraform 1.5.0 or later
309309
},
310310
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
311311
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
@@ -377,7 +377,7 @@ func TestTest_TestStep_ImportBlockId_ImportStateVerifyIgnore(t *testing.T) {
377377
{
378378
ResourceName: "examplecloud_container.test",
379379
ImportState: true,
380-
ImportStateKind: r.ImportBlockWithId,
380+
ImportStateKind: r.ImportBlockWithID,
381381
ImportStateVerify: true,
382382
ImportStateVerifyIgnore: []string{"password"},
383383
},

helper/resource/importstate/import_command_as_first_step_test.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,9 @@ func Test_ImportCommand_AsFirstStep(t *testing.T) {
3333
},
3434
Steps: []r.TestStep{
3535
{
36-
ResourceName: "examplecloud_container.test",
37-
ImportStateId: "examplecloud_container.test",
38-
ImportState: true,
39-
ImportStateKind: r.ImportCommandWithId,
40-
// ImportStateVerify: true,
36+
ResourceName: "examplecloud_container.test",
37+
ImportStateId: "examplecloud_container.test",
38+
ImportState: true,
4139
Config: `resource "examplecloud_container" "test" {
4240
name = "somevalue"
4341
location = "westeurope"

helper/resource/testing.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -457,14 +457,32 @@ type ExternalProvider struct {
457457
type ImportStateKind byte
458458

459459
const (
460-
// ImportCommandWithId imports the state using the import command
461-
ImportCommandWithId ImportStateKind = iota
462-
// ImportBlockWithId imports the state using an import block with an ID
463-
ImportBlockWithId
460+
// ImportCommandWithID imports the state using the import command
461+
ImportCommandWithID ImportStateKind = iota
462+
463+
// ImportBlockWithID imports the state using an import block with an ID
464+
ImportBlockWithID
465+
464466
// ImportBlockWithResourceIdentity imports the state using an import block with a resource identity
465467
ImportBlockWithResourceIdentity
466468
)
467469

470+
func (kind ImportStateKind) plannable() bool {
471+
return kind == ImportBlockWithID || kind == ImportBlockWithResourceIdentity
472+
}
473+
474+
func (kind ImportStateKind) resourceIdentity() bool {
475+
return kind == ImportBlockWithResourceIdentity
476+
}
477+
478+
func (kind ImportStateKind) String() string {
479+
return map[ImportStateKind]string{
480+
ImportCommandWithID: "ImportCommandWithID",
481+
ImportBlockWithID: "ImportBlockWithID",
482+
ImportBlockWithResourceIdentity: "ImportBlockWithResourceIdentity",
483+
}[kind]
484+
}
485+
468486
// TestStep is a single apply sequence of a test, done within the
469487
// context of a state.
470488
//
@@ -967,17 +985,17 @@ func UnitTest(t testing.T, c TestCase) {
967985
Test(t, c)
968986
}
969987

970-
func testResource(c TestStep, state *terraform.State) (*terraform.ResourceState, error) {
988+
func testResource(name string, state *terraform.State) (*terraform.ResourceState, error) {
971989
for _, m := range state.Modules {
972990
if len(m.Resources) > 0 {
973-
if v, ok := m.Resources[c.ResourceName]; ok {
991+
if v, ok := m.Resources[name]; ok {
974992
return v, nil
975993
}
976994
}
977995
}
978996

979997
return nil, fmt.Errorf(
980-
"Resource specified by ResourceName couldn't be found: %s", c.ResourceName)
998+
"Resource specified by ResourceName couldn't be found: %s", name)
981999
}
9821000

9831001
// ComposeTestCheckFunc lets you compose multiple TestCheckFuncs into

helper/resource/testing_new_import_state.go

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"reflect"
1010
"strings"
1111

12-
"github.com/hashicorp/go-version"
1312
tfjson "github.com/hashicorp/terraform-json"
1413

1514
"github.com/google/go-cmp/cmp"
@@ -21,40 +20,27 @@ import (
2120
"github.com/hashicorp/terraform-plugin-testing/internal/plugintest"
2221
"github.com/hashicorp/terraform-plugin-testing/internal/teststep"
2322
"github.com/hashicorp/terraform-plugin-testing/terraform"
24-
"github.com/hashicorp/terraform-plugin-testing/tfversion"
2523
)
2624

27-
func requirePlannableImport(t testing.T, versionUnderTest version.Version) error {
28-
t.Helper()
29-
30-
if versionUnderTest.LessThan(tfversion.Version1_5_0) {
31-
return fmt.Errorf(
32-
`ImportState steps using plannable import blocks require Terraform 1.5.0 or later. Either ` +
33-
`upgrade the Terraform version running the test or add a ` + "`TerraformVersionChecks`" + ` to ` +
34-
`the test case to skip this test.` + "\n\n" +
35-
`https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/tfversion-checks#skip-version-checks`)
36-
}
37-
38-
return nil
39-
}
40-
4125
func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest.Helper, wd *plugintest.WorkingDir, step TestStep, cfgRaw string, providers *providerFactories, stepNumber int) error {
4226
t.Helper()
4327

44-
// Currently import modes `ImportBlockWithId` and `ImportBlockWithResourceIdentity` cannot support config file or directory
45-
// since these modes append the import block to the configuration automatically
46-
if step.ImportStateKind != ImportCommandWithId {
47-
if step.ConfigFile != nil || step.ConfigDirectory != nil {
48-
t.Fatalf("ImportStateKind %q is not supported for config file or directory", step.ImportStateKind)
49-
}
50-
}
51-
52-
if step.ImportStateKind != ImportCommandWithId {
28+
// step.ImportStateKind implicitly defaults to the zero-value (ImportCommandWithID) for backward compatibility
29+
kind := step.ImportStateKind
30+
if kind.plannable() {
31+
// Instead of calling [t.Fatal], return an error. This package's unit tests can use [TestStep.ExpectError] to match on the error message.
32+
// An alternative, [plugintest.TestExpectTFatal], does not have access to logged error messages, so it is open to false positives on this
33+
// complex code path.
5334
if err := requirePlannableImport(t, *helper.TerraformVersion()); err != nil {
5435
return err
5536
}
5637
}
5738

39+
resourceName := step.ResourceName
40+
if resourceName == "" {
41+
t.Fatal("ResourceName is required for an import state test")
42+
}
43+
5844
configRequest := teststep.PrepareConfigurationRequest{
5945
Directory: step.ConfigDirectory,
6046
File: step.ConfigFile,
@@ -67,10 +53,6 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
6753

6854
testStepConfig := teststep.Configuration(configRequest)
6955

70-
if step.ResourceName == "" {
71-
t.Fatal("ResourceName is required for an import state test")
72-
}
73-
7456
// get state from check sequence
7557
var state *terraform.State
7658
var err error
@@ -110,7 +92,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
11092
default:
11193
logging.HelperResourceTrace(ctx, "Using resource identifier for import identifier")
11294

113-
resource, err := testResource(step, state)
95+
resource, err := testResource(resourceName, state)
11496
if err != nil {
11597
t.Fatal(err)
11698
}
@@ -125,26 +107,16 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
125107

126108
logging.HelperResourceTrace(ctx, fmt.Sprintf("Using import identifier: %s", importId))
127109

110+
// Append to previous step config unless using ConfigFile or ConfigDirectory
128111
if testStepConfig == nil || step.Config != "" {
129112
importConfig := step.Config
130113
if importConfig == "" {
131114
logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import")
132115
importConfig = cfgRaw
133116
}
134117

135-
// Update the test config dependent on the kind of import test being performed
136-
switch step.ImportStateKind {
137-
case ImportBlockWithResourceIdentity:
138-
t.Fatalf("TODO implement me")
139-
case ImportBlockWithId:
140-
importConfig += fmt.Sprintf(`
141-
import {
142-
to = %s
143-
id = %q
144-
}
145-
`, step.ResourceName, importId)
146-
default:
147-
// Not an import block test so nothing to do here
118+
if kind.plannable() {
119+
importConfig = appendImportBlock(importConfig, resourceName, importId)
148120
}
149121

150122
confRequest := teststep.PrepareConfigurationRequest{
@@ -170,7 +142,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
170142
importWd = wd
171143
} else {
172144
importWd = helper.RequireNewWorkingDir(ctx, t, "")
173-
defer importWd.Close()
145+
defer importWd.Close() //nolint:errcheck
174146
}
175147

176148
err = importWd.SetConfig(ctx, testStepConfig, step.ConfigVariables)
@@ -189,7 +161,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
189161
}
190162

191163
var plan *tfjson.Plan
192-
if step.ImportStateKind == ImportBlockWithResourceIdentity || step.ImportStateKind == ImportBlockWithId {
164+
if kind.plannable() {
193165
var opts []tfexec.PlanOption
194166

195167
err = runProviderCommand(ctx, t, func() error {
@@ -214,7 +186,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
214186
logging.HelperResourceDebug(ctx, fmt.Sprintf("ImportBlockWithId: %d resource changes", len(plan.ResourceChanges)))
215187

216188
for _, rc := range plan.ResourceChanges {
217-
if rc.Address != step.ResourceName {
189+
if rc.Address != resourceName {
218190
// we're only interested in the changes for the resource being imported
219191
continue
220192
}
@@ -232,7 +204,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
232204
return fmt.Errorf("retrieving formatted plan output: %w", err)
233205
}
234206

235-
return fmt.Errorf("importing resource %s should be a no-op, but got action %s with plan \\nstdout:\\n\\n%s", rc.Address, action, stdout)
207+
return fmt.Errorf("importing resource %s: expected a no-op resource action, got %q action with plan \nstdout:\n\n%s", rc.Address, action, stdout)
236208
}
237209
}
238210
}
@@ -244,11 +216,9 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
244216
if err := runPlanChecks(ctx, t, plan, step.ImportPlanChecks.PreApply); err != nil {
245217
return err
246218
}
247-
248219
} else {
249220
err = runProviderCommand(ctx, t, func() error {
250-
logging.HelperResourceDebug(ctx, "Run terraform import")
251-
return importWd.Import(ctx, step.ResourceName, importId)
221+
return importWd.Import(ctx, resourceName, importId)
252222
}, importWd, providers)
253223
if err != nil {
254224
return err

0 commit comments

Comments
 (0)