@@ -14,7 +14,6 @@ import (
1414 "github.com/google/go-cmp/cmp"
1515 "github.com/mitchellh/go-testing-interface"
1616
17- "github.com/hashicorp/terraform-exec/tfexec"
1817 "github.com/hashicorp/terraform-plugin-testing/config"
1918 "github.com/hashicorp/terraform-plugin-testing/internal/logging"
2019 "github.com/hashicorp/terraform-plugin-testing/internal/plugintest"
@@ -67,9 +66,6 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
6766 t .Fatalf ("Error getting state: %s" , err )
6867 }
6968
70- // TODO: this statement is a placeholder -- it simply prevents stateJSON from being unused
71- logging .HelperResourceTrace (ctx , fmt .Sprintf ("State before import: values %v" , stateJSON .Values != nil ))
72-
7369 // Determine the ID to import
7470 var importId string
7571 switch {
@@ -109,6 +105,8 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
109105
110106 logging .HelperResourceTrace (ctx , fmt .Sprintf ("Using import identifier: %s" , importId ))
111107
108+ var priorIdentityValues map [string ]any
109+
112110 // Append to previous step config unless using ConfigFile or ConfigDirectory
113111 if testStepConfig == nil || step .Config != "" {
114112 importConfig := step .Config
@@ -117,7 +115,10 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
117115 importConfig = cfgRaw
118116 }
119117
120- if kind .plannable () {
118+ if kind .plannable () && kind .resourceIdentity () {
119+ priorIdentityValues = identityValuesFromState (stateJSON , resourceName )
120+ importConfig = appendImportBlockWithIdentity (importConfig , resourceName , priorIdentityValues )
121+ } else if kind .plannable () {
121122 importConfig = appendImportBlock (importConfig , resourceName , importId )
122123 }
123124
@@ -179,23 +180,8 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
179180
180181 var plan * tfjson.Plan
181182 if kind .plannable () {
182- var opts []tfexec.PlanOption
183-
184- err = runProviderCommand (ctx , t , func () error {
185- return importWd .CreatePlan (ctx , opts ... )
186- }, importWd , providers )
187- if err != nil {
188- return err
189- }
190-
191- err = runProviderCommand (ctx , t , func () error {
192- var err error
193- plan , err = importWd .SavedPlan (ctx )
194- return err
195- }, importWd , providers )
196- if err != nil {
197- return err
198- }
183+ runProviderCommandCreatePlan (ctx , t , importWd , providers )
184+ plan = runProviderCommandSavedPlan (ctx , t , importWd , providers )
199185
200186 logging .HelperResourceDebug (ctx , fmt .Sprintf ("ImportBlockWithId: %d resource changes" , len (plan .ResourceChanges )))
201187
@@ -224,23 +210,40 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
224210 case importing == nil :
225211 return fmt .Errorf ("importing resource %s: expected an import operation, got %q action with plan \n stdout:\n \n %s" , resourceChangeUnderTest .Address , actions , savedPlanRawStdout (ctx , t , importWd , providers ))
226212
227- case ! actions .NoOp (): // TODO: is this reachable? possible to have anything other than no-op when importing != nil ?
213+ case ! actions .NoOp ():
228214 return fmt .Errorf ("importing resource %s: expected a no-op import operation, got %q action with plan \n stdout:\n \n %s" , resourceChangeUnderTest .Address , actions , savedPlanRawStdout (ctx , t , importWd , providers ))
229215 }
230216
231217 if err := runPlanChecks (ctx , t , plan , step .ImportPlanChecks .PreApply ); err != nil {
232218 return err
233219 }
234- } else {
235- err = runProviderCommand (ctx , t , func () error {
236- return importWd .Import (ctx , resourceName , importId )
237- }, importWd , providers )
238- if err != nil {
239- return err
220+
221+ {
222+ if kind .resourceIdentity () {
223+ runProviderCommandApply (ctx , t , wd , providers )
224+ newStateJSON := runProviderCommandGetStateJSON (ctx , t , wd , providers )
225+
226+ newIdentityValues := identityValuesFromState (newStateJSON , resourceName )
227+ if ! cmp .Equal (priorIdentityValues , newIdentityValues ) {
228+ return fmt .Errorf ("importing resource %s: expected identity values %v, got %v" , resourceName , priorIdentityValues , newIdentityValues )
229+ }
230+ }
240231 }
232+
233+ return nil
241234 }
242235
236+ // !kind.plannable()
237+
243238 var importState * terraform.State
239+
240+ err = runProviderCommand (ctx , t , func () error {
241+ return importWd .Import (ctx , resourceName , importId )
242+ }, importWd , providers )
243+ if err != nil {
244+ return err
245+ }
246+
244247 err = runProviderCommand (ctx , t , func () error {
245248 _ , importState , err = getState (ctx , t , importWd )
246249 if err != nil {
@@ -410,6 +413,26 @@ func appendImportBlock(config string, resourceName string, importID string) stri
410413 resourceName , importID )
411414}
412415
416+ func appendImportBlockWithIdentity (config string , resourceName string , identityValues map [string ]any ) string {
417+ configBuilder := config
418+ configBuilder += fmt .Sprintf (`` + "\n " +
419+ `import {` + "\n " +
420+ ` to = %s` + "\n " +
421+ ` identity = {` + "\n " ,
422+ resourceName )
423+
424+ // ` id = %q`+"\n"+
425+ for k , v := range identityValues {
426+ configBuilder += fmt .Sprintf (` %q = %q` + "\n " , k , v )
427+ }
428+
429+ configBuilder +=
430+ ` }` + "\n " +
431+ `}` + "\n "
432+
433+ return configBuilder
434+ }
435+
413436func importStatePreconditions (t testing.T , helper * plugintest.Helper , step TestStep ) error {
414437 t .Helper ()
415438
@@ -437,6 +460,33 @@ func importStatePreconditions(t testing.T, helper *plugintest.Helper, step TestS
437460 return nil
438461}
439462
463+ func resourcesFromState (state * tfjson.State ) []* tfjson.StateResource {
464+ stateValues := state .Values
465+ if stateValues == nil || stateValues .RootModule == nil {
466+ return []* tfjson.StateResource {}
467+ }
468+
469+ return stateValues .RootModule .Resources
470+ }
471+
472+ func identityValuesFromState (state * tfjson.State , resourceName string ) map [string ]any {
473+ var resourceUnderTest * tfjson.StateResource
474+ resources := resourcesFromState (state )
475+
476+ for _ , resource := range resources {
477+ if resource .Address == resourceName {
478+ resourceUnderTest = resource
479+ break
480+ }
481+ }
482+
483+ if resourceUnderTest == nil || len (resourceUnderTest .IdentityValues ) == 0 {
484+ return map [string ]any {}
485+ }
486+
487+ return resourceUnderTest .IdentityValues
488+ }
489+
440490func runImportStateCheckFunction (ctx context.Context , t testing.T , importState * terraform.State , step TestStep ) {
441491 t .Helper ()
442492
0 commit comments