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