github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/transform_provider_test.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/hashicorp/terraform/internal/addrs" 9 "github.com/hashicorp/terraform/internal/configs" 10 "github.com/hashicorp/terraform/internal/dag" 11 ) 12 13 func testProviderTransformerGraph(t *testing.T, cfg *configs.Config) *Graph { 14 t.Helper() 15 16 g := &Graph{Path: addrs.RootModuleInstance} 17 ct := &ConfigTransformer{Config: cfg} 18 if err := ct.Transform(g); err != nil { 19 t.Fatal(err) 20 } 21 arct := &AttachResourceConfigTransformer{Config: cfg} 22 if err := arct.Transform(g); err != nil { 23 t.Fatal(err) 24 } 25 26 return g 27 } 28 29 func TestProviderTransformer(t *testing.T) { 30 mod := testModule(t, "transform-provider-basic") 31 32 g := testProviderTransformerGraph(t, mod) 33 { 34 transform := &MissingProviderTransformer{} 35 if err := transform.Transform(g); err != nil { 36 t.Fatalf("err: %s", err) 37 } 38 } 39 40 transform := &ProviderTransformer{} 41 if err := transform.Transform(g); err != nil { 42 t.Fatalf("err: %s", err) 43 } 44 45 actual := strings.TrimSpace(g.String()) 46 expected := strings.TrimSpace(testTransformProviderBasicStr) 47 if actual != expected { 48 t.Fatalf("bad:\n\n%s", actual) 49 } 50 } 51 52 // Test providers with FQNs that do not match the typeName 53 func TestProviderTransformer_fqns(t *testing.T) { 54 for _, mod := range []string{"fqns", "fqns-module"} { 55 mod := testModule(t, fmt.Sprintf("transform-provider-%s", mod)) 56 57 g := testProviderTransformerGraph(t, mod) 58 { 59 transform := &MissingProviderTransformer{Config: mod} 60 if err := transform.Transform(g); err != nil { 61 t.Fatalf("err: %s", err) 62 } 63 } 64 65 transform := &ProviderTransformer{Config: mod} 66 if err := transform.Transform(g); err != nil { 67 t.Fatalf("err: %s", err) 68 } 69 70 actual := strings.TrimSpace(g.String()) 71 expected := strings.TrimSpace(testTransformProviderBasicStr) 72 if actual != expected { 73 t.Fatalf("bad:\n\n%s", actual) 74 } 75 } 76 } 77 78 func TestCloseProviderTransformer(t *testing.T) { 79 mod := testModule(t, "transform-provider-basic") 80 g := testProviderTransformerGraph(t, mod) 81 82 { 83 transform := &MissingProviderTransformer{} 84 if err := transform.Transform(g); err != nil { 85 t.Fatalf("err: %s", err) 86 } 87 } 88 89 { 90 transform := &ProviderTransformer{} 91 if err := transform.Transform(g); err != nil { 92 t.Fatalf("err: %s", err) 93 } 94 } 95 96 { 97 transform := &CloseProviderTransformer{} 98 if err := transform.Transform(g); err != nil { 99 t.Fatalf("err: %s", err) 100 } 101 } 102 103 actual := strings.TrimSpace(g.String()) 104 expected := strings.TrimSpace(testTransformCloseProviderBasicStr) 105 if actual != expected { 106 t.Fatalf("bad:\n\n%s", actual) 107 } 108 } 109 110 func TestCloseProviderTransformer_withTargets(t *testing.T) { 111 mod := testModule(t, "transform-provider-basic") 112 113 g := testProviderTransformerGraph(t, mod) 114 transforms := []GraphTransformer{ 115 &MissingProviderTransformer{}, 116 &ProviderTransformer{}, 117 &CloseProviderTransformer{}, 118 &TargetsTransformer{ 119 Targets: []addrs.Targetable{ 120 addrs.RootModuleInstance.Resource( 121 addrs.ManagedResourceMode, "something", "else", 122 ), 123 }, 124 }, 125 } 126 127 for _, tr := range transforms { 128 if err := tr.Transform(g); err != nil { 129 t.Fatalf("err: %s", err) 130 } 131 } 132 133 actual := strings.TrimSpace(g.String()) 134 expected := strings.TrimSpace(``) 135 if actual != expected { 136 t.Fatalf("expected:%s\n\ngot:\n\n%s", expected, actual) 137 } 138 } 139 140 func TestMissingProviderTransformer(t *testing.T) { 141 mod := testModule(t, "transform-provider-missing") 142 143 g := testProviderTransformerGraph(t, mod) 144 { 145 transform := &MissingProviderTransformer{} 146 if err := transform.Transform(g); err != nil { 147 t.Fatalf("err: %s", err) 148 } 149 } 150 151 { 152 transform := &ProviderTransformer{} 153 if err := transform.Transform(g); err != nil { 154 t.Fatalf("err: %s", err) 155 } 156 } 157 158 { 159 transform := &CloseProviderTransformer{} 160 if err := transform.Transform(g); err != nil { 161 t.Fatalf("err: %s", err) 162 } 163 } 164 165 actual := strings.TrimSpace(g.String()) 166 expected := strings.TrimSpace(testTransformMissingProviderBasicStr) 167 if actual != expected { 168 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 169 } 170 } 171 172 func TestMissingProviderTransformer_grandchildMissing(t *testing.T) { 173 mod := testModule(t, "transform-provider-missing-grandchild") 174 175 concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } 176 177 g := testProviderTransformerGraph(t, mod) 178 { 179 transform := transformProviders(concrete, mod) 180 if err := transform.Transform(g); err != nil { 181 t.Fatalf("err: %s", err) 182 } 183 } 184 { 185 transform := &TransitiveReductionTransformer{} 186 if err := transform.Transform(g); err != nil { 187 t.Fatalf("err: %s", err) 188 } 189 } 190 191 actual := strings.TrimSpace(g.String()) 192 expected := strings.TrimSpace(testTransformMissingGrandchildProviderStr) 193 if actual != expected { 194 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 195 } 196 } 197 198 func TestPruneProviderTransformer(t *testing.T) { 199 mod := testModule(t, "transform-provider-prune") 200 201 g := testProviderTransformerGraph(t, mod) 202 { 203 transform := &MissingProviderTransformer{} 204 if err := transform.Transform(g); err != nil { 205 t.Fatalf("err: %s", err) 206 } 207 } 208 209 { 210 transform := &ProviderTransformer{} 211 if err := transform.Transform(g); err != nil { 212 t.Fatalf("err: %s", err) 213 } 214 } 215 216 { 217 transform := &CloseProviderTransformer{} 218 if err := transform.Transform(g); err != nil { 219 t.Fatalf("err: %s", err) 220 } 221 } 222 223 { 224 transform := &PruneProviderTransformer{} 225 if err := transform.Transform(g); err != nil { 226 t.Fatalf("err: %s", err) 227 } 228 } 229 230 actual := strings.TrimSpace(g.String()) 231 expected := strings.TrimSpace(testTransformPruneProviderBasicStr) 232 if actual != expected { 233 t.Fatalf("bad:\n\n%s", actual) 234 } 235 } 236 237 // the child module resource is attached to the configured parent provider 238 func TestProviderConfigTransformer_parentProviders(t *testing.T) { 239 mod := testModule(t, "transform-provider-inherit") 240 concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } 241 242 g := testProviderTransformerGraph(t, mod) 243 { 244 tf := transformProviders(concrete, mod) 245 if err := tf.Transform(g); err != nil { 246 t.Fatalf("err: %s", err) 247 } 248 } 249 250 actual := strings.TrimSpace(g.String()) 251 expected := strings.TrimSpace(testTransformModuleProviderConfigStr) 252 if actual != expected { 253 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 254 } 255 } 256 257 // the child module resource is attached to the configured grand-parent provider 258 func TestProviderConfigTransformer_grandparentProviders(t *testing.T) { 259 mod := testModule(t, "transform-provider-grandchild-inherit") 260 concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } 261 262 g := testProviderTransformerGraph(t, mod) 263 { 264 tf := transformProviders(concrete, mod) 265 if err := tf.Transform(g); err != nil { 266 t.Fatalf("err: %s", err) 267 } 268 } 269 270 actual := strings.TrimSpace(g.String()) 271 expected := strings.TrimSpace(testTransformModuleProviderGrandparentStr) 272 if actual != expected { 273 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 274 } 275 } 276 277 func TestProviderConfigTransformer_inheritOldSkool(t *testing.T) { 278 mod := testModuleInline(t, map[string]string{ 279 "main.tf": ` 280 provider "test" { 281 test_string = "config" 282 } 283 284 module "moda" { 285 source = "./moda" 286 } 287 `, 288 289 "moda/main.tf": ` 290 resource "test_object" "a" { 291 } 292 `, 293 }) 294 concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } 295 296 g := testProviderTransformerGraph(t, mod) 297 { 298 tf := transformProviders(concrete, mod) 299 if err := tf.Transform(g); err != nil { 300 t.Fatalf("err: %s", err) 301 } 302 } 303 304 expected := `module.moda.test_object.a 305 provider["registry.terraform.io/hashicorp/test"] 306 provider["registry.terraform.io/hashicorp/test"]` 307 308 actual := strings.TrimSpace(g.String()) 309 if actual != expected { 310 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 311 } 312 } 313 314 // Verify that configurations which are not recommended yet supported still work 315 func TestProviderConfigTransformer_nestedModuleProviders(t *testing.T) { 316 mod := testModuleInline(t, map[string]string{ 317 "main.tf": ` 318 terraform { 319 required_providers { 320 test = { 321 source = "registry.terraform.io/hashicorp/test" 322 } 323 } 324 } 325 326 provider "test" { 327 alias = "z" 328 test_string = "config" 329 } 330 331 module "moda" { 332 source = "./moda" 333 providers = { 334 test.x = test.z 335 } 336 } 337 `, 338 339 "moda/main.tf": ` 340 terraform { 341 required_providers { 342 test = { 343 source = "registry.terraform.io/hashicorp/test" 344 configuration_aliases = [ test.x ] 345 } 346 } 347 } 348 349 provider "test" { 350 test_string = "config" 351 } 352 353 // this should connect to this module's provider 354 resource "test_object" "a" { 355 } 356 357 resource "test_object" "x" { 358 provider = test.x 359 } 360 361 module "modb" { 362 source = "./modb" 363 } 364 `, 365 366 "moda/modb/main.tf": ` 367 # this should end up with the provider from the parent module 368 resource "test_object" "a" { 369 } 370 `, 371 }) 372 concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } 373 374 g := testProviderTransformerGraph(t, mod) 375 { 376 tf := transformProviders(concrete, mod) 377 if err := tf.Transform(g); err != nil { 378 t.Fatalf("err: %s", err) 379 } 380 } 381 382 expected := `module.moda.module.modb.test_object.a 383 module.moda.provider["registry.terraform.io/hashicorp/test"] 384 module.moda.provider["registry.terraform.io/hashicorp/test"] 385 module.moda.test_object.a 386 module.moda.provider["registry.terraform.io/hashicorp/test"] 387 module.moda.test_object.x 388 provider["registry.terraform.io/hashicorp/test"].z 389 provider["registry.terraform.io/hashicorp/test"].z` 390 391 actual := strings.TrimSpace(g.String()) 392 if actual != expected { 393 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 394 } 395 } 396 397 func TestProviderConfigTransformer_duplicateLocalName(t *testing.T) { 398 mod := testModuleInline(t, map[string]string{ 399 "main.tf": ` 400 terraform { 401 required_providers { 402 # We have to allow this since it wasn't previously prevented. If the 403 # default config is equivalent to the provider config, the user may never 404 # see an error. 405 dupe = { 406 source = "registry.terraform.io/hashicorp/test" 407 } 408 } 409 } 410 411 provider "test" { 412 } 413 `}) 414 concrete := func(a *NodeAbstractProvider) dag.Vertex { return a } 415 416 g := testProviderTransformerGraph(t, mod) 417 tf := ProviderConfigTransformer{ 418 Config: mod, 419 Concrete: concrete, 420 } 421 if err := tf.Transform(g); err != nil { 422 t.Fatalf("err: %s", err) 423 } 424 425 expected := `provider["registry.terraform.io/hashicorp/test"]` 426 427 actual := strings.TrimSpace(g.String()) 428 if actual != expected { 429 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 430 } 431 } 432 433 const testTransformProviderBasicStr = ` 434 aws_instance.web 435 provider["registry.terraform.io/hashicorp/aws"] 436 provider["registry.terraform.io/hashicorp/aws"] 437 ` 438 439 const testTransformCloseProviderBasicStr = ` 440 aws_instance.web 441 provider["registry.terraform.io/hashicorp/aws"] 442 provider["registry.terraform.io/hashicorp/aws"] 443 provider["registry.terraform.io/hashicorp/aws"] (close) 444 aws_instance.web 445 provider["registry.terraform.io/hashicorp/aws"] 446 ` 447 448 const testTransformMissingProviderBasicStr = ` 449 aws_instance.web 450 provider["registry.terraform.io/hashicorp/aws"] 451 foo_instance.web 452 provider["registry.terraform.io/hashicorp/foo"] 453 provider["registry.terraform.io/hashicorp/aws"] 454 provider["registry.terraform.io/hashicorp/aws"] (close) 455 aws_instance.web 456 provider["registry.terraform.io/hashicorp/aws"] 457 provider["registry.terraform.io/hashicorp/foo"] 458 provider["registry.terraform.io/hashicorp/foo"] (close) 459 foo_instance.web 460 provider["registry.terraform.io/hashicorp/foo"] 461 ` 462 463 const testTransformMissingGrandchildProviderStr = ` 464 module.sub.module.subsub.bar_instance.two 465 provider["registry.terraform.io/hashicorp/bar"] 466 module.sub.module.subsub.foo_instance.one 467 module.sub.provider["registry.terraform.io/hashicorp/foo"] 468 module.sub.provider["registry.terraform.io/hashicorp/foo"] 469 provider["registry.terraform.io/hashicorp/bar"] 470 ` 471 472 const testTransformPruneProviderBasicStr = ` 473 foo_instance.web 474 provider["registry.terraform.io/hashicorp/foo"] 475 provider["registry.terraform.io/hashicorp/foo"] 476 provider["registry.terraform.io/hashicorp/foo"] (close) 477 foo_instance.web 478 provider["registry.terraform.io/hashicorp/foo"] 479 ` 480 481 const testTransformModuleProviderConfigStr = ` 482 module.child.aws_instance.thing 483 provider["registry.terraform.io/hashicorp/aws"].foo 484 provider["registry.terraform.io/hashicorp/aws"].foo 485 ` 486 487 const testTransformModuleProviderGrandparentStr = ` 488 module.child.module.grandchild.aws_instance.baz 489 provider["registry.terraform.io/hashicorp/aws"].foo 490 provider["registry.terraform.io/hashicorp/aws"].foo 491 `