@@ -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,13 @@ 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+ if len (priorIdentityValues ) == 0 {
121+ return fmt .Errorf ("importing resource %s: expected prior state to have resource identity values, got none" , resourceName )
122+ }
123+ importConfig = appendImportBlockWithIdentity (importConfig , resourceName , priorIdentityValues )
124+ } else if kind .plannable () {
121125 importConfig = appendImportBlock (importConfig , resourceName , importId )
122126 }
123127
@@ -179,22 +183,16 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
179183
180184 var plan * tfjson.Plan
181185 if kind .plannable () {
182- var opts []tfexec. PlanOption
186+ // TODO: extract to a function -- this is a long `if` :)
183187
184- err = runProviderCommand (ctx , t , func () error {
185- return importWd .CreatePlan (ctx , opts ... )
186- }, importWd , providers )
188+ err := runProviderCommandCreatePlan (ctx , t , importWd , providers )
187189 if err != nil {
188- return err
190+ return fmt . Errorf ( "generating plan with import config: %s" , err )
189191 }
190192
191- err = runProviderCommand (ctx , t , func () error {
192- var err error
193- plan , err = importWd .SavedPlan (ctx )
194- return err
195- }, importWd , providers )
193+ plan , err = runProviderCommandSavedPlan (ctx , t , importWd , providers )
196194 if err != nil {
197- return err
195+ return fmt . Errorf ( "reading generated plan with import config: %s" , err )
198196 }
199197
200198 logging .HelperResourceDebug (ctx , fmt .Sprintf ("ImportBlockWithId: %d resource changes" , len (plan .ResourceChanges )))
@@ -231,16 +229,40 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
231229 if err := runPlanChecks (ctx , t , plan , step .ImportPlanChecks .PreApply ); err != nil {
232230 return err
233231 }
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
232+
233+ {
234+ if kind .resourceIdentity () {
235+ err := runProviderCommandApply (ctx , t , wd , providers )
236+ if err != nil {
237+ return fmt .Errorf ("applying plan with import config: %s" , err )
238+ }
239+
240+ newStateJSON , err := runProviderCommandGetStateJSON (ctx , t , wd , providers )
241+ if err != nil {
242+ return fmt .Errorf ("getting state after applying plan with import config: %s" , err )
243+ }
244+
245+ newIdentityValues := identityValuesFromState (newStateJSON , resourceName )
246+ if ! cmp .Equal (priorIdentityValues , newIdentityValues ) {
247+ return fmt .Errorf ("importing resource %s: expected identity values %v, got %v" , resourceName , priorIdentityValues , newIdentityValues )
248+ }
249+ }
240250 }
251+
252+ return nil
241253 }
242254
255+ // TODO: extract to a function -- this is an implicit `else` for the long `if` above :)
256+
243257 var importState * terraform.State
258+
259+ err = runProviderCommand (ctx , t , func () error {
260+ return importWd .Import (ctx , resourceName , importId )
261+ }, importWd , providers )
262+ if err != nil {
263+ return err
264+ }
265+
244266 err = runProviderCommand (ctx , t , func () error {
245267 _ , importState , err = getState (ctx , t , importWd )
246268 if err != nil {
@@ -410,6 +432,25 @@ func appendImportBlock(config string, resourceName string, importID string) stri
410432 resourceName , importID )
411433}
412434
435+ func appendImportBlockWithIdentity (config string , resourceName string , identityValues map [string ]any ) string {
436+ configBuilder := config
437+ configBuilder += fmt .Sprintf (`` + "\n " +
438+ `import {` + "\n " +
439+ ` to = %s` + "\n " +
440+ ` identity = {` + "\n " ,
441+ resourceName )
442+
443+ for k , v := range identityValues {
444+ configBuilder += fmt .Sprintf (` %q = %q` + "\n " , k , v )
445+ }
446+
447+ configBuilder += `` +
448+ ` }` + "\n " +
449+ `}` + "\n "
450+
451+ return configBuilder
452+ }
453+
413454func importStatePreconditions (t testing.T , helper * plugintest.Helper , step TestStep ) error {
414455 t .Helper ()
415456
@@ -437,6 +478,33 @@ func importStatePreconditions(t testing.T, helper *plugintest.Helper, step TestS
437478 return nil
438479}
439480
481+ func resourcesFromState (state * tfjson.State ) []* tfjson.StateResource {
482+ stateValues := state .Values
483+ if stateValues == nil || stateValues .RootModule == nil {
484+ return []* tfjson.StateResource {}
485+ }
486+
487+ return stateValues .RootModule .Resources
488+ }
489+
490+ func identityValuesFromState (state * tfjson.State , resourceName string ) map [string ]any {
491+ var resource * tfjson.StateResource
492+ resources := resourcesFromState (state )
493+
494+ for _ , r := range resources {
495+ if r .Address == resourceName {
496+ resource = r
497+ break
498+ }
499+ }
500+
501+ if resource == nil || len (resource .IdentityValues ) == 0 {
502+ return map [string ]any {}
503+ }
504+
505+ return resource .IdentityValues
506+ }
507+
440508func runImportStateCheckFunction (ctx context.Context , t testing.T , importState * terraform.State , step TestStep ) {
441509 t .Helper ()
442510
0 commit comments