Skip to content

Commit 0060a87

Browse files
authored
ResourceIdentity: Switch to using plan instead of applied state for asserting identity data (#502)
* add test * update to use planned values * remove unused functions
1 parent 8b8c33a commit 0060a87

File tree

4 files changed

+64
-51
lines changed

4 files changed

+64
-51
lines changed

helper/resource/importstate/examplecloud_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,3 +596,27 @@ func examplecloudResourceWithNullIdentityAttr() testprovider.Resource {
596596
},
597597
}
598598
}
599+
600+
// This example resource, on update plans, will plan a different identity to test that
601+
// our testing framework assertions catch an identity that differs after import/refresh.
602+
func examplecloudResourceWithChangingIdentity() testprovider.Resource {
603+
exampleCloudResource := examplecloudResource()
604+
605+
exampleCloudResource.PlanChangeFunc = func(ctx context.Context, req resource.PlanChangeRequest, resp *resource.PlanChangeResponse) {
606+
// Only on update
607+
if !req.PriorState.IsNull() && !req.ProposedNewState.IsNull() {
608+
resp.PlannedIdentity = teststep.Pointer(tftypes.NewValue(
609+
tftypes.Object{
610+
AttributeTypes: map[string]tftypes.Type{
611+
"id": tftypes.String,
612+
},
613+
},
614+
map[string]tftypes.Value{
615+
"id": tftypes.NewValue(tftypes.String, "easteurope/someothervalue"),
616+
},
617+
))
618+
}
619+
}
620+
621+
return exampleCloudResource
622+
}

helper/resource/importstate/import_block_with_resource_identity_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,39 @@ func TestImportBlock_WithResourceIdentity_WithEveryType(t *testing.T) {
119119
})
120120
}
121121

