Skip to content

Commit

Permalink
Merge branch 'main' into av/set-bug-acceptance-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
austinvalle authored Sep 18, 2024
2 parents 336ad20 + 8773819 commit 0ec4292
Show file tree
Hide file tree
Showing 6 changed files with 380 additions and 0 deletions.
121 changes: 121 additions & 0 deletions internal/framework5provider/move_state_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package framework

import (
"context"
"fmt"
"strings"

"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 = MoveStateResource{}
var _ resource.ResourceWithMoveState = MoveStateResource{}

func NewMoveStateResource() resource.Resource {
return &MoveStateResource{}
}

// MoveStateResource is for testing the MoveResourceState RPC
// https://developer.hashicorp.com/terraform/plugin/framework/resources/state-move
type MoveStateResource struct{}

func (r MoveStateResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_move_state"
}

func (r MoveStateResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"moved_random_string": schema.StringAttribute{
Computed: true,
},
},
}
}

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

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

if resp.Diagnostics.HasError() {
return
}

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

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

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

if resp.Diagnostics.HasError() {
return
}

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

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

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

if resp.Diagnostics.HasError() {
return
}

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

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

func (r MoveStateResource) MoveState(ctx context.Context) []resource.StateMover {
return []resource.StateMover{
{
SourceSchema: &schema.Schema{
Attributes: map[string]schema.Attribute{
"result": schema.StringAttribute{},
},
},
StateMover: func(ctx context.Context, req resource.MoveStateRequest, resp *resource.MoveStateResponse) {
if !strings.HasSuffix(req.SourceProviderAddress, "hashicorp/random") || req.SourceTypeName != "random_string" {
resp.Diagnostics.AddError(
"Invalid Move State Request",
fmt.Sprintf("This test can only migrate resource state from the \"random_string\" managed resource from the \"hashicorp/random\" provider:\n\n"+
"req.SourceProviderAddress: %q\n"+
"req.SourceTypeName: %q\n",
req.SourceProviderAddress,
req.SourceTypeName,
),
)
}

var oldState RandomStringResourceModel
resp.Diagnostics.Append(req.SourceState.Get(ctx, &oldState)...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.TargetState.SetAttribute(ctx, path.Root("moved_random_string"), oldState.Result)...)
},
},
}
}

// https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string
type RandomStringResourceModel struct {
Result types.String `tfsdk:"result"`
}

type MoveStateResourceModel struct {
MovedRandomString types.String `tfsdk:"moved_random_string"`
}
68 changes: 68 additions & 0 deletions internal/framework5provider/move_state_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package framework

import (
"testing"

"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-testing/compare"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

// This is a smoke test for using the "moved" block to transition state between
// the "random_string" managed resource and the corner provider "framework_move_state"
// managed resource.
//
// Ref: https://github.com/hashicorp/terraform-plugin-framework/issues/1039
func TestMoveStateResource(t *testing.T) {
randomStringSame := statecheck.CompareValue(compare.ValuesSame())

resource.UnitTest(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(tfversion.Version1_8_0),
},
ExternalProviders: map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
},
},
ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){
"framework": providerserver.NewProtocol5WithError(New()),
},
Steps: []resource.TestStep{
{
Config: `resource "random_string" "old" {
length = 12
}`,
ConfigStateChecks: []statecheck.StateCheck{
randomStringSame.AddStateValue("random_string.old", tfjsonpath.New("result")),
},
},
{
Config: `
moved {
from = random_string.old
to = framework_move_state.new
}
resource "framework_move_state" "new" {}
`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
ConfigStateChecks: []statecheck.StateCheck{
// The previous random_string.result value should be moved to this new location unchanged.
randomStringSame.AddStateValue("framework_move_state.new", tfjsonpath.New("moved_random_string")),
},
},
},
})
}
1 change: 1 addition & 0 deletions internal/framework5provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (p *testProvider) Resources(_ context.Context) []func() resource.Resource {
NewFloat32PrecisionResource,
NewFloat64PrecisionResource,
NewTFSDKReflectionResource,
NewMoveStateResource,
NewSetNestedBlockWithDefaultsResource,
}
}
Expand Down
121 changes: 121 additions & 0 deletions internal/framework6provider/move_state_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package framework

