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