122+
func TestImportBlock_WithResourceIdentity_ChangingIdentityError(t *testing.T) {
123+
t.Parallel()
124+
125+
r.UnitTest(t, r.TestCase{
126+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
127+
tfversion.SkipBelow(tfversion.Version1_12_0), // ImportBlockWithResourceIdentity requires Terraform 1.12.0 or later
128+
},
129+
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
130+
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
131+
Resources: map[string]testprovider.Resource{
132+
"examplecloud_container": examplecloudResourceWithChangingIdentity(),
133+
},
134+
}),
135+
},
136+
Steps: []r.TestStep{
137+
{
138+
Config: `
139+
resource "examplecloud_container" "test" {
140+
location = "westeurope"
141+
name = "somevalue"
142+
}`,
143+
},
144+
{
145+
ResourceName: "examplecloud_container.test",
146+
ImportState: true,
147+
ImportStateKind: r.ImportBlockWithResourceIdentity,
148+
// The plan following the import will produce a different identity value then test step 1
149+
ExpectError: regexp.MustCompile(`expected identity values map\[id:westeurope/somevalue\], got map\[id:easteurope/someothervalue\]`),
150+
},
151+
},
152+
})
153+
}
154+
122155
func TestImportBlock_WithResourceIdentity_RequiresVersion1_12_0(t *testing.T) {
123156
t.Parallel()
124157

helper/resource/plugin.go

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,6 @@ type providerFactories struct {
114114
protov6 protov6ProviderFactories
115115
}
116116

117-
func runProviderCommandApply(ctx context.Context, t testing.T, wd *plugintest.WorkingDir, factories *providerFactories) error {
118-
t.Helper()
119-
120-
fn := func() error {
121-
return wd.Apply(ctx)
122-
}
123-
return runProviderCommand(ctx, t, wd, factories, fn)
124-
}
125-
126117
func runProviderCommandCreatePlan(ctx context.Context, t testing.T, wd *plugintest.WorkingDir, factories *providerFactories) error {
127118
t.Helper()
128119

@@ -132,23 +123,6 @@ func runProviderCommandCreatePlan(ctx context.Context, t testing.T, wd *pluginte
132123
return runProviderCommand(ctx, t, wd, factories, fn)
133124
}
134125

135-
func runProviderCommandGetStateJSON(ctx context.Context, t testing.T, wd *plugintest.WorkingDir, factories *providerFactories) (*tfjson.State, error) {
136-
t.Helper()
137-
138-
var stateJSON *tfjson.State
139-
fn := func() error {
140-
var err error
141-
stateJSON, err = wd.State(ctx)
142-
return err
143-
}
144-
err := runProviderCommand(ctx, t, wd, factories, fn)
145-
if err != nil {
146-
return nil, err
147-
}
148-
149-
return stateJSON, nil
150-
}
151-
152126
func runProviderCommandSavedPlan(ctx context.Context, t testing.T, wd *plugintest.WorkingDir, factories *providerFactories) (*tfjson.Plan, error) {
153127
t.Helper()
154128

helper/resource/testing_new_import_state.go

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest
9999
var priorIdentityValues map[string]any
100100

101101
if kind.plannable() && kind.resourceIdentity() {
102-
priorIdentityValues = identityValuesFromState(stateJSON, resourceName)
102+
priorIdentityValues = identityValuesFromStateValues(stateJSON.Values, resourceName)
103103
if len(priorIdentityValues) == 0 {
104104
return fmt.Errorf("importing resource %s: expected prior state to have resource identity values, got none", resourceName)
105105
}
@@ -231,32 +231,15 @@ func testImportBlock(ctx context.Context, t testing.T, workingDir *plugintest.Wo
231231
}
232232

233233
if kind.resourceIdentity() {
234-
if err := verifyIdentityValues(ctx, t, workingDir, providers, resourceName, priorIdentityValues); err != nil {
235-
return err
234+
newIdentityValues := identityValuesFromStateValues(plan.PlannedValues, resourceName)
235+
if !cmp.Equal(priorIdentityValues, newIdentityValues) {
236+
return fmt.Errorf("importing resource %s: expected identity values %v, got %v", resourceName, priorIdentityValues, newIdentityValues)
236237
}
237238
}
238239

239240
return nil
240241
}
241242

242-
func verifyIdentityValues(ctx context.Context, t testing.T, workingDir *plugintest.WorkingDir, providers *providerFactories, resourceName string, priorIdentityValues map[string]any) error {
243-
err := runProviderCommandApply(ctx, t, workingDir, providers)
244-
if err != nil {
245-
return fmt.Errorf("applying plan with import config: %s", err)
246-
}
247-
248-
newStateJSON, err := runProviderCommandGetStateJSON(ctx, t, workingDir, providers)
249-
if err != nil {
250-
return fmt.Errorf("getting state after applying plan with import config: %s", err)
251-
}
252-
253-
newIdentityValues := identityValuesFromState(newStateJSON, resourceName)
254-
if !cmp.Equal(priorIdentityValues, newIdentityValues) {
255-
return fmt.Errorf("importing resource %s: expected identity values %v, got %v", resourceName, priorIdentityValues, newIdentityValues)
256-
}
257-
return nil
258-
}
259-
260243
func testImportCommand(ctx context.Context, t testing.T, workingDir *plugintest.WorkingDir, providers *providerFactories, resourceName string, importId string, step TestStep, state *terraform.State) error {
261244
err := runProviderCommand(ctx, t, workingDir, providers, func() error {
262245
return workingDir.Import(ctx, resourceName, importId)
@@ -515,18 +498,17 @@ func importStatePreconditions(t testing.T, helper *plugintest.Helper, step TestS
515498
return nil
516499
}
517500

518-
func resourcesFromState(state *tfjson.State) []*tfjson.StateResource {
519-
stateValues := state.Values
501+
func resourcesFromState(stateValues *tfjson.StateValues) []*tfjson.StateResource {
520502
if stateValues == nil || stateValues.RootModule == nil {
521503
return []*tfjson.StateResource{}
522504
}
523505

524506
return stateValues.RootModule.Resources
525507
}
526508

527-
func identityValuesFromState(state *tfjson.State, resourceName string) map[string]any {
509+
func identityValuesFromStateValues(stateValues *tfjson.StateValues, resourceName string) map[string]any {
528510
var resource *tfjson.StateResource
529-
resources := resourcesFromState(state)
511+
resources := resourcesFromState(stateValues)
530512

531513
for _, r := range resources {
532514
if r.Address == resourceName {

0 commit comments

Comments
 (0)