import (
"context"
"fmt"
"strings"

"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 = MoveStateResource{}
var _ resource.ResourceWithMoveState = MoveStateResource{}

func NewMoveStateResource() resource.Resource {
return &MoveStateResource{}
}

// MoveStateResource is for testing the MoveResourceState RPC
// https://developer.hashicorp.com/terraform/plugin/framework/resources/state-move
type MoveStateResource struct{}

func (r MoveStateResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_move_state"
}

func (r MoveStateResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"moved_random_string": schema.StringAttribute{
Computed: true,
},
},
}
}

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

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

if resp.Diagnostics.HasError() {
return
}

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

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

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

if resp.Diagnostics.HasError() {
return
}

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

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

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

if resp.Diagnostics.HasError() {
return
}

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

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

func (r MoveStateResource) MoveState(ctx context.Context) []resource.StateMover {
return []resource.StateMover{
{
SourceSchema: &schema.Schema{
Attributes: map[string]schema.Attribute{
"result": schema.StringAttribute{},
},
},
StateMover: func(ctx context.Context, req resource.MoveStateRequest, resp *resource.MoveStateResponse) {
if !strings.HasSuffix(req.SourceProviderAddress, "hashicorp/random") || req.SourceTypeName != "random_string" {
resp.Diagnostics.AddError(
"Invalid Move State Request",
fmt.Sprintf("This test can only migrate resource state from the \"random_string\" managed resource from the \"hashicorp/random\" provider:\n\n"+
"req.SourceProviderAddress: %q\n"+
"req.SourceTypeName: %q\n",
req.SourceProviderAddress,
req.SourceTypeName,
),
)
}

var oldState RandomStringResourceModel
resp.Diagnostics.Append(req.SourceState.Get(ctx, &oldState)...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.TargetState.SetAttribute(ctx, path.Root("moved_random_string"), oldState.Result)...)
},
},
}
}

// https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string
type RandomStringResourceModel struct {
Result types.String `tfsdk:"result"`
}

type MoveStateResourceModel struct {
MovedRandomString types.String `tfsdk:"moved_random_string"`
}
68 changes: 68 additions & 0 deletions internal/framework6provider/move_state_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package framework

import (
"testing"

"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-testing/compare"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

// This is a smoke test for using the "moved" block to transition state between
// the "random_string" managed resource and the corner provider "framework_move_state"
// managed resource.
//
// Ref: https://github.com/hashicorp/terraform-plugin-framework/issues/1039
func TestMoveStateResource(t *testing.T) {
randomStringSame := statecheck.CompareValue(compare.ValuesSame())

resource.UnitTest(t, resource.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(tfversion.Version1_8_0),
},
ExternalProviders: map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
},
},
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
"framework": providerserver.NewProtocol6WithError(New()),
},
Steps: []resource.TestStep{
{
Config: `resource "random_string" "old" {
length = 12
}`,
ConfigStateChecks: []statecheck.StateCheck{
randomStringSame.AddStateValue("random_string.old", tfjsonpath.New("result")),
},
},
{
Config: `
moved {
from = random_string.old
to = framework_move_state.new
}
resource "framework_move_state" "new" {}
`,
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
ConfigStateChecks: []statecheck.StateCheck{
// The previous random_string.result value should be moved to this new location unchanged.
randomStringSame.AddStateValue("framework_move_state.new", tfjsonpath.New("moved_random_string")),
},
},
},
})
}
1 change: 1 addition & 0 deletions internal/framework6provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (p *testProvider) Resources(_ context.Context) []func() resource.Resource {
NewFloat32PrecisionResource,
NewFloat64PrecisionResource,
NewTFSDKReflectionResource,
NewMoveStateResource,
NewSetNestedBlockWithDefaultsResource,
NewSetNestedAttributeWithDefaultsResource,
}
Expand Down

0 comments on commit 0ec4292

Please sign in to comment.