Skip to content

Conversation

@bbasata
Copy link
Collaborator

@bbasata bbasata commented Apr 8, 2025

To merge after #476. This pull request adds resource identity support to ImportState test steps. For example:

Steps: []r.TestStep{
{
Config: `
resource "examplecloud_container" "test" {
location = "westeurope"
name = "somevalue"
}`,
},
{
RefreshState: true,
},
{
ResourceName: "examplecloud_container.test",
ImportState: true,
ImportStateKind: r.ImportBlockWithResourceIdentity,
},
},

In this example, the test author writes in-line config in Step 1. In Step 3 with ImportBlockWithResourceIdentity, the test appends an import block. The test constructs this import block using resource identity values from the Step 1 state:

if kind.plannable() && kind.resourceIdentity() {
priorIdentityValues = identityValuesFromState(stateJSON, resourceName)
if len(priorIdentityValues) == 0 {
return fmt.Errorf("importing resource %s: expected prior state to have resource identity values, got none", resourceName)
}
importConfig = appendImportBlockWithIdentity(importConfig, resourceName, priorIdentityValues)
} else if kind.plannable() {
importConfig = appendImportBlock(importConfig, resourceName, importId)
}

The test generates a plan and asserts that the plan is a no-op import of a single resource:

switch {
case importing == nil:
return fmt.Errorf("importing resource %s: expected an import operation, got %q action with plan \nstdout:\n\n%s", resourceChangeUnderTest.Address, actions, savedPlanRawStdout(ctx, t, importWd, providers))
case !actions.NoOp():
return fmt.Errorf("importing resource %s: expected a no-op import operation, got %q action with plan \nstdout:\n\n%s", resourceChangeUnderTest.Address, actions, savedPlanRawStdout(ctx, t, importWd, providers))
}

Finally, the test compares the Step 3 identity values with the identity values in Step 1 state. 💭 I want to take another look to consider whether this is necessary or duplicative of the "no-op import" assertion. 💭

At the time of writing this PR, I observed that a generated plan does not include resource identity values. And I reasoned that it's safe to run apply by this point -- the test applies a no-op import plan to a "sandboxed" statefile. Cross-ref #476 "Error on use of ImportStatePersist with plannable import"

{
if kind.resourceIdentity() {
err := runProviderCommandApply(ctx, t, wd, providers)
if err != nil {
return fmt.Errorf("applying plan with import config: %s", err)
}
newStateJSON, err := runProviderCommandGetStateJSON(ctx, t, wd, providers)
if err != nil {
return fmt.Errorf("getting state after applying plan with import config: %s", err)
}
newIdentityValues := identityValuesFromState(newStateJSON, resourceName)
if !cmp.Equal(priorIdentityValues, newIdentityValues) {
return fmt.Errorf("importing resource %s: expected identity values %v, got %v", resourceName, priorIdentityValues, newIdentityValues)
}
}
}

@bbasata bbasata changed the title helper/resource: add ImportBlockWithResourceIdentity kind helper/resource: add ImportBlockWithResourceIdentity kind Apr 8, 2025
@bbasata bbasata force-pushed the import-block-with-resource-identity branch from b986ce0 to 5072047 Compare April 8, 2025 20:58
@bbasata bbasata force-pushed the import-block-with-resource-identity branch from 5072047 to c2a5b46 Compare April 11, 2025 15:27
@bbasata bbasata marked this pull request as ready for review April 11, 2025 16:23
@bbasata bbasata requested a review from a team as a code owner April 11, 2025 16:23
Base automatically changed from zone-record to main April 15, 2025 15:59
@austinvalle austinvalle added this to the v1.13.0 milestone Apr 15, 2025
Copy link
Member

@austinvalle austinvalle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is looking great! I do have some specific questions and suggestions around the version check

Comment on lines 236 to 251
if kind.resourceIdentity() {
err := runProviderCommandApply(ctx, t, wd, providers)
if err != nil {
return fmt.Errorf("applying plan with import config: %s", err)
}

newStateJSON, err := runProviderCommandGetStateJSON(ctx, t, wd, providers)
if err != nil {
return fmt.Errorf("getting state after applying plan with import config: %s", err)
}

newIdentityValues := identityValuesFromState(newStateJSON, resourceName)
if !cmp.Equal(priorIdentityValues, newIdentityValues) {
return fmt.Errorf("importing resource %s: expected identity values %v, got %v", resourceName, priorIdentityValues, newIdentityValues)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I'm more leaning towards not applying and just waiting for TF core to give us the data during plan for comparison (it sounds like it should be included)

At least how it is ATM, core is validating that the data doesn't change during apply, and if they remove that logic, the SDKs should probably add it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly because we can't fully trust providers to apply what they plan (since the testing framework also supports SDKv2 😆 ), so if we can avoid it, I think we should

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me. Since we have a working implementation in this PR, it should be no trouble to switch to planned values & expect tests to remain green.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about this offline and we're good with keeping apply with the caveat that we'll remove it before full release

case []any:
var quotedV []string
for _, v := range v.([]any) {
quotedV = append(quotedV, fmt.Sprintf(`%q`, v))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 also need to handle lists of numbers and lists of booleans

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or not? I added list of numbers and lists of booleans to the test resource schema and ... still green 🟢.

ansgarm added a commit to hashicorp/terraform-provider-corner that referenced this pull request Apr 17, 2025
austinvalle
austinvalle previously approved these changes Apr 17, 2025
Copy link
Member

@austinvalle austinvalle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, great work on this @bbasata!

Copy link
Member

@austinvalle austinvalle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@bbasata bbasata merged commit e488dee into main Apr 18, 2025
40 checks passed
@bbasata bbasata deleted the import-block-with-resource-identity branch April 18, 2025 13:01
austinvalle pushed a commit to hashicorp/terraform-provider-corner that referenced this pull request Apr 18, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 18, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants