github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/terraform/context_input_test.go (about) 1 package terraform 2 3 import ( 4 "reflect" 5 "strings" 6 "sync" 7 "testing" 8 ) 9 10 func TestContext2Input(t *testing.T) { 11 input := new(MockUIInput) 12 m := testModule(t, "input-vars") 13 p := testProvider("aws") 14 p.ApplyFn = testApplyFn 15 p.DiffFn = testDiffFn 16 ctx := testContext2(t, &ContextOpts{ 17 Module: m, 18 ProviderResolver: ResourceProviderResolverFixed( 19 map[string]ResourceProviderFactory{ 20 "aws": testProviderFuncFixed(p), 21 }, 22 ), 23 Variables: map[string]interface{}{ 24 "foo": "us-west-2", 25 "amis": []map[string]interface{}{ 26 map[string]interface{}{ 27 "us-east-1": "override", 28 }, 29 }, 30 }, 31 UIInput: input, 32 }) 33 34 input.InputReturnMap = map[string]string{ 35 "var.foo": "us-east-1", 36 } 37 38 if err := ctx.Input(InputModeStd); err != nil { 39 t.Fatalf("err: %s", err) 40 } 41 42 if _, err := ctx.Plan(); err != nil { 43 t.Fatalf("err: %s", err) 44 } 45 46 state, err := ctx.Apply() 47 if err != nil { 48 t.Fatalf("err: %s", err) 49 } 50 51 actual := strings.TrimSpace(state.String()) 52 expected := strings.TrimSpace(testTerraformInputVarsStr) 53 if actual != expected { 54 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 55 } 56 } 57 58 func TestContext2Input_moduleComputedOutputElement(t *testing.T) { 59 m := testModule(t, "input-module-computed-output-element") 60 p := testProvider("aws") 61 p.ApplyFn = testApplyFn 62 p.DiffFn = testDiffFn 63 ctx := testContext2(t, &ContextOpts{ 64 Module: m, 65 ProviderResolver: ResourceProviderResolverFixed( 66 map[string]ResourceProviderFactory{ 67 "aws": testProviderFuncFixed(p), 68 }, 69 ), 70 }) 71 72 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 73 return c, nil 74 } 75 76 if err := ctx.Input(InputModeStd); err != nil { 77 t.Fatalf("err: %s", err) 78 } 79 } 80 81 func TestContext2Input_badVarDefault(t *testing.T) { 82 m := testModule(t, "input-bad-var-default") 83 p := testProvider("aws") 84 p.ApplyFn = testApplyFn 85 p.DiffFn = testDiffFn 86 ctx := testContext2(t, &ContextOpts{ 87 Module: m, 88 ProviderResolver: ResourceProviderResolverFixed( 89 map[string]ResourceProviderFactory{ 90 "aws": testProviderFuncFixed(p), 91 }, 92 ), 93 }) 94 95 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 96 c.Config["foo"] = "bar" 97 return c, nil 98 } 99 100 if err := ctx.Input(InputModeStd); err != nil { 101 t.Fatalf("err: %s", err) 102 } 103 } 104 105 func TestContext2Input_provider(t *testing.T) { 106 m := testModule(t, "input-provider") 107 p := testProvider("aws") 108 p.ApplyFn = testApplyFn 109 p.DiffFn = testDiffFn 110 ctx := testContext2(t, &ContextOpts{ 111 Module: m, 112 ProviderResolver: ResourceProviderResolverFixed( 113 map[string]ResourceProviderFactory{ 114 "aws": testProviderFuncFixed(p), 115 }, 116 ), 117 }) 118 119 var actual interface{} 120 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 121 c.Config["foo"] = "bar" 122 return c, nil 123 } 124 p.ConfigureFn = func(c *ResourceConfig) error { 125 actual = c.Config["foo"] 126 return nil 127 } 128 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 129 return nil, c.CheckSet([]string{"foo"}) 130 } 131 132 if err := ctx.Input(InputModeStd); err != nil { 133 t.Fatalf("err: %s", err) 134 } 135 136 if _, err := ctx.Plan(); err != nil { 137 t.Fatalf("err: %s", err) 138 } 139 140 if _, err := ctx.Apply(); err != nil { 141 t.Fatalf("err: %s", err) 142 } 143 144 if !reflect.DeepEqual(actual, "bar") { 145 t.Fatalf("bad: %#v", actual) 146 } 147 } 148 149 func TestContext2Input_providerMulti(t *testing.T) { 150 m := testModule(t, "input-provider-multi") 151 p := testProvider("aws") 152 p.ApplyFn = testApplyFn 153 p.DiffFn = testDiffFn 154 ctx := testContext2(t, &ContextOpts{ 155 Module: m, 156 ProviderResolver: ResourceProviderResolverFixed( 157 map[string]ResourceProviderFactory{ 158 "aws": testProviderFuncFixed(p), 159 }, 160 ), 161 }) 162 163 var actual []interface{} 164 var lock sync.Mutex 165 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 166 c.Config["foo"] = "bar" 167 return c, nil 168 } 169 p.ConfigureFn = func(c *ResourceConfig) error { 170 lock.Lock() 171 defer lock.Unlock() 172 actual = append(actual, c.Config["foo"]) 173 return nil 174 } 175 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 176 return nil, c.CheckSet([]string{"foo"}) 177 } 178 179 if err := ctx.Input(InputModeStd); err != nil { 180 t.Fatalf("err: %s", err) 181 } 182 183 if _, err := ctx.Plan(); err != nil { 184 t.Fatalf("err: %s", err) 185 } 186 187 if _, err := ctx.Apply(); err != nil { 188 t.Fatalf("err: %s", err) 189 } 190 191 expected := []interface{}{"bar", "bar"} 192 if !reflect.DeepEqual(actual, expected) { 193 t.Fatalf("bad: %#v", actual) 194 } 195 } 196 197 func TestContext2Input_providerOnce(t *testing.T) { 198 m := testModule(t, "input-provider-once") 199 p := testProvider("aws") 200 p.ApplyFn = testApplyFn 201 p.DiffFn = testDiffFn 202 ctx := testContext2(t, &ContextOpts{ 203 Module: m, 204 ProviderResolver: ResourceProviderResolverFixed( 205 map[string]ResourceProviderFactory{ 206 "aws": testProviderFuncFixed(p), 207 }, 208 ), 209 }) 210 211 count := 0 212 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 213 count++ 214 return nil, nil 215 } 216 217 if err := ctx.Input(InputModeStd); err != nil { 218 t.Fatalf("err: %s", err) 219 } 220 221 if count != 1 { 222 t.Fatalf("should only be called once: %d", count) 223 } 224 } 225 226 func TestContext2Input_providerId(t *testing.T) { 227 input := new(MockUIInput) 228 m := testModule(t, "input-provider") 229 p := testProvider("aws") 230 p.ApplyFn = testApplyFn 231 p.DiffFn = testDiffFn 232 ctx := testContext2(t, &ContextOpts{ 233 Module: m, 234 ProviderResolver: ResourceProviderResolverFixed( 235 map[string]ResourceProviderFactory{ 236 "aws": testProviderFuncFixed(p), 237 }, 238 ), 239 UIInput: input, 240 }) 241 242 var actual interface{} 243 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 244 v, err := i.Input(&InputOpts{Id: "foo"}) 245 if err != nil { 246 return nil, err 247 } 248 249 c.Config["foo"] = v 250 return c, nil 251 } 252 p.ConfigureFn = func(c *ResourceConfig) error { 253 actual = c.Config["foo"] 254 return nil 255 } 256 257 input.InputReturnMap = map[string]string{ 258 "provider.aws.foo": "bar", 259 } 260 261 if err := ctx.Input(InputModeStd); err != nil { 262 t.Fatalf("err: %s", err) 263 } 264 265 if _, err := ctx.Plan(); err != nil { 266 t.Fatalf("err: %s", err) 267 } 268 269 if _, err := ctx.Apply(); err != nil { 270 t.Fatalf("err: %s", err) 271 } 272 273 if !reflect.DeepEqual(actual, "bar") { 274 t.Fatalf("bad: %#v", actual) 275 } 276 } 277 278 func TestContext2Input_providerOnly(t *testing.T) { 279 input := new(MockUIInput) 280 m := testModule(t, "input-provider-vars") 281 p := testProvider("aws") 282 p.ApplyFn = testApplyFn 283 p.DiffFn = testDiffFn 284 ctx := testContext2(t, &ContextOpts{ 285 Module: m, 286 ProviderResolver: ResourceProviderResolverFixed( 287 map[string]ResourceProviderFactory{ 288 "aws": testProviderFuncFixed(p), 289 }, 290 ), 291 Variables: map[string]interface{}{ 292 "foo": "us-west-2", 293 }, 294 UIInput: input, 295 }) 296 297 input.InputReturnMap = map[string]string{ 298 "var.foo": "us-east-1", 299 } 300 301 var actual interface{} 302 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 303 c.Config["foo"] = "bar" 304 return c, nil 305 } 306 p.ConfigureFn = func(c *ResourceConfig) error { 307 actual = c.Config["foo"] 308 return nil 309 } 310 311 if err := ctx.Input(InputModeProvider); err != nil { 312 t.Fatalf("err: %s", err) 313 } 314 315 if _, err := ctx.Plan(); err != nil { 316 t.Fatalf("err: %s", err) 317 } 318 319 state, err := ctx.Apply() 320 if err != nil { 321 t.Fatalf("err: %s", err) 322 } 323 324 if !reflect.DeepEqual(actual, "bar") { 325 t.Fatalf("bad: %#v", actual) 326 } 327 328 actualStr := strings.TrimSpace(state.String()) 329 expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr) 330 if actualStr != expectedStr { 331 t.Fatalf("bad: \n%s", actualStr) 332 } 333 } 334 335 func TestContext2Input_providerVars(t *testing.T) { 336 input := new(MockUIInput) 337 m := testModule(t, "input-provider-with-vars") 338 p := testProvider("aws") 339 p.ApplyFn = testApplyFn 340 p.DiffFn = testDiffFn 341 ctx := testContext2(t, &ContextOpts{ 342 Module: m, 343 ProviderResolver: ResourceProviderResolverFixed( 344 map[string]ResourceProviderFactory{ 345 "aws": testProviderFuncFixed(p), 346 }, 347 ), 348 Variables: map[string]interface{}{ 349 "foo": "bar", 350 }, 351 UIInput: input, 352 }) 353 354 input.InputReturnMap = map[string]string{ 355 "var.foo": "bar", 356 } 357 358 var actual interface{} 359 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 360 c.Config["bar"] = "baz" 361 return c, nil 362 } 363 p.ConfigureFn = func(c *ResourceConfig) error { 364 actual, _ = c.Get("foo") 365 return nil 366 } 367 368 if err := ctx.Input(InputModeStd); err != nil { 369 t.Fatalf("err: %s", err) 370 } 371 372 if _, err := ctx.Plan(); err != nil { 373 t.Fatalf("err: %s", err) 374 } 375 376 if _, err := ctx.Apply(); err != nil { 377 t.Fatalf("err: %s", err) 378 } 379 380 if !reflect.DeepEqual(actual, "bar") { 381 t.Fatalf("bad: %#v", actual) 382 } 383 } 384 385 func TestContext2Input_providerVarsModuleInherit(t *testing.T) { 386 input := new(MockUIInput) 387 m := testModule(t, "input-provider-with-vars-and-module") 388 p := testProvider("aws") 389 p.ApplyFn = testApplyFn 390 p.DiffFn = testDiffFn 391 ctx := testContext2(t, &ContextOpts{ 392 Module: m, 393 ProviderResolver: ResourceProviderResolverFixed( 394 map[string]ResourceProviderFactory{ 395 "aws": testProviderFuncFixed(p), 396 }, 397 ), 398 UIInput: input, 399 }) 400 401 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 402 if errs := c.CheckSet([]string{"access_key"}); len(errs) > 0 { 403 return c, errs[0] 404 } 405 return c, nil 406 } 407 p.ConfigureFn = func(c *ResourceConfig) error { 408 return nil 409 } 410 411 if err := ctx.Input(InputModeStd); err != nil { 412 t.Fatalf("err: %s", err) 413 } 414 } 415 416 func TestContext2Input_varOnly(t *testing.T) { 417 input := new(MockUIInput) 418 m := testModule(t, "input-provider-vars") 419 p := testProvider("aws") 420 p.ApplyFn = testApplyFn 421 p.DiffFn = testDiffFn 422 ctx := testContext2(t, &ContextOpts{ 423 Module: m, 424 ProviderResolver: ResourceProviderResolverFixed( 425 map[string]ResourceProviderFactory{ 426 "aws": testProviderFuncFixed(p), 427 }, 428 ), 429 Variables: map[string]interface{}{ 430 "foo": "us-west-2", 431 }, 432 UIInput: input, 433 }) 434 435 input.InputReturnMap = map[string]string{ 436 "var.foo": "us-east-1", 437 } 438 439 var actual interface{} 440 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 441 c.Raw["foo"] = "bar" 442 return c, nil 443 } 444 p.ConfigureFn = func(c *ResourceConfig) error { 445 actual = c.Raw["foo"] 446 return nil 447 } 448 449 if err := ctx.Input(InputModeVar); err != nil { 450 t.Fatalf("err: %s", err) 451 } 452 453 if _, err := ctx.Plan(); err != nil { 454 t.Fatalf("err: %s", err) 455 } 456 457 state, err := ctx.Apply() 458 if err != nil { 459 t.Fatalf("err: %s", err) 460 } 461 462 if reflect.DeepEqual(actual, "bar") { 463 t.Fatalf("bad: %#v", actual) 464 } 465 466 actualStr := strings.TrimSpace(state.String()) 467 expectedStr := strings.TrimSpace(testTerraformInputVarOnlyStr) 468 if actualStr != expectedStr { 469 t.Fatalf("bad: \n%s", actualStr) 470 } 471 } 472 473 func TestContext2Input_varOnlyUnset(t *testing.T) { 474 input := new(MockUIInput) 475 m := testModule(t, "input-vars-unset") 476 p := testProvider("aws") 477 p.ApplyFn = testApplyFn 478 p.DiffFn = testDiffFn 479 ctx := testContext2(t, &ContextOpts{ 480 Module: m, 481 ProviderResolver: ResourceProviderResolverFixed( 482 map[string]ResourceProviderFactory{ 483 "aws": testProviderFuncFixed(p), 484 }, 485 ), 486 Variables: map[string]interface{}{ 487 "foo": "foovalue", 488 }, 489 UIInput: input, 490 }) 491 492 input.InputReturnMap = map[string]string{ 493 "var.foo": "nope", 494 "var.bar": "baz", 495 } 496 497 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 498 t.Fatalf("err: %s", err) 499 } 500 501 if _, err := ctx.Plan(); err != nil { 502 t.Fatalf("err: %s", err) 503 } 504 505 state, err := ctx.Apply() 506 if err != nil { 507 t.Fatalf("err: %s", err) 508 } 509 510 actualStr := strings.TrimSpace(state.String()) 511 expectedStr := strings.TrimSpace(testTerraformInputVarOnlyUnsetStr) 512 if actualStr != expectedStr { 513 t.Fatalf("bad: \n%s", actualStr) 514 } 515 } 516 517 func TestContext2Input_varWithDefault(t *testing.T) { 518 input := new(MockUIInput) 519 m := testModule(t, "input-var-default") 520 p := testProvider("aws") 521 p.ApplyFn = testApplyFn 522 p.DiffFn = testDiffFn 523 ctx := testContext2(t, &ContextOpts{ 524 Module: m, 525 ProviderResolver: ResourceProviderResolverFixed( 526 map[string]ResourceProviderFactory{ 527 "aws": testProviderFuncFixed(p), 528 }, 529 ), 530 Variables: map[string]interface{}{}, 531 UIInput: input, 532 }) 533 534 input.InputFn = func(opts *InputOpts) (string, error) { 535 t.Fatalf( 536 "Input should never be called because variable has a default: %#v", opts) 537 return "", nil 538 } 539 540 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 541 t.Fatalf("err: %s", err) 542 } 543 544 if _, err := ctx.Plan(); err != nil { 545 t.Fatalf("err: %s", err) 546 } 547 548 state, err := ctx.Apply() 549 if err != nil { 550 t.Fatalf("err: %s", err) 551 } 552 553 actualStr := strings.TrimSpace(state.String()) 554 expectedStr := strings.TrimSpace(` 555 aws_instance.foo: 556 ID = foo 557 foo = 123 558 type = aws_instance 559 `) 560 if actualStr != expectedStr { 561 t.Fatalf("expected: \n%s\ngot: \n%s\n", expectedStr, actualStr) 562 } 563 } 564 565 func TestContext2Input_varPartiallyComputed(t *testing.T) { 566 input := new(MockUIInput) 567 m := testModule(t, "input-var-partially-computed") 568 p := testProvider("aws") 569 p.ApplyFn = testApplyFn 570 p.DiffFn = testDiffFn 571 ctx := testContext2(t, &ContextOpts{ 572 Module: m, 573 ProviderResolver: ResourceProviderResolverFixed( 574 map[string]ResourceProviderFactory{ 575 "aws": testProviderFuncFixed(p), 576 }, 577 ), 578 Variables: map[string]interface{}{ 579 "foo": "foovalue", 580 }, 581 UIInput: input, 582 State: &State{ 583 Modules: []*ModuleState{ 584 &ModuleState{ 585 Path: rootModulePath, 586 Resources: map[string]*ResourceState{ 587 "aws_instance.foo": &ResourceState{ 588 Type: "aws_instance", 589 Primary: &InstanceState{ 590 ID: "i-abc123", 591 Attributes: map[string]string{ 592 "id": "i-abc123", 593 }, 594 }, 595 }, 596 }, 597 }, 598 &ModuleState{ 599 Path: append(rootModulePath, "child"), 600 Resources: map[string]*ResourceState{ 601 "aws_instance.mod": &ResourceState{ 602 Type: "aws_instance", 603 Primary: &InstanceState{ 604 ID: "i-bcd345", 605 Attributes: map[string]string{ 606 "id": "i-bcd345", 607 "value": "one,i-abc123", 608 }, 609 }, 610 }, 611 }, 612 }, 613 }, 614 }, 615 }) 616 617 if err := ctx.Input(InputModeStd); err != nil { 618 t.Fatalf("err: %s", err) 619 } 620 621 if _, err := ctx.Plan(); err != nil { 622 t.Fatalf("err: %s", err) 623 } 624 } 625 626 // Module variables weren't being interpolated during the Input walk. 627 // https://github.com/hashicorp/terraform/issues/5322 628 func TestContext2Input_interpolateVar(t *testing.T) { 629 input := new(MockUIInput) 630 631 m := testModule(t, "input-interpolate-var") 632 p := testProvider("null") 633 p.ApplyFn = testApplyFn 634 p.DiffFn = testDiffFn 635 636 ctx := testContext2(t, &ContextOpts{ 637 Module: m, 638 ProviderResolver: ResourceProviderResolverFixed( 639 map[string]ResourceProviderFactory{ 640 "template": testProviderFuncFixed(p), 641 }, 642 ), 643 UIInput: input, 644 }) 645 646 if err := ctx.Input(InputModeStd); err != nil { 647 t.Fatalf("err: %s", err) 648 } 649 } 650 651 func TestContext2Input_hcl(t *testing.T) { 652 input := new(MockUIInput) 653 m := testModule(t, "input-hcl") 654 p := testProvider("hcl") 655 p.ApplyFn = testApplyFn 656 p.DiffFn = testDiffFn 657 ctx := testContext2(t, &ContextOpts{ 658 Module: m, 659 ProviderResolver: ResourceProviderResolverFixed( 660 map[string]ResourceProviderFactory{ 661 "hcl": testProviderFuncFixed(p), 662 }, 663 ), 664 Variables: map[string]interface{}{}, 665 UIInput: input, 666 }) 667 668 input.InputReturnMap = map[string]string{ 669 "var.listed": `["a", "b"]`, 670 "var.mapped": `{x = "y", w = "z"}`, 671 } 672 673 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 674 t.Fatalf("err: %s", err) 675 } 676 677 if _, err := ctx.Plan(); err != nil { 678 t.Fatalf("err: %s", err) 679 } 680 681 state, err := ctx.Apply() 682 if err != nil { 683 t.Fatalf("err: %s", err) 684 } 685 686 actualStr := strings.TrimSpace(state.String()) 687 expectedStr := strings.TrimSpace(testTerraformInputHCL) 688 if actualStr != expectedStr { 689 t.Logf("expected: \n%s", expectedStr) 690 t.Fatalf("bad: \n%s", actualStr) 691 } 692 } 693 694 // adding a list interpolation in fails to interpolate the count variable 695 func TestContext2Input_submoduleTriggersInvalidCount(t *testing.T) { 696 input := new(MockUIInput) 697 m := testModule(t, "input-submodule-count") 698 p := testProvider("aws") 699 p.ApplyFn = testApplyFn 700 p.DiffFn = testDiffFn 701 ctx := testContext2(t, &ContextOpts{ 702 Module: m, 703 ProviderResolver: ResourceProviderResolverFixed( 704 map[string]ResourceProviderFactory{ 705 "aws": testProviderFuncFixed(p), 706 }, 707 ), 708 UIInput: input, 709 }) 710 711 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 712 return c, nil 713 } 714 p.ConfigureFn = func(c *ResourceConfig) error { 715 return nil 716 } 717 718 if err := ctx.Input(InputModeStd); err != nil { 719 t.Fatalf("err: %s", err) 720 } 721 }