Skip to content

Commit

Permalink
Add Deferred Action Testing (#253)
Browse files Browse the repository at this point in the history
* Add deferred action tests for Framework providers

* Add deferred action tests for SDKv2 provider

* Update `terraform-plugin-framework` to `v1.9.0`

* Update SDKv2 test to use attribute to indicate deferral

* Add plan modification tests for automatic provider deferrals

* Add deferred action tests for the `terraform-plugin-go` provider

* Resolve linting errors

* Add clarifying comments to test cases
  • Loading branch information
SBGoods authored Jun 6, 2024
1 parent c359134 commit c961b06
Show file tree
Hide file tree
Showing 18 changed files with 1,398 additions and 23 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ toolchain go1.21.6
require (
github.com/hashicorp/go-memdb v1.3.4
github.com/hashicorp/terraform-json v0.22.1
github.com/hashicorp/terraform-plugin-framework v1.8.0
github.com/hashicorp/terraform-plugin-framework v1.9.0
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1
github.com/hashicorp/terraform-plugin-framework-timetypes v0.4.0
github.com/hashicorp/terraform-plugin-go v0.23.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVW
github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec=
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
github.com/hashicorp/terraform-plugin-framework v1.8.0 h1:P07qy8RKLcoBkCrY2RHJer5AEvJnDuXomBgou6fD8kI=
github.com/hashicorp/terraform-plugin-framework v1.8.0/go.mod h1:/CpTukO88PcL/62noU7cuyaSJ4Rsim+A/pa+3rUVufY=
github.com/hashicorp/terraform-plugin-framework v1.9.0 h1:caLcDoxiRucNi2hk8+j3kJwkKfvHznubyFsJMWfZqKU=
github.com/hashicorp/terraform-plugin-framework v1.9.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1 h1:gm5b1kHgFFhaKFhm4h2TgvMUlNzFAtUqlcOWnWPm+9E=
github.com/hashicorp/terraform-plugin-framework-timeouts v0.4.1/go.mod h1:MsjL1sQ9L7wGwzJ5RjcI6FzEMdyoBnw+XK8ZnOvQOLY=
github.com/hashicorp/terraform-plugin-framework-timetypes v0.4.0 h1:XLI93Oqw2/KTzYjgCXrUnm8LBkGAiHC/mDQg5g5Vob4=
Expand Down
142 changes: 142 additions & 0 deletions internal/framework5provider/deferred_action_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package framework

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var _ resource.Resource = (*DeferredActionResource)(nil)
var _ resource.ResourceWithModifyPlan = (*DeferredActionResource)(nil)
var _ resource.ResourceWithImportState = (*DeferredActionResource)(nil)

func NewDeferredActionResource() resource.Resource {
return &DeferredActionResource{
typeName: "_deferred_action",
planModification: false,
}
}

func NewDeferredActionPlanModificationResource() resource.Resource {
return &DeferredActionResource{
typeName: "_deferred_action_plan_modification",
planModification: true,
}
}

// DeferredActionResource is for testing all schema types.
type DeferredActionResource struct {
typeName string
planModification bool
}

func (r *DeferredActionResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + r.typeName
resp.ResourceBehavior.ProviderDeferred.EnablePlanModification = r.planModification
}

func (r *DeferredActionResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
if req.Plan.Raw.IsNull() {
return
}

var plan DeferredActionResourceModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

if !plan.ID.IsNull() && !plan.ID.IsUnknown() && plan.ID.ValueString() != "test_id" {
resp.Diagnostics.AddError("invalid id value", "id should be test_id")
return
}

if plan.ModifyPlanDeferral.ValueBool() && req.ClientCapabilities.DeferralAllowed {
resp.Deferred = &resource.Deferred{
Reason: resource.DeferredReasonResourceConfigUnknown,
}
}
}

func (r *DeferredActionResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"modify_plan_deferral": schema.BoolAttribute{
Optional: true,
},
"read_deferral": schema.BoolAttribute{
Optional: true,
},
"id": schema.StringAttribute{
Optional: true,
},
},
}
}

func (r *DeferredActionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data DeferredActionResourceModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *DeferredActionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data DeferredActionResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

if data.ReadDeferral.ValueBool() && req.ClientCapabilities.DeferralAllowed {
resp.Deferred = &resource.Deferred{
Reason: resource.DeferredReasonResourceConfigUnknown,
}
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *DeferredActionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data DeferredActionResourceModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *DeferredActionResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
}

type DeferredActionResourceModel struct {
ModifyPlanDeferral types.Bool `tfsdk:"modify_plan_deferral"`
ReadDeferral types.Bool `tfsdk:"read_deferral"`
ID types.String `tfsdk:"id"`
}

func (r *DeferredActionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
if req.ClientCapabilities.DeferralAllowed && req.ID == "deferral-id" {
resp.Deferred = &resource.Deferred{
Reason: resource.DeferredReasonResourceConfigUnknown,
}
}
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
Loading

0 comments on commit c961b06

Please sign in to comment.