github.com/richardmarshall/terraform@v0.9.5-0.20170429023105-15704cc6ee35/command/push_test.go (about) 1 package command 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "compress/gzip" 7 "io" 8 "os" 9 "path/filepath" 10 "reflect" 11 "sort" 12 "strings" 13 "testing" 14 15 atlas "github.com/hashicorp/atlas-go/v1" 16 "github.com/hashicorp/terraform/helper/copy" 17 "github.com/hashicorp/terraform/terraform" 18 "github.com/mitchellh/cli" 19 ) 20 21 func TestPush_good(t *testing.T) { 22 tmp, cwd := testCwd(t) 23 defer testFixCwd(t, tmp, cwd) 24 25 // Create remote state file, this should be pulled 26 conf, srv := testRemoteState(t, testState(), 200) 27 defer srv.Close() 28 29 // Persist local remote state 30 s := terraform.NewState() 31 s.Serial = 5 32 s.Remote = conf 33 testStateFileRemote(t, s) 34 35 // Path where the archive will be "uploaded" to 36 archivePath := testTempFile(t) 37 defer os.Remove(archivePath) 38 39 client := &mockPushClient{File: archivePath} 40 ui := new(cli.MockUi) 41 c := &PushCommand{ 42 Meta: Meta{ 43 ContextOpts: testCtxConfig(testProvider()), 44 Ui: ui, 45 }, 46 47 client: client, 48 } 49 50 args := []string{ 51 "-vcs=false", 52 testFixturePath("push"), 53 } 54 if code := c.Run(args); code != 0 { 55 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 56 } 57 58 actual := testArchiveStr(t, archivePath) 59 expected := []string{ 60 ".terraform/", 61 ".terraform/terraform.tfstate", 62 "main.tf", 63 } 64 if !reflect.DeepEqual(actual, expected) { 65 t.Fatalf("bad: %#v", actual) 66 } 67 68 variables := make(map[string]interface{}) 69 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 70 t.Fatalf("bad: %#v", client.UpsertOptions) 71 } 72 73 if client.UpsertOptions.Name != "foo" { 74 t.Fatalf("bad: %#v", client.UpsertOptions) 75 } 76 } 77 78 func TestPush_goodBackendInit(t *testing.T) { 79 // Create a temporary working directory that is empty 80 td := tempDir(t) 81 copy.CopyDir(testFixturePath("push-backend-new"), td) 82 defer os.RemoveAll(td) 83 defer testChdir(t, td)() 84 85 // init backend 86 ui := new(cli.MockUi) 87 ci := &InitCommand{ 88 Meta: Meta{ 89 Ui: ui, 90 }, 91 } 92 if code := ci.Run(nil); code != 0 { 93 t.Fatalf("bad: %d\n%s", code, ui.ErrorWriter) 94 } 95 96 // Path where the archive will be "uploaded" to 97 archivePath := testTempFile(t) 98 defer os.Remove(archivePath) 99 100 client := &mockPushClient{File: archivePath} 101 ui = new(cli.MockUi) 102 c := &PushCommand{ 103 Meta: Meta{ 104 ContextOpts: testCtxConfig(testProvider()), 105 Ui: ui, 106 }, 107 108 client: client, 109 } 110 111 args := []string{ 112 "-vcs=false", 113 td, 114 } 115 if code := c.Run(args); code != 0 { 116 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 117 } 118 119 actual := testArchiveStr(t, archivePath) 120 expected := []string{ 121 // Expected weird behavior, doesn't affect unpackaging 122 ".terraform/", 123 ".terraform/", 124 ".terraform/terraform.tfstate", 125 ".terraform/terraform.tfstate", 126 "main.tf", 127 } 128 if !reflect.DeepEqual(actual, expected) { 129 t.Fatalf("bad: %#v", actual) 130 } 131 132 variables := make(map[string]interface{}) 133 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 134 t.Fatalf("bad: %#v", client.UpsertOptions) 135 } 136 137 if client.UpsertOptions.Name != "hello" { 138 t.Fatalf("bad: %#v", client.UpsertOptions) 139 } 140 } 141 142 func TestPush_noUploadModules(t *testing.T) { 143 // Path where the archive will be "uploaded" to 144 archivePath := testTempFile(t) 145 defer os.Remove(archivePath) 146 147 client := &mockPushClient{File: archivePath} 148 ui := new(cli.MockUi) 149 c := &PushCommand{ 150 Meta: Meta{ 151 ContextOpts: testCtxConfig(testProvider()), 152 Ui: ui, 153 }, 154 155 client: client, 156 } 157 158 // Path of the test. We have to do some renaming to avoid our own 159 // VCS getting in the way. 160 path := testFixturePath("push-no-upload") 161 defer os.RemoveAll(filepath.Join(path, ".terraform")) 162 163 // Move into that directory 164 defer testChdir(t, path)() 165 166 // Do a "terraform get" 167 { 168 ui := new(cli.MockUi) 169 c := &GetCommand{ 170 Meta: Meta{ 171 ContextOpts: testCtxConfig(testProvider()), 172 Ui: ui, 173 }, 174 } 175 176 if code := c.Run([]string{}); code != 0 { 177 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 178 } 179 } 180 181 // Create remote state file, this should be pulled 182 conf, srv := testRemoteState(t, testState(), 200) 183 defer srv.Close() 184 185 // Persist local remote state 186 s := terraform.NewState() 187 s.Serial = 5 188 s.Remote = conf 189 defer os.Remove(testStateFileRemote(t, s)) 190 191 args := []string{ 192 "-vcs=false", 193 "-name=mitchellh/tf-test", 194 "-upload-modules=false", 195 path, 196 } 197 if code := c.Run(args); code != 0 { 198 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 199 } 200 201 // NOTE: The duplicates below are not ideal but are how things work 202 // currently due to how we manually add the files to the archive. This 203 // is definitely a "bug" we can fix in the future. 204 actual := testArchiveStr(t, archivePath) 205 expected := []string{ 206 ".terraform/", 207 ".terraform/", 208 ".terraform/terraform.tfstate", 209 ".terraform/terraform.tfstate", 210 "child/", 211 "child/main.tf", 212 "main.tf", 213 } 214 if !reflect.DeepEqual(actual, expected) { 215 t.Fatalf("bad: %#v", actual) 216 } 217 } 218 219 func TestPush_input(t *testing.T) { 220 tmp, cwd := testCwd(t) 221 defer testFixCwd(t, tmp, cwd) 222 223 // Create remote state file, this should be pulled 224 conf, srv := testRemoteState(t, testState(), 200) 225 defer srv.Close() 226 227 // Persist local remote state 228 s := terraform.NewState() 229 s.Serial = 5 230 s.Remote = conf 231 testStateFileRemote(t, s) 232 233 // Path where the archive will be "uploaded" to 234 archivePath := testTempFile(t) 235 defer os.Remove(archivePath) 236 237 client := &mockPushClient{File: archivePath} 238 ui := new(cli.MockUi) 239 c := &PushCommand{ 240 Meta: Meta{ 241 ContextOpts: testCtxConfig(testProvider()), 242 Ui: ui, 243 }, 244 245 client: client, 246 } 247 248 // Disable test mode so input would be asked and setup the 249 // input reader/writers. 250 test = false 251 defer func() { test = true }() 252 defaultInputReader = bytes.NewBufferString("foo\n") 253 defaultInputWriter = new(bytes.Buffer) 254 255 args := []string{ 256 "-vcs=false", 257 testFixturePath("push-input"), 258 } 259 if code := c.Run(args); code != 0 { 260 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 261 } 262 263 variables := map[string]interface{}{ 264 "foo": "foo", 265 } 266 267 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 268 t.Fatalf("bad: %#v", client.UpsertOptions.Variables) 269 } 270 } 271 272 // We want a variable from atlas to fill a missing variable locally 273 func TestPush_inputPartial(t *testing.T) { 274 tmp, cwd := testCwd(t) 275 defer testFixCwd(t, tmp, cwd) 276 277 // Create remote state file, this should be pulled 278 conf, srv := testRemoteState(t, testState(), 200) 279 defer srv.Close() 280 281 // Persist local remote state 282 s := terraform.NewState() 283 s.Serial = 5 284 s.Remote = conf 285 testStateFileRemote(t, s) 286 287 // Path where the archive will be "uploaded" to 288 archivePath := testTempFile(t) 289 defer os.Remove(archivePath) 290 291 client := &mockPushClient{ 292 File: archivePath, 293 GetResult: map[string]atlas.TFVar{ 294 "foo": atlas.TFVar{Key: "foo", Value: "bar"}, 295 }, 296 } 297 ui := new(cli.MockUi) 298 c := &PushCommand{ 299 Meta: Meta{ 300 ContextOpts: testCtxConfig(testProvider()), 301 Ui: ui, 302 }, 303 304 client: client, 305 } 306 307 // Disable test mode so input would be asked and setup the 308 // input reader/writers. 309 test = false 310 defer func() { test = true }() 311 defaultInputReader = bytes.NewBufferString("foo\n") 312 defaultInputWriter = new(bytes.Buffer) 313 314 args := []string{ 315 "-vcs=false", 316 testFixturePath("push-input-partial"), 317 } 318 if code := c.Run(args); code != 0 { 319 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 320 } 321 322 expectedTFVars := []atlas.TFVar{ 323 {Key: "bar", Value: "foo"}, 324 {Key: "foo", Value: "bar"}, 325 } 326 if !reflect.DeepEqual(client.UpsertOptions.TFVars, expectedTFVars) { 327 t.Logf("expected: %#v", expectedTFVars) 328 t.Fatalf("got: %#v", client.UpsertOptions.TFVars) 329 } 330 } 331 332 // This tests that the push command will override Atlas variables 333 // if requested. 334 func TestPush_localOverride(t *testing.T) { 335 // Disable test mode so input would be asked and setup the 336 // input reader/writers. 337 test = false 338 defer func() { test = true }() 339 defaultInputReader = bytes.NewBufferString("nope\n") 340 defaultInputWriter = new(bytes.Buffer) 341 342 tmp, cwd := testCwd(t) 343 defer testFixCwd(t, tmp, cwd) 344 345 // Create remote state file, this should be pulled 346 conf, srv := testRemoteState(t, testState(), 200) 347 defer srv.Close() 348 349 // Persist local remote state 350 s := terraform.NewState() 351 s.Serial = 5 352 s.Remote = conf 353 testStateFileRemote(t, s) 354 355 // Path where the archive will be "uploaded" to 356 archivePath := testTempFile(t) 357 defer os.Remove(archivePath) 358 359 client := &mockPushClient{File: archivePath} 360 // Provided vars should override existing ones 361 client.GetResult = map[string]atlas.TFVar{ 362 "foo": atlas.TFVar{ 363 Key: "foo", 364 Value: "old", 365 }, 366 } 367 ui := new(cli.MockUi) 368 c := &PushCommand{ 369 Meta: Meta{ 370 ContextOpts: testCtxConfig(testProvider()), 371 Ui: ui, 372 }, 373 374 client: client, 375 } 376 377 path := testFixturePath("push-tfvars") 378 args := []string{ 379 "-var-file", path + "/terraform.tfvars", 380 "-vcs=false", 381 "-overwrite=foo", 382 path, 383 } 384 if code := c.Run(args); code != 0 { 385 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 386 } 387 388 actual := testArchiveStr(t, archivePath) 389 expected := []string{ 390 ".terraform/", 391 ".terraform/terraform.tfstate", 392 "main.tf", 393 "terraform.tfvars", 394 } 395 if !reflect.DeepEqual(actual, expected) { 396 t.Fatalf("bad: %#v", actual) 397 } 398 399 if client.UpsertOptions.Name != "foo" { 400 t.Fatalf("bad: %#v", client.UpsertOptions) 401 } 402 403 expectedTFVars := pushTFVars() 404 405 if !reflect.DeepEqual(client.UpsertOptions.TFVars, expectedTFVars) { 406 t.Logf("expected: %#v", expectedTFVars) 407 t.Fatalf("got: %#v", client.UpsertOptions.TFVars) 408 } 409 } 410 411 // This tests that the push command will override Atlas variables 412 // even if we don't have it defined locally 413 func TestPush_remoteOverride(t *testing.T) { 414 // Disable test mode so input would be asked and setup the 415 // input reader/writers. 416 test = false 417 defer func() { test = true }() 418 defaultInputReader = bytes.NewBufferString("nope\n") 419 defaultInputWriter = new(bytes.Buffer) 420 421 tmp, cwd := testCwd(t) 422 defer testFixCwd(t, tmp, cwd) 423 424 // Create remote state file, this should be pulled 425 conf, srv := testRemoteState(t, testState(), 200) 426 defer srv.Close() 427 428 // Persist local remote state 429 s := terraform.NewState() 430 s.Serial = 5 431 s.Remote = conf 432 testStateFileRemote(t, s) 433 434 // Path where the archive will be "uploaded" to 435 archivePath := testTempFile(t) 436 defer os.Remove(archivePath) 437 438 client := &mockPushClient{File: archivePath} 439 // Provided vars should override existing ones 440 client.GetResult = map[string]atlas.TFVar{ 441 "remote": atlas.TFVar{ 442 Key: "remote", 443 Value: "old", 444 }, 445 } 446 ui := new(cli.MockUi) 447 c := &PushCommand{ 448 Meta: Meta{ 449 ContextOpts: testCtxConfig(testProvider()), 450 Ui: ui, 451 }, 452 453 client: client, 454 } 455 456 path := testFixturePath("push-tfvars") 457 args := []string{ 458 "-var-file", path + "/terraform.tfvars", 459 "-vcs=false", 460 "-overwrite=remote", 461 "-var", 462 "remote=new", 463 path, 464 } 465 466 if code := c.Run(args); code != 0 { 467 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 468 } 469 470 actual := testArchiveStr(t, archivePath) 471 expected := []string{ 472 ".terraform/", 473 ".terraform/terraform.tfstate", 474 "main.tf", 475 "terraform.tfvars", 476 } 477 if !reflect.DeepEqual(actual, expected) { 478 t.Fatalf("bad: %#v", actual) 479 } 480 481 if client.UpsertOptions.Name != "foo" { 482 t.Fatalf("bad: %#v", client.UpsertOptions) 483 } 484 485 found := false 486 // find the "remote" var and make sure we're going to set it 487 for _, tfVar := range client.UpsertOptions.TFVars { 488 if tfVar.Key == "remote" { 489 found = true 490 if tfVar.Value != "new" { 491 t.Log("'remote' variable should be set to 'new'") 492 t.Fatalf("sending instead: %#v", tfVar) 493 } 494 } 495 } 496 497 if !found { 498 t.Fatal("'remote' variable not being sent to atlas") 499 } 500 } 501 502 // This tests that the push command prefers Atlas variables over 503 // local ones. 504 func TestPush_preferAtlas(t *testing.T) { 505 // Disable test mode so input would be asked and setup the 506 // input reader/writers. 507 test = false 508 defer func() { test = true }() 509 defaultInputReader = bytes.NewBufferString("nope\n") 510 defaultInputWriter = new(bytes.Buffer) 511 512 tmp, cwd := testCwd(t) 513 defer testFixCwd(t, tmp, cwd) 514 515 // Create remote state file, this should be pulled 516 conf, srv := testRemoteState(t, testState(), 200) 517 defer srv.Close() 518 519 // Persist local remote state 520 s := terraform.NewState() 521 s.Serial = 5 522 s.Remote = conf 523 testStateFileRemote(t, s) 524 525 // Path where the archive will be "uploaded" to 526 archivePath := testTempFile(t) 527 defer os.Remove(archivePath) 528 529 client := &mockPushClient{File: archivePath} 530 // Provided vars should override existing ones 531 client.GetResult = map[string]atlas.TFVar{ 532 "foo": atlas.TFVar{ 533 Key: "foo", 534 Value: "old", 535 }, 536 } 537 ui := new(cli.MockUi) 538 c := &PushCommand{ 539 Meta: Meta{ 540 ContextOpts: testCtxConfig(testProvider()), 541 Ui: ui, 542 }, 543 544 client: client, 545 } 546 547 path := testFixturePath("push-tfvars") 548 args := []string{ 549 "-var-file", path + "/terraform.tfvars", 550 "-vcs=false", 551 path, 552 } 553 if code := c.Run(args); code != 0 { 554 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 555 } 556 557 actual := testArchiveStr(t, archivePath) 558 expected := []string{ 559 ".terraform/", 560 ".terraform/terraform.tfstate", 561 "main.tf", 562 "terraform.tfvars", 563 } 564 if !reflect.DeepEqual(actual, expected) { 565 t.Fatalf("bad: %#v", actual) 566 } 567 568 if client.UpsertOptions.Name != "foo" { 569 t.Fatalf("bad: %#v", client.UpsertOptions) 570 } 571 572 // change the expected response to match our change 573 expectedTFVars := pushTFVars() 574 for i, v := range expectedTFVars { 575 if v.Key == "foo" { 576 expectedTFVars[i] = atlas.TFVar{Key: "foo", Value: "old"} 577 } 578 } 579 580 if !reflect.DeepEqual(expectedTFVars, client.UpsertOptions.TFVars) { 581 t.Logf("expected: %#v", expectedTFVars) 582 t.Fatalf("got: %#v", client.UpsertOptions.TFVars) 583 } 584 } 585 586 // This tests that the push command will send the variables in tfvars 587 func TestPush_tfvars(t *testing.T) { 588 // Disable test mode so input would be asked and setup the 589 // input reader/writers. 590 test = false 591 defer func() { test = true }() 592 defaultInputReader = bytes.NewBufferString("nope\n") 593 defaultInputWriter = new(bytes.Buffer) 594 595 tmp, cwd := testCwd(t) 596 defer testFixCwd(t, tmp, cwd) 597 598 // Create remote state file, this should be pulled 599 conf, srv := testRemoteState(t, testState(), 200) 600 defer srv.Close() 601 602 // Persist local remote state 603 s := terraform.NewState() 604 s.Serial = 5 605 s.Remote = conf 606 testStateFileRemote(t, s) 607 608 // Path where the archive will be "uploaded" to 609 archivePath := testTempFile(t) 610 defer os.Remove(archivePath) 611 612 client := &mockPushClient{File: archivePath} 613 ui := new(cli.MockUi) 614 c := &PushCommand{ 615 Meta: Meta{ 616 ContextOpts: testCtxConfig(testProvider()), 617 Ui: ui, 618 }, 619 620 client: client, 621 } 622 623 path := testFixturePath("push-tfvars") 624 args := []string{ 625 "-var-file", path + "/terraform.tfvars", 626 "-vcs=false", 627 "-var", 628 "bar=[1,2]", 629 path, 630 } 631 if code := c.Run(args); code != 0 { 632 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 633 } 634 635 actual := testArchiveStr(t, archivePath) 636 expected := []string{ 637 ".terraform/", 638 ".terraform/terraform.tfstate", 639 "main.tf", 640 "terraform.tfvars", 641 } 642 if !reflect.DeepEqual(actual, expected) { 643 t.Fatalf("bad: %#v", actual) 644 } 645 646 if client.UpsertOptions.Name != "foo" { 647 t.Fatalf("bad: %#v", client.UpsertOptions) 648 } 649 650 //now check TFVars 651 tfvars := pushTFVars() 652 // update bar to match cli value 653 for i, v := range tfvars { 654 if v.Key == "bar" { 655 tfvars[i].Value = "[1, 2]" 656 tfvars[i].IsHCL = true 657 } 658 } 659 660 for i, expected := range tfvars { 661 got := client.UpsertOptions.TFVars[i] 662 if got != expected { 663 t.Logf("%2d expected: %#v", i, expected) 664 t.Fatalf(" got: %#v", got) 665 } 666 } 667 } 668 669 func TestPush_name(t *testing.T) { 670 tmp, cwd := testCwd(t) 671 defer testFixCwd(t, tmp, cwd) 672 673 // Create remote state file, this should be pulled 674 conf, srv := testRemoteState(t, testState(), 200) 675 defer srv.Close() 676 677 // Persist local remote state 678 s := terraform.NewState() 679 s.Serial = 5 680 s.Remote = conf 681 testStateFileRemote(t, s) 682 683 // Path where the archive will be "uploaded" to 684 archivePath := testTempFile(t) 685 defer os.Remove(archivePath) 686 687 client := &mockPushClient{File: archivePath} 688 ui := new(cli.MockUi) 689 c := &PushCommand{ 690 Meta: Meta{ 691 ContextOpts: testCtxConfig(testProvider()), 692 Ui: ui, 693 }, 694 695 client: client, 696 } 697 698 args := []string{ 699 "-name", "bar", 700 "-vcs=false", 701 testFixturePath("push"), 702 } 703 if code := c.Run(args); code != 0 { 704 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 705 } 706 707 if client.UpsertOptions.Name != "bar" { 708 t.Fatalf("bad: %#v", client.UpsertOptions) 709 } 710 } 711 712 func TestPush_noState(t *testing.T) { 713 tmp, cwd := testCwd(t) 714 defer testFixCwd(t, tmp, cwd) 715 716 ui := new(cli.MockUi) 717 c := &PushCommand{ 718 Meta: Meta{ 719 ContextOpts: testCtxConfig(testProvider()), 720 Ui: ui, 721 }, 722 } 723 724 args := []string{} 725 if code := c.Run(args); code != 1 { 726 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 727 } 728 } 729 730 func TestPush_noRemoteState(t *testing.T) { 731 // Create a temporary working directory that is empty 732 td := tempDir(t) 733 copy.CopyDir(testFixturePath("push-no-remote"), td) 734 defer os.RemoveAll(td) 735 defer testChdir(t, td)() 736 737 state := &terraform.State{ 738 Modules: []*terraform.ModuleState{ 739 &terraform.ModuleState{ 740 Path: []string{"root"}, 741 Resources: map[string]*terraform.ResourceState{ 742 "test_instance.foo": &terraform.ResourceState{ 743 Type: "test_instance", 744 Primary: &terraform.InstanceState{ 745 ID: "bar", 746 }, 747 }, 748 }, 749 }, 750 }, 751 } 752 statePath := testStateFile(t, state) 753 754 // Path where the archive will be "uploaded" to 755 archivePath := testTempFile(t) 756 defer os.Remove(archivePath) 757 758 client := &mockPushClient{File: archivePath} 759 ui := new(cli.MockUi) 760 c := &PushCommand{ 761 Meta: Meta{ 762 Ui: ui, 763 }, 764 client: client, 765 } 766 767 args := []string{ 768 "-vcs=false", 769 "-state", statePath, 770 td, 771 } 772 if code := c.Run(args); code != 1 { 773 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 774 } 775 776 errStr := ui.ErrorWriter.String() 777 if !strings.Contains(errStr, "remote backend") { 778 t.Fatalf("bad: %s", errStr) 779 } 780 } 781 782 func TestPush_plan(t *testing.T) { 783 tmp, cwd := testCwd(t) 784 defer testFixCwd(t, tmp, cwd) 785 786 // Create remote state file, this should be pulled 787 conf, srv := testRemoteState(t, testState(), 200) 788 defer srv.Close() 789 790 // Persist local remote state 791 s := terraform.NewState() 792 s.Serial = 5 793 s.Remote = conf 794 testStateFileRemote(t, s) 795 796 // Create a plan 797 planPath := testPlanFile(t, &terraform.Plan{ 798 Module: testModule(t, "apply"), 799 }) 800 801 ui := new(cli.MockUi) 802 c := &PushCommand{ 803 Meta: Meta{ 804 ContextOpts: testCtxConfig(testProvider()), 805 Ui: ui, 806 }, 807 } 808 809 args := []string{planPath} 810 if code := c.Run(args); code != 1 { 811 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 812 } 813 } 814 815 func testArchiveStr(t *testing.T, path string) []string { 816 f, err := os.Open(path) 817 if err != nil { 818 t.Fatalf("err: %s", err) 819 } 820 defer f.Close() 821 822 // Ungzip 823 gzipR, err := gzip.NewReader(f) 824 if err != nil { 825 t.Fatalf("err: %s", err) 826 } 827 828 // Accumulator 829 result := make([]string, 0, 10) 830 831 // Untar 832 tarR := tar.NewReader(gzipR) 833 for { 834 header, err := tarR.Next() 835 if err == io.EOF { 836 break 837 } 838 if err != nil { 839 t.Fatalf("err: %s", err) 840 } 841 842 result = append(result, header.Name) 843 } 844 845 sort.Strings(result) 846 return result 847 } 848 849 // we always quote map keys to be safe 850 func pushTFVars() []atlas.TFVar { 851 return []atlas.TFVar{ 852 {Key: "bar", Value: "foo", IsHCL: false}, 853 {Key: "baz", Value: `{ 854 "A" = "a" 855 }`, IsHCL: true}, 856 {Key: "fob", Value: `["a", "quotes \"in\" quotes"]`, IsHCL: true}, 857 {Key: "foo", Value: "bar", IsHCL: false}, 858 } 859 } 860 861 // the structure returned from the push-tfvars test fixture 862 func pushTFVarsMap() map[string]atlas.TFVar { 863 vars := make(map[string]atlas.TFVar) 864 for _, v := range pushTFVars() { 865 vars[v.Key] = v 866 } 867 return vars 868 }