opentofu/internal/tofu/node_resource_destroy_deposed_test.go
2023-09-20 15:16:53 +03:00

220 lines
6.4 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package tofu
import (
"testing"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/zclconf/go-cty/cty"
)
func TestNodePlanDeposedResourceInstanceObject_Execute(t *testing.T) {
deposedKey := states.NewDeposedKey()
state := states.NewState()
absResource := mustResourceInstanceAddr("test_instance.foo")
state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed(
absResource.Resource,
deposedKey,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectTainted,
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
p := testProvider("test")
p.ConfigureProvider(providers.ConfigureProviderRequest{})
p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
UpgradedState: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("bar"),
}),
}
ctx := &MockEvalContext{
StateState: state.SyncWrapper(),
PrevRunStateState: state.DeepCopy().SyncWrapper(),
RefreshStateState: state.DeepCopy().SyncWrapper(),
ProviderProvider: p,
ProviderSchemaSchema: providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"test_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
},
},
},
},
},
ChangesChanges: plans.NewChanges().SyncWrapper(),
}
node := NodePlanDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
},
},
DeposedKey: deposedKey,
}
err := node.Execute(ctx, walkPlan)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !p.UpgradeResourceStateCalled {
t.Errorf("UpgradeResourceState wasn't called; should've been called to upgrade the previous run's object")
}
if !p.ReadResourceCalled {
t.Errorf("ReadResource wasn't called; should've been called to refresh the deposed object")
}
change := ctx.Changes().GetResourceInstanceChange(absResource, deposedKey)
if got, want := change.ChangeSrc.Action, plans.Delete; got != want {
t.Fatalf("wrong planned action\ngot: %s\nwant: %s", got, want)
}
}
func TestNodeDestroyDeposedResourceInstanceObject_Execute(t *testing.T) {
deposedKey := states.NewDeposedKey()
state := states.NewState()
absResource := mustResourceInstanceAddr("test_instance.foo")
state.Module(addrs.RootModuleInstance).SetResourceInstanceDeposed(
absResource.Resource,
deposedKey,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectTainted,
AttrsJSON: []byte(`{"id":"bar"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
schema := providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"test_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
},
},
},
},
}
p := testProvider("test")
p.ConfigureProvider(providers.ConfigureProviderRequest{})
p.GetProviderSchemaResponse = &schema
p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
UpgradedState: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("bar"),
}),
}
ctx := &MockEvalContext{
StateState: state.SyncWrapper(),
ProviderProvider: p,
ProviderSchemaSchema: schema,
ChangesChanges: plans.NewChanges().SyncWrapper(),
}
node := NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: absResource,
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
},
},
DeposedKey: deposedKey,
}
err := node.Execute(ctx, walkApply)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !state.Empty() {
t.Fatalf("resources left in state after destroy")
}
}
func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t *testing.T) {
state := states.NewState()
ctx := new(MockEvalContext)
ctx.StateState = state.SyncWrapper()
ctx.PathPath = addrs.RootModuleInstance
mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Optional: true,
},
},
})
ctx.ProviderProvider = mockProvider
ctx.ProviderSchemaSchema = mockProvider.GetProviderSchema()
obj := &states.ResourceInstanceObject{
Value: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("i-abc123"),
}),
Status: states.ObjectReady,
}
node := &NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
},
Addr: mustResourceInstanceAddr("aws_instance.foo"),
},
DeposedKey: states.NewDeposedKey(),
}
err := node.writeResourceInstanceState(ctx, obj)
if err != nil {
t.Fatalf("unexpected error: %s", err.Error())
}
checkStateString(t, state, `
aws_instance.foo: (1 deposed)
ID = <not created>
provider = provider["registry.terraform.io/hashicorp/aws"]
Deposed ID 1 = i-abc123
`)
}
func TestNodeDestroyDeposedResourceInstanceObject_ExecuteMissingState(t *testing.T) {
p := simpleMockProvider()
ctx := &MockEvalContext{
StateState: states.NewState().SyncWrapper(),
ProviderProvider: simpleMockProvider(),
ProviderSchemaSchema: p.GetProviderSchema(),
ChangesChanges: plans.NewChanges().SyncWrapper(),
}
node := NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
Addr: mustResourceInstanceAddr("test_object.foo"),
NodeAbstractResource: NodeAbstractResource{
ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
},
},
DeposedKey: states.NewDeposedKey(),
}
err := node.Execute(ctx, walkApply)
if err == nil {
t.Fatal("expected error")
}
}