github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/command/init_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "reflect" 9 "runtime" 10 "sort" 11 "strings" 12 "testing" 13 14 "github.com/hashicorp/terraform/helper/copy" 15 "github.com/hashicorp/terraform/plugin/discovery" 16 "github.com/mitchellh/cli" 17 ) 18 19 func TestInit_empty(t *testing.T) { 20 // Create a temporary working directory that is empty 21 td := tempDir(t) 22 os.MkdirAll(td, 0755) 23 defer os.RemoveAll(td) 24 defer testChdir(t, td)() 25 26 ui := new(cli.MockUi) 27 c := &InitCommand{ 28 Meta: Meta{ 29 testingOverrides: metaOverridesForProvider(testProvider()), 30 Ui: ui, 31 }, 32 } 33 34 args := []string{} 35 if code := c.Run(args); code != 0 { 36 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 37 } 38 } 39 40 func TestInit_multipleArgs(t *testing.T) { 41 ui := new(cli.MockUi) 42 c := &InitCommand{ 43 Meta: Meta{ 44 testingOverrides: metaOverridesForProvider(testProvider()), 45 Ui: ui, 46 }, 47 } 48 49 args := []string{ 50 "bad", 51 "bad", 52 } 53 if code := c.Run(args); code != 1 { 54 t.Fatalf("bad: \n%s", ui.OutputWriter.String()) 55 } 56 } 57 58 func TestInit_get(t *testing.T) { 59 // Create a temporary working directory that is empty 60 td := tempDir(t) 61 copy.CopyDir(testFixturePath("init-get"), td) 62 defer os.RemoveAll(td) 63 defer testChdir(t, td)() 64 65 ui := new(cli.MockUi) 66 c := &InitCommand{ 67 Meta: Meta{ 68 testingOverrides: metaOverridesForProvider(testProvider()), 69 Ui: ui, 70 }, 71 } 72 73 args := []string{} 74 if code := c.Run(args); code != 0 { 75 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 76 } 77 78 // Check output 79 output := ui.OutputWriter.String() 80 if !strings.Contains(output, "Get: file://") { 81 t.Fatalf("doesn't look like get: %s", output) 82 } 83 } 84 85 func TestInit_getUpgradeModules(t *testing.T) { 86 // Create a temporary working directory that is empty 87 td := tempDir(t) 88 os.MkdirAll(td, 0755) 89 // copy.CopyDir(testFixturePath("init-get"), td) 90 defer os.RemoveAll(td) 91 defer testChdir(t, td)() 92 93 ui := new(cli.MockUi) 94 c := &InitCommand{ 95 Meta: Meta{ 96 testingOverrides: metaOverridesForProvider(testProvider()), 97 Ui: ui, 98 }, 99 } 100 101 args := []string{ 102 "-get=true", 103 "-get-plugins=false", 104 "-upgrade", 105 testFixturePath("init-get"), 106 } 107 if code := c.Run(args); code != 0 { 108 t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) 109 } 110 111 // Check output 112 output := ui.OutputWriter.String() 113 if !strings.Contains(output, "(update)") { 114 t.Fatalf("doesn't look like get upgrade: %s", output) 115 } 116 } 117 118 func TestInit_backend(t *testing.T) { 119 // Create a temporary working directory that is empty 120 td := tempDir(t) 121 copy.CopyDir(testFixturePath("init-backend"), td) 122 defer os.RemoveAll(td) 123 defer testChdir(t, td)() 124 125 ui := new(cli.MockUi) 126 c := &InitCommand{ 127 Meta: Meta{ 128 testingOverrides: metaOverridesForProvider(testProvider()), 129 Ui: ui, 130 }, 131 } 132 133 args := []string{} 134 if code := c.Run(args); code != 0 { 135 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 136 } 137 138 if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil { 139 t.Fatalf("err: %s", err) 140 } 141 } 142 143 func TestInit_backendUnset(t *testing.T) { 144 // Create a temporary working directory that is empty 145 td := tempDir(t) 146 copy.CopyDir(testFixturePath("init-backend"), td) 147 defer os.RemoveAll(td) 148 defer testChdir(t, td)() 149 150 { 151 ui := new(cli.MockUi) 152 c := &InitCommand{ 153 Meta: Meta{ 154 testingOverrides: metaOverridesForProvider(testProvider()), 155 Ui: ui, 156 }, 157 } 158 159 // Init 160 args := []string{} 161 if code := c.Run(args); code != 0 { 162 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 163 } 164 165 if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil { 166 t.Fatalf("err: %s", err) 167 } 168 } 169 170 { 171 // Unset 172 if err := ioutil.WriteFile("main.tf", []byte(""), 0644); err != nil { 173 t.Fatalf("err: %s", err) 174 } 175 176 ui := new(cli.MockUi) 177 c := &InitCommand{ 178 Meta: Meta{ 179 testingOverrides: metaOverridesForProvider(testProvider()), 180 Ui: ui, 181 }, 182 } 183 184 args := []string{"-force-copy"} 185 if code := c.Run(args); code != 0 { 186 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 187 } 188 189 s := testStateRead(t, filepath.Join( 190 DefaultDataDir, DefaultStateFilename)) 191 if !s.Backend.Empty() { 192 t.Fatal("should not have backend config") 193 } 194 } 195 } 196 197 func TestInit_backendConfigFile(t *testing.T) { 198 // Create a temporary working directory that is empty 199 td := tempDir(t) 200 copy.CopyDir(testFixturePath("init-backend-config-file"), td) 201 defer os.RemoveAll(td) 202 defer testChdir(t, td)() 203 204 ui := new(cli.MockUi) 205 c := &InitCommand{ 206 Meta: Meta{ 207 testingOverrides: metaOverridesForProvider(testProvider()), 208 Ui: ui, 209 }, 210 } 211 212 args := []string{"-backend-config", "input.config"} 213 if code := c.Run(args); code != 0 { 214 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 215 } 216 217 // Read our saved backend config and verify we have our settings 218 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 219 if v := state.Backend.Config["path"]; v != "hello" { 220 t.Fatalf("bad: %#v", v) 221 } 222 } 223 224 func TestInit_backendConfigFileChange(t *testing.T) { 225 // Create a temporary working directory that is empty 226 td := tempDir(t) 227 copy.CopyDir(testFixturePath("init-backend-config-file-change"), td) 228 defer os.RemoveAll(td) 229 defer testChdir(t, td)() 230 231 // Ask input 232 defer testInputMap(t, map[string]string{ 233 "backend-migrate-to-new": "no", 234 })() 235 236 ui := new(cli.MockUi) 237 c := &InitCommand{ 238 Meta: Meta{ 239 testingOverrides: metaOverridesForProvider(testProvider()), 240 Ui: ui, 241 }, 242 } 243 244 args := []string{"-backend-config", "input.config"} 245 if code := c.Run(args); code != 0 { 246 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 247 } 248 249 // Read our saved backend config and verify we have our settings 250 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 251 if v := state.Backend.Config["path"]; v != "hello" { 252 t.Fatalf("bad: %#v", v) 253 } 254 } 255 256 func TestInit_backendConfigKV(t *testing.T) { 257 // Create a temporary working directory that is empty 258 td := tempDir(t) 259 copy.CopyDir(testFixturePath("init-backend-config-kv"), td) 260 defer os.RemoveAll(td) 261 defer testChdir(t, td)() 262 263 ui := new(cli.MockUi) 264 c := &InitCommand{ 265 Meta: Meta{ 266 testingOverrides: metaOverridesForProvider(testProvider()), 267 Ui: ui, 268 }, 269 } 270 271 args := []string{"-backend-config", "path=hello"} 272 if code := c.Run(args); code != 0 { 273 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 274 } 275 276 // Read our saved backend config and verify we have our settings 277 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 278 if v := state.Backend.Config["path"]; v != "hello" { 279 t.Fatalf("bad: %#v", v) 280 } 281 } 282 283 func TestInit_targetSubdir(t *testing.T) { 284 // Create a temporary working directory that is empty 285 td := tempDir(t) 286 os.MkdirAll(td, 0755) 287 defer os.RemoveAll(td) 288 defer testChdir(t, td)() 289 290 // copy the source into a subdir 291 copy.CopyDir(testFixturePath("init-backend"), filepath.Join(td, "source")) 292 293 ui := new(cli.MockUi) 294 c := &InitCommand{ 295 Meta: Meta{ 296 testingOverrides: metaOverridesForProvider(testProvider()), 297 Ui: ui, 298 }, 299 } 300 301 args := []string{ 302 "source", 303 } 304 if code := c.Run(args); code != 0 { 305 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 306 } 307 308 if _, err := os.Stat(filepath.Join(td, "source", DefaultDataDir, DefaultStateFilename)); err != nil { 309 t.Fatalf("err: %s", err) 310 } 311 312 // a data directory should not have been added to out working dir 313 if _, err := os.Stat(filepath.Join(td, DefaultDataDir)); !os.IsNotExist(err) { 314 t.Fatalf("err: %s", err) 315 } 316 } 317 318 func TestInit_backendReinitWithExtra(t *testing.T) { 319 td := tempDir(t) 320 copy.CopyDir(testFixturePath("init-backend-empty"), td) 321 defer os.RemoveAll(td) 322 defer testChdir(t, td)() 323 324 m := testMetaBackend(t, nil) 325 opts := &BackendOpts{ 326 ConfigExtra: map[string]interface{}{"path": "hello"}, 327 Init: true, 328 } 329 330 b, err := m.backendConfig(opts) 331 if err != nil { 332 t.Fatal(err) 333 } 334 335 ui := new(cli.MockUi) 336 c := &InitCommand{ 337 Meta: Meta{ 338 testingOverrides: metaOverridesForProvider(testProvider()), 339 Ui: ui, 340 }, 341 } 342 343 args := []string{"-backend-config", "path=hello"} 344 if code := c.Run(args); code != 0 { 345 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 346 } 347 348 // Read our saved backend config and verify we have our settings 349 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 350 if v := state.Backend.Config["path"]; v != "hello" { 351 t.Fatalf("bad: %#v", v) 352 } 353 354 if state.Backend.Hash != b.Hash { 355 t.Fatal("mismatched state and config backend hashes") 356 } 357 358 if state.Backend.Rehash() != b.Rehash() { 359 t.Fatal("mismatched state and config re-hashes") 360 } 361 362 // init again and make sure nothing changes 363 if code := c.Run(args); code != 0 { 364 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 365 } 366 state = testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 367 if v := state.Backend.Config["path"]; v != "hello" { 368 t.Fatalf("bad: %#v", v) 369 } 370 371 if state.Backend.Hash != b.Hash { 372 t.Fatal("mismatched state and config backend hashes") 373 } 374 } 375 376 // move option from config to -backend-config args 377 func TestInit_backendReinitConfigToExtra(t *testing.T) { 378 td := tempDir(t) 379 copy.CopyDir(testFixturePath("init-backend"), td) 380 defer os.RemoveAll(td) 381 defer testChdir(t, td)() 382 383 ui := new(cli.MockUi) 384 c := &InitCommand{ 385 Meta: Meta{ 386 testingOverrides: metaOverridesForProvider(testProvider()), 387 Ui: ui, 388 }, 389 } 390 391 if code := c.Run([]string{"-input=false"}); code != 0 { 392 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 393 } 394 395 // Read our saved backend config and verify we have our settings 396 state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 397 if v := state.Backend.Config["path"]; v != "foo" { 398 t.Fatalf("bad: %#v", v) 399 } 400 401 backendHash := state.Backend.Hash 402 403 // init again but remove the path option from the config 404 cfg := "terraform {\n backend \"local\" {}\n}\n" 405 if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil { 406 t.Fatal(err) 407 } 408 409 args := []string{"-input=false", "-backend-config=path=foo"} 410 if code := c.Run(args); code != 0 { 411 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 412 } 413 state = testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename)) 414 415 if state.Backend.Hash == backendHash { 416 t.Fatal("state.Backend.Hash was not updated") 417 } 418 } 419 420 // make sure inputFalse stops execution on migrate 421 func TestInit_inputFalse(t *testing.T) { 422 td := tempDir(t) 423 copy.CopyDir(testFixturePath("init-backend"), td) 424 defer os.RemoveAll(td) 425 defer testChdir(t, td)() 426 427 ui := new(cli.MockUi) 428 c := &InitCommand{ 429 Meta: Meta{ 430 testingOverrides: metaOverridesForProvider(testProvider()), 431 Ui: ui, 432 }, 433 } 434 435 args := []string{"-input=false", "-backend-config=path=foo"} 436 if code := c.Run([]string{"-input=false"}); code != 0 { 437 t.Fatalf("bad: \n%s", ui.ErrorWriter) 438 } 439 440 args = []string{"-input=false", "-backend-config=path=bar"} 441 if code := c.Run(args); code == 0 { 442 t.Fatal("init should have failed", ui.OutputWriter) 443 } 444 } 445 446 func TestInit_getProvider(t *testing.T) { 447 // Create a temporary working directory that is empty 448 td := tempDir(t) 449 copy.CopyDir(testFixturePath("init-get-providers"), td) 450 defer os.RemoveAll(td) 451 defer testChdir(t, td)() 452 453 ui := new(cli.MockUi) 454 m := Meta{ 455 testingOverrides: metaOverridesForProvider(testProvider()), 456 Ui: ui, 457 } 458 459 installer := &mockProviderInstaller{ 460 Providers: map[string][]string{ 461 // looking for an exact version 462 "exact": []string{"1.2.3"}, 463 // config requires >= 2.3.3 464 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 465 // config specifies 466 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 467 }, 468 469 Dir: m.pluginDir(), 470 } 471 472 c := &InitCommand{ 473 Meta: m, 474 providerInstaller: installer, 475 } 476 477 args := []string{} 478 if code := c.Run(args); code != 0 { 479 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 480 } 481 482 // check that we got the providers for our config 483 exactPath := filepath.Join(c.pluginDir(), installer.FileName("exact", "1.2.3")) 484 if _, err := os.Stat(exactPath); os.IsNotExist(err) { 485 t.Fatal("provider 'exact' not downloaded") 486 } 487 greaterThanPath := filepath.Join(c.pluginDir(), installer.FileName("greater_than", "2.3.4")) 488 if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) { 489 t.Fatal("provider 'greater_than' not downloaded") 490 } 491 betweenPath := filepath.Join(c.pluginDir(), installer.FileName("between", "2.3.4")) 492 if _, err := os.Stat(betweenPath); os.IsNotExist(err) { 493 t.Fatal("provider 'between' not downloaded") 494 } 495 } 496 497 func TestInit_getUpgradePlugins(t *testing.T) { 498 // Create a temporary working directory that is empty 499 td := tempDir(t) 500 copy.CopyDir(testFixturePath("init-get-providers"), td) 501 defer os.RemoveAll(td) 502 defer testChdir(t, td)() 503 504 ui := new(cli.MockUi) 505 m := Meta{ 506 testingOverrides: metaOverridesForProvider(testProvider()), 507 Ui: ui, 508 } 509 510 installer := &mockProviderInstaller{ 511 Providers: map[string][]string{ 512 // looking for an exact version 513 "exact": []string{"1.2.3"}, 514 // config requires >= 2.3.3 515 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 516 // config specifies 517 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 518 }, 519 520 Dir: m.pluginDir(), 521 } 522 523 err := os.MkdirAll(m.pluginDir(), os.ModePerm) 524 if err != nil { 525 t.Fatal(err) 526 } 527 exactUnwanted := filepath.Join(m.pluginDir(), installer.FileName("exact", "0.0.1")) 528 err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm) 529 if err != nil { 530 t.Fatal(err) 531 } 532 greaterThanUnwanted := filepath.Join(m.pluginDir(), installer.FileName("greater_than", "2.3.3")) 533 err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm) 534 if err != nil { 535 t.Fatal(err) 536 } 537 betweenOverride := installer.FileName("between", "2.3.4") // intentionally directly in cwd, and should override auto-install 538 err = ioutil.WriteFile(betweenOverride, []byte{}, os.ModePerm) 539 if err != nil { 540 t.Fatal(err) 541 } 542 543 c := &InitCommand{ 544 Meta: m, 545 providerInstaller: installer, 546 } 547 548 args := []string{ 549 "-upgrade=true", 550 } 551 if code := c.Run(args); code != 0 { 552 t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) 553 } 554 555 files, err := ioutil.ReadDir(m.pluginDir()) 556 if err != nil { 557 t.Fatal(err) 558 } 559 560 if !installer.PurgeUnusedCalled { 561 t.Errorf("init -upgrade didn't purge providers, but should have") 562 } 563 564 gotFilenames := make([]string, len(files)) 565 for i, info := range files { 566 gotFilenames[i] = info.Name() 567 } 568 sort.Strings(gotFilenames) 569 570 wantFilenames := []string{ 571 "lock.json", 572 573 // no "between" because the file in cwd overrides it 574 575 // The mock PurgeUnused doesn't actually purge anything, so the dir 576 // includes both our old and new versions. 577 "terraform-provider-exact_v0.0.1_x4", 578 "terraform-provider-exact_v1.2.3_x4", 579 "terraform-provider-greater_than_v2.3.3_x4", 580 "terraform-provider-greater_than_v2.3.4_x4", 581 } 582 583 if !reflect.DeepEqual(gotFilenames, wantFilenames) { 584 t.Errorf("wrong directory contents after upgrade\ngot: %#v\nwant: %#v", gotFilenames, wantFilenames) 585 } 586 587 } 588 589 func TestInit_getProviderMissing(t *testing.T) { 590 // Create a temporary working directory that is empty 591 td := tempDir(t) 592 copy.CopyDir(testFixturePath("init-get-providers"), td) 593 defer os.RemoveAll(td) 594 defer testChdir(t, td)() 595 596 ui := new(cli.MockUi) 597 m := Meta{ 598 testingOverrides: metaOverridesForProvider(testProvider()), 599 Ui: ui, 600 } 601 602 installer := &mockProviderInstaller{ 603 Providers: map[string][]string{ 604 // looking for exact version 1.2.3 605 "exact": []string{"1.2.4"}, 606 // config requires >= 2.3.3 607 "greater_than": []string{"2.3.4", "2.3.3", "2.3.0"}, 608 // config specifies 609 "between": []string{"3.4.5", "2.3.4", "1.2.3"}, 610 }, 611 612 Dir: m.pluginDir(), 613 } 614 615 c := &InitCommand{ 616 Meta: m, 617 providerInstaller: installer, 618 } 619 620 args := []string{} 621 if code := c.Run(args); code == 0 { 622 t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String()) 623 } 624 625 if !strings.Contains(ui.ErrorWriter.String(), "no suitable version for provider") { 626 t.Fatalf("unexpected error output: %s", ui.ErrorWriter) 627 } 628 } 629 630 func TestInit_getProviderHaveLegacyVersion(t *testing.T) { 631 // Create a temporary working directory that is empty 632 td := tempDir(t) 633 copy.CopyDir(testFixturePath("init-providers-lock"), td) 634 defer os.RemoveAll(td) 635 defer testChdir(t, td)() 636 637 if err := ioutil.WriteFile("terraform-provider-test", []byte("provider bin"), 0755); err != nil { 638 t.Fatal(err) 639 } 640 641 // provider test has a version constraint in the config, which should 642 // trigger the getProvider error below. 643 ui := new(cli.MockUi) 644 c := &InitCommand{ 645 Meta: Meta{ 646 testingOverrides: metaOverridesForProvider(testProvider()), 647 Ui: ui, 648 }, 649 providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, error) { 650 return discovery.PluginMeta{}, fmt.Errorf("EXPECTED PROVIDER ERROR %s", provider) 651 }), 652 } 653 654 args := []string{} 655 if code := c.Run(args); code == 0 { 656 t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String()) 657 } 658 659 if !strings.Contains(ui.ErrorWriter.String(), "EXPECTED PROVIDER ERROR test") { 660 t.Fatalf("unexpected error output: %s", ui.ErrorWriter) 661 } 662 } 663 664 func TestInit_providerLockFile(t *testing.T) { 665 // Create a temporary working directory that is empty 666 td := tempDir(t) 667 copy.CopyDir(testFixturePath("init-provider-lock-file"), td) 668 defer os.RemoveAll(td) 669 defer testChdir(t, td)() 670 671 ui := new(cli.MockUi) 672 m := Meta{ 673 testingOverrides: metaOverridesForProvider(testProvider()), 674 Ui: ui, 675 } 676 677 installer := &mockProviderInstaller{ 678 Providers: map[string][]string{ 679 "test": []string{"1.2.3"}, 680 }, 681 682 Dir: m.pluginDir(), 683 } 684 685 c := &InitCommand{ 686 Meta: m, 687 providerInstaller: installer, 688 } 689 690 args := []string{} 691 if code := c.Run(args); code != 0 { 692 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 693 } 694 695 providersLockFile := fmt.Sprintf( 696 ".terraform/plugins/%s_%s/lock.json", 697 runtime.GOOS, runtime.GOARCH, 698 ) 699 buf, err := ioutil.ReadFile(providersLockFile) 700 if err != nil { 701 t.Fatalf("failed to read providers lock file %s: %s", providersLockFile, err) 702 } 703 // The hash in here is for the empty files that mockGetProvider produces 704 wantLockFile := strings.TrimSpace(` 705 { 706 "test": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 707 } 708 `) 709 if string(buf) != wantLockFile { 710 t.Errorf("wrong provider lock file contents\ngot: %s\nwant: %s", buf, wantLockFile) 711 } 712 }