github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/node_resource_abstract_test.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/hashicorp/terraform/internal/addrs" 8 "github.com/hashicorp/terraform/internal/configs" 9 "github.com/hashicorp/terraform/internal/configs/configschema" 10 "github.com/hashicorp/terraform/internal/providers" 11 "github.com/hashicorp/terraform/internal/states" 12 "github.com/zclconf/go-cty/cty" 13 ) 14 15 func TestNodeAbstractResourceProvider(t *testing.T) { 16 tests := []struct { 17 Addr addrs.ConfigResource 18 Config *configs.Resource 19 Want addrs.Provider 20 }{ 21 { 22 Addr: addrs.Resource{ 23 Mode: addrs.ManagedResourceMode, 24 Type: "null_resource", 25 Name: "baz", 26 }.InModule(addrs.RootModule), 27 Want: addrs.Provider{ 28 Hostname: addrs.DefaultProviderRegistryHost, 29 Namespace: "hashicorp", 30 Type: "null", 31 }, 32 }, 33 { 34 Addr: addrs.Resource{ 35 Mode: addrs.DataResourceMode, 36 Type: "terraform_remote_state", 37 Name: "baz", 38 }.InModule(addrs.RootModule), 39 Want: addrs.Provider{ 40 // As a special case, the type prefix "terraform_" maps to 41 // the builtin provider, not the default one. 42 Hostname: addrs.BuiltInProviderHost, 43 Namespace: addrs.BuiltInProviderNamespace, 44 Type: "terraform", 45 }, 46 }, 47 { 48 Addr: addrs.Resource{ 49 Mode: addrs.ManagedResourceMode, 50 Type: "null_resource", 51 Name: "baz", 52 }.InModule(addrs.RootModule), 53 Config: &configs.Resource{ 54 // Just enough configs.Resource for the Provider method. Not 55 // actually valid for general use. 56 Provider: addrs.Provider{ 57 Hostname: addrs.DefaultProviderRegistryHost, 58 Namespace: "awesomecorp", 59 Type: "happycloud", 60 }, 61 }, 62 // The config overrides the default behavior. 63 Want: addrs.Provider{ 64 Hostname: addrs.DefaultProviderRegistryHost, 65 Namespace: "awesomecorp", 66 Type: "happycloud", 67 }, 68 }, 69 { 70 Addr: addrs.Resource{ 71 Mode: addrs.DataResourceMode, 72 Type: "terraform_remote_state", 73 Name: "baz", 74 }.InModule(addrs.RootModule), 75 Config: &configs.Resource{ 76 // Just enough configs.Resource for the Provider method. Not 77 // actually valid for general use. 78 Provider: addrs.Provider{ 79 Hostname: addrs.DefaultProviderRegistryHost, 80 Namespace: "awesomecorp", 81 Type: "happycloud", 82 }, 83 }, 84 // The config overrides the default behavior. 85 Want: addrs.Provider{ 86 Hostname: addrs.DefaultProviderRegistryHost, 87 Namespace: "awesomecorp", 88 Type: "happycloud", 89 }, 90 }, 91 } 92 93 for _, test := range tests { 94 var name string 95 if test.Config != nil { 96 name = fmt.Sprintf("%s with configured %s", test.Addr, test.Config.Provider) 97 } else { 98 name = fmt.Sprintf("%s with no configuration", test.Addr) 99 } 100 t.Run(name, func(t *testing.T) { 101 node := &NodeAbstractResource{ 102 // Just enough NodeAbstractResource for the Provider function. 103 // (This would not be valid for some other functions.) 104 Addr: test.Addr, 105 Config: test.Config, 106 } 107 got := node.Provider() 108 if got != test.Want { 109 t.Errorf("wrong result\naddr: %s\nconfig: %#v\ngot: %s\nwant: %s", test.Addr, test.Config, got, test.Want) 110 } 111 }) 112 } 113 } 114 115 func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) { 116 mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ 117 Attributes: map[string]*configschema.Attribute{ 118 "id": { 119 Type: cty.String, 120 Optional: true, 121 }, 122 }, 123 }) 124 // This test does not configure the provider, but the mock provider will 125 // check that this was called and report errors. 126 mockProvider.ConfigureProviderCalled = true 127 128 tests := map[string]struct { 129 State *states.State 130 Node *NodeAbstractResource 131 ExpectedInstanceId string 132 }{ 133 "ReadState gets primary instance state": { 134 State: states.BuildState(func(s *states.SyncState) { 135 providerAddr := addrs.AbsProviderConfig{ 136 Provider: addrs.NewDefaultProvider("aws"), 137 Module: addrs.RootModule, 138 } 139 oneAddr := addrs.Resource{ 140 Mode: addrs.ManagedResourceMode, 141 Type: "aws_instance", 142 Name: "bar", 143 }.Absolute(addrs.RootModuleInstance) 144 s.SetResourceProvider(oneAddr, providerAddr) 145 s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.NoKey), &states.ResourceInstanceObjectSrc{ 146 Status: states.ObjectReady, 147 AttrsJSON: []byte(`{"id":"i-abc123"}`), 148 }, providerAddr) 149 }), 150 Node: &NodeAbstractResource{ 151 Addr: mustConfigResourceAddr("aws_instance.bar"), 152 ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), 153 }, 154 ExpectedInstanceId: "i-abc123", 155 }, 156 } 157 158 for k, test := range tests { 159 t.Run(k, func(t *testing.T) { 160 ctx := new(MockEvalContext) 161 ctx.StateState = test.State.SyncWrapper() 162 ctx.PathPath = addrs.RootModuleInstance 163 ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() 164 165 ctx.ProviderProvider = providers.Interface(mockProvider) 166 167 got, readDiags := test.Node.readResourceInstanceState(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)) 168 if readDiags.HasErrors() { 169 t.Fatalf("[%s] Got err: %#v", k, readDiags.Err()) 170 } 171 172 expected := test.ExpectedInstanceId 173 174 if !(got != nil && got.Value.GetAttr("id") == cty.StringVal(expected)) { 175 t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, got) 176 } 177 }) 178 } 179 } 180 181 func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) { 182 mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ 183 Attributes: map[string]*configschema.Attribute{ 184 "id": { 185 Type: cty.String, 186 Optional: true, 187 }, 188 }, 189 }) 190 // This test does not configure the provider, but the mock provider will 191 // check that this was called and report errors. 192 mockProvider.ConfigureProviderCalled = true 193 194 tests := map[string]struct { 195 State *states.State 196 Node *NodeAbstractResource 197 ExpectedInstanceId string 198 }{ 199 "ReadStateDeposed gets deposed instance": { 200 State: states.BuildState(func(s *states.SyncState) { 201 providerAddr := addrs.AbsProviderConfig{ 202 Provider: addrs.NewDefaultProvider("aws"), 203 Module: addrs.RootModule, 204 } 205 oneAddr := addrs.Resource{ 206 Mode: addrs.ManagedResourceMode, 207 Type: "aws_instance", 208 Name: "bar", 209 }.Absolute(addrs.RootModuleInstance) 210 s.SetResourceProvider(oneAddr, providerAddr) 211 s.SetResourceInstanceDeposed(oneAddr.Instance(addrs.NoKey), states.DeposedKey("00000001"), &states.ResourceInstanceObjectSrc{ 212 Status: states.ObjectReady, 213 AttrsJSON: []byte(`{"id":"i-abc123"}`), 214 }, providerAddr) 215 }), 216 Node: &NodeAbstractResource{ 217 Addr: mustConfigResourceAddr("aws_instance.bar"), 218 ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), 219 }, 220 ExpectedInstanceId: "i-abc123", 221 }, 222 } 223 for k, test := range tests { 224 t.Run(k, func(t *testing.T) { 225 ctx := new(MockEvalContext) 226 ctx.StateState = test.State.SyncWrapper() 227 ctx.PathPath = addrs.RootModuleInstance 228 ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() 229 ctx.ProviderProvider = providers.Interface(mockProvider) 230 231 key := states.DeposedKey("00000001") // shim from legacy state assigns 0th deposed index this key 232 233 got, readDiags := test.Node.readResourceInstanceStateDeposed(ctx, test.Node.Addr.Resource.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), key) 234 if readDiags.HasErrors() { 235 t.Fatalf("[%s] Got err: %#v", k, readDiags.Err()) 236 } 237 238 expected := test.ExpectedInstanceId 239 240 if !(got != nil && got.Value.GetAttr("id") == cty.StringVal(expected)) { 241 t.Fatalf("[%s] Expected output with ID %#v, got: %#v", k, expected, got) 242 } 243 }) 244 } 245 }