github.com/opentofu/opentofu@v1.7.1/internal/tofu/transform_import_state_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package tofu 7 8 import ( 9 "strings" 10 "testing" 11 12 "github.com/opentofu/opentofu/internal/addrs" 13 "github.com/opentofu/opentofu/internal/configs/configschema" 14 "github.com/opentofu/opentofu/internal/providers" 15 "github.com/opentofu/opentofu/internal/states" 16 "github.com/zclconf/go-cty/cty" 17 ) 18 19 func TestGraphNodeImportStateExecute(t *testing.T) { 20 state := states.NewState() 21 provider := testProvider("aws") 22 provider.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 23 ImportedResources: []providers.ImportedResource{ 24 { 25 TypeName: "aws_instance", 26 State: cty.ObjectVal(map[string]cty.Value{ 27 "id": cty.StringVal("bar"), 28 }), 29 }, 30 }, 31 } 32 provider.ConfigureProvider(providers.ConfigureProviderRequest{}) 33 34 ctx := &MockEvalContext{ 35 StateState: state.SyncWrapper(), 36 ProviderProvider: provider, 37 } 38 39 // Import a new aws_instance.foo, this time with ID=bar. The original 40 // aws_instance.foo object should be removed from state and replaced with 41 // the new. 42 node := graphNodeImportState{ 43 Addr: addrs.Resource{ 44 Mode: addrs.ManagedResourceMode, 45 Type: "aws_instance", 46 Name: "foo", 47 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 48 ID: "bar", 49 ResolvedProvider: addrs.AbsProviderConfig{ 50 Provider: addrs.NewDefaultProvider("aws"), 51 Module: addrs.RootModule, 52 }, 53 } 54 55 diags := node.Execute(ctx, walkImport) 56 if diags.HasErrors() { 57 t.Fatalf("Unexpected error: %s", diags.Err()) 58 } 59 60 if len(node.states) != 1 { 61 t.Fatalf("Wrong result! Expected one imported resource, got %d", len(node.states)) 62 } 63 // Verify the ID for good measure 64 id := node.states[0].State.GetAttr("id") 65 if !id.RawEquals(cty.StringVal("bar")) { 66 t.Fatalf("Wrong result! Expected id \"bar\", got %q", id.AsString()) 67 } 68 } 69 70 func TestGraphNodeImportStateSubExecute(t *testing.T) { 71 state := states.NewState() 72 provider := testProvider("aws") 73 provider.ConfigureProvider(providers.ConfigureProviderRequest{}) 74 ctx := &MockEvalContext{ 75 StateState: state.SyncWrapper(), 76 ProviderProvider: provider, 77 ProviderSchemaSchema: providers.ProviderSchema{ 78 ResourceTypes: map[string]providers.Schema{ 79 "aws_instance": { 80 Block: &configschema.Block{ 81 Attributes: map[string]*configschema.Attribute{ 82 "id": { 83 Type: cty.String, 84 Computed: true, 85 }, 86 }, 87 }, 88 }, 89 }, 90 }, 91 } 92 93 importedResource := providers.ImportedResource{ 94 TypeName: "aws_instance", 95 State: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}), 96 } 97 98 node := graphNodeImportStateSub{ 99 TargetAddr: addrs.Resource{ 100 Mode: addrs.ManagedResourceMode, 101 Type: "aws_instance", 102 Name: "foo", 103 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 104 State: importedResource, 105 ResolvedProvider: addrs.AbsProviderConfig{ 106 Provider: addrs.NewDefaultProvider("aws"), 107 Module: addrs.RootModule, 108 }, 109 } 110 diags := node.Execute(ctx, walkImport) 111 if diags.HasErrors() { 112 t.Fatalf("Unexpected error: %s", diags.Err()) 113 } 114 115 // check for resource in state 116 actual := strings.TrimSpace(state.String()) 117 expected := `aws_instance.foo: 118 ID = bar 119 provider = provider["registry.opentofu.org/hashicorp/aws"]` 120 if actual != expected { 121 t.Fatalf("bad state after import: \n%s", actual) 122 } 123 } 124 125 func TestGraphNodeImportStateSubExecuteNull(t *testing.T) { 126 state := states.NewState() 127 provider := testProvider("aws") 128 provider.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { 129 // return null indicating that the requested resource does not exist 130 resp.NewState = cty.NullVal(cty.Object(map[string]cty.Type{ 131 "id": cty.String, 132 })) 133 return resp 134 } 135 136 ctx := &MockEvalContext{ 137 StateState: state.SyncWrapper(), 138 ProviderProvider: provider, 139 ProviderSchemaSchema: providers.ProviderSchema{ 140 ResourceTypes: map[string]providers.Schema{ 141 "aws_instance": { 142 Block: &configschema.Block{ 143 Attributes: map[string]*configschema.Attribute{ 144 "id": { 145 Type: cty.String, 146 Computed: true, 147 }, 148 }, 149 }, 150 }, 151 }, 152 }, 153 } 154 155 importedResource := providers.ImportedResource{ 156 TypeName: "aws_instance", 157 State: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}), 158 } 159 160 node := graphNodeImportStateSub{ 161 TargetAddr: addrs.Resource{ 162 Mode: addrs.ManagedResourceMode, 163 Type: "aws_instance", 164 Name: "foo", 165 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 166 State: importedResource, 167 ResolvedProvider: addrs.AbsProviderConfig{ 168 Provider: addrs.NewDefaultProvider("aws"), 169 Module: addrs.RootModule, 170 }, 171 } 172 diags := node.Execute(ctx, walkImport) 173 if !diags.HasErrors() { 174 t.Fatal("expected error for non-existent resource") 175 } 176 }