github.com/markdia/terraform@v0.5.1-0.20150508012022-f1ae920aa970/command/push_test.go (about)

     1  package command
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"compress/gzip"
     7  	"io"
     8  	"os"
     9  	"reflect"
    10  	"sort"
    11  	"testing"
    12  
    13  	"github.com/hashicorp/terraform/terraform"
    14  	"github.com/mitchellh/cli"
    15  )
    16  
    17  func TestPush_good(t *testing.T) {
    18  	tmp, cwd := testCwd(t)
    19  	defer testFixCwd(t, tmp, cwd)
    20  
    21  	// Create remote state file, this should be pulled
    22  	conf, srv := testRemoteState(t, testState(), 200)
    23  	defer srv.Close()
    24  
    25  	// Persist local remote state
    26  	s := terraform.NewState()
    27  	s.Serial = 5
    28  	s.Remote = conf
    29  	testStateFileRemote(t, s)
    30  
    31  	// Path where the archive will be "uploaded" to
    32  	archivePath := testTempFile(t)
    33  	defer os.Remove(archivePath)
    34  
    35  	client := &mockPushClient{File: archivePath}
    36  	ui := new(cli.MockUi)
    37  	c := &PushCommand{
    38  		Meta: Meta{
    39  			ContextOpts: testCtxConfig(testProvider()),
    40  			Ui:          ui,
    41  		},
    42  
    43  		client: client,
    44  	}
    45  
    46  	args := []string{
    47  		"-vcs=false",
    48  		testFixturePath("push"),
    49  	}
    50  	if code := c.Run(args); code != 0 {
    51  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    52  	}
    53  
    54  	actual := testArchiveStr(t, archivePath)
    55  	expected := []string{
    56  		".terraform/",
    57  		".terraform/terraform.tfstate",
    58  		"main.tf",
    59  	}
    60  	if !reflect.DeepEqual(actual, expected) {
    61  		t.Fatalf("bad: %#v", actual)
    62  	}
    63  
    64  	variables := make(map[string]string)
    65  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
    66  		t.Fatalf("bad: %#v", client.UpsertOptions)
    67  	}
    68  
    69  	if client.UpsertOptions.Name != "foo" {
    70  		t.Fatalf("bad: %#v", client.UpsertOptions)
    71  	}
    72  }
    73  
    74  func TestPush_input(t *testing.T) {
    75  	tmp, cwd := testCwd(t)
    76  	defer testFixCwd(t, tmp, cwd)
    77  
    78  	// Create remote state file, this should be pulled
    79  	conf, srv := testRemoteState(t, testState(), 200)
    80  	defer srv.Close()
    81  
    82  	// Persist local remote state
    83  	s := terraform.NewState()
    84  	s.Serial = 5
    85  	s.Remote = conf
    86  	testStateFileRemote(t, s)
    87  
    88  	// Path where the archive will be "uploaded" to
    89  	archivePath := testTempFile(t)
    90  	defer os.Remove(archivePath)
    91  
    92  	client := &mockPushClient{File: archivePath}
    93  	ui := new(cli.MockUi)
    94  	c := &PushCommand{
    95  		Meta: Meta{
    96  			ContextOpts: testCtxConfig(testProvider()),
    97  			Ui:          ui,
    98  		},
    99  
   100  		client: client,
   101  	}
   102  
   103  	// Disable test mode so input would be asked and setup the
   104  	// input reader/writers.
   105  	test = false
   106  	defer func() { test = true }()
   107  	defaultInputReader = bytes.NewBufferString("foo\n")
   108  	defaultInputWriter = new(bytes.Buffer)
   109  
   110  	args := []string{
   111  		"-vcs=false",
   112  		testFixturePath("push-input"),
   113  	}
   114  	if code := c.Run(args); code != 0 {
   115  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   116  	}
   117  
   118  	variables := map[string]string{
   119  		"foo": "foo",
   120  	}
   121  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
   122  		t.Fatalf("bad: %#v", client.UpsertOptions)
   123  	}
   124  }
   125  
   126  func TestPush_inputPartial(t *testing.T) {
   127  	tmp, cwd := testCwd(t)
   128  	defer testFixCwd(t, tmp, cwd)
   129  
   130  	// Create remote state file, this should be pulled
   131  	conf, srv := testRemoteState(t, testState(), 200)
   132  	defer srv.Close()
   133  
   134  	// Persist local remote state
   135  	s := terraform.NewState()
   136  	s.Serial = 5
   137  	s.Remote = conf
   138  	testStateFileRemote(t, s)
   139  
   140  	// Path where the archive will be "uploaded" to
   141  	archivePath := testTempFile(t)
   142  	defer os.Remove(archivePath)
   143  
   144  	client := &mockPushClient{
   145  		File:      archivePath,
   146  		GetResult: map[string]string{"foo": "bar"},
   147  	}
   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  	// Disable test mode so input would be asked and setup the
   159  	// input reader/writers.
   160  	test = false
   161  	defer func() { test = true }()
   162  	defaultInputReader = bytes.NewBufferString("foo\n")
   163  	defaultInputWriter = new(bytes.Buffer)
   164  
   165  	args := []string{
   166  		"-vcs=false",
   167  		testFixturePath("push-input-partial"),
   168  	}
   169  	if code := c.Run(args); code != 0 {
   170  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   171  	}
   172  
   173  	variables := map[string]string{
   174  		"foo": "bar",
   175  		"bar": "foo",
   176  	}
   177  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
   178  		t.Fatalf("bad: %#v", client.UpsertOptions)
   179  	}
   180  }
   181  
   182  func TestPush_inputTfvars(t *testing.T) {
   183  	// Disable test mode so input would be asked and setup the
   184  	// input reader/writers.
   185  	test = false
   186  	defer func() { test = true }()
   187  	defaultInputReader = bytes.NewBufferString("nope\n")
   188  	defaultInputWriter = new(bytes.Buffer)
   189  
   190  	tmp, cwd := testCwd(t)
   191  	defer testFixCwd(t, tmp, cwd)
   192  
   193  	// Create remote state file, this should be pulled
   194  	conf, srv := testRemoteState(t, testState(), 200)
   195  	defer srv.Close()
   196  
   197  	// Persist local remote state
   198  	s := terraform.NewState()
   199  	s.Serial = 5
   200  	s.Remote = conf
   201  	testStateFileRemote(t, s)
   202  
   203  	// Path where the archive will be "uploaded" to
   204  	archivePath := testTempFile(t)
   205  	defer os.Remove(archivePath)
   206  
   207  	client := &mockPushClient{File: archivePath}
   208  	ui := new(cli.MockUi)
   209  	c := &PushCommand{
   210  		Meta: Meta{
   211  			ContextOpts: testCtxConfig(testProvider()),
   212  			Ui:          ui,
   213  		},
   214  
   215  		client: client,
   216  	}
   217  
   218  	path := testFixturePath("push-tfvars")
   219  	args := []string{
   220  		"-var-file", path + "/terraform.tfvars",
   221  		"-vcs=false",
   222  		path,
   223  	}
   224  	if code := c.Run(args); code != 0 {
   225  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   226  	}
   227  
   228  	actual := testArchiveStr(t, archivePath)
   229  	expected := []string{
   230  		".terraform/",
   231  		".terraform/terraform.tfstate",
   232  		"main.tf",
   233  		"terraform.tfvars",
   234  	}
   235  	if !reflect.DeepEqual(actual, expected) {
   236  		t.Fatalf("bad: %#v", actual)
   237  	}
   238  
   239  	if client.UpsertOptions.Name != "foo" {
   240  		t.Fatalf("bad: %#v", client.UpsertOptions)
   241  	}
   242  
   243  	variables := map[string]string{
   244  		"foo": "bar",
   245  		"bar": "foo",
   246  	}
   247  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
   248  		t.Fatalf("bad: %#v", client.UpsertOptions)
   249  	}
   250  }
   251  
   252  func TestPush_name(t *testing.T) {
   253  	tmp, cwd := testCwd(t)
   254  	defer testFixCwd(t, tmp, cwd)
   255  
   256  	// Create remote state file, this should be pulled
   257  	conf, srv := testRemoteState(t, testState(), 200)
   258  	defer srv.Close()
   259  
   260  	// Persist local remote state
   261  	s := terraform.NewState()
   262  	s.Serial = 5
   263  	s.Remote = conf
   264  	testStateFileRemote(t, s)
   265  
   266  	// Path where the archive will be "uploaded" to
   267  	archivePath := testTempFile(t)
   268  	defer os.Remove(archivePath)
   269  
   270  	client := &mockPushClient{File: archivePath}
   271  	ui := new(cli.MockUi)
   272  	c := &PushCommand{
   273  		Meta: Meta{
   274  			ContextOpts: testCtxConfig(testProvider()),
   275  			Ui:          ui,
   276  		},
   277  
   278  		client: client,
   279  	}
   280  
   281  	args := []string{
   282  		"-name", "bar",
   283  		"-vcs=false",
   284  		testFixturePath("push"),
   285  	}
   286  	if code := c.Run(args); code != 0 {
   287  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   288  	}
   289  
   290  	if client.UpsertOptions.Name != "bar" {
   291  		t.Fatalf("bad: %#v", client.UpsertOptions)
   292  	}
   293  }
   294  
   295  func TestPush_noState(t *testing.T) {
   296  	tmp, cwd := testCwd(t)
   297  	defer testFixCwd(t, tmp, cwd)
   298  
   299  	ui := new(cli.MockUi)
   300  	c := &PushCommand{
   301  		Meta: Meta{
   302  			ContextOpts: testCtxConfig(testProvider()),
   303  			Ui:          ui,
   304  		},
   305  	}
   306  
   307  	args := []string{}
   308  	if code := c.Run(args); code != 1 {
   309  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   310  	}
   311  }
   312  
   313  func TestPush_noRemoteState(t *testing.T) {
   314  	state := &terraform.State{
   315  		Modules: []*terraform.ModuleState{
   316  			&terraform.ModuleState{
   317  				Path: []string{"root"},
   318  				Resources: map[string]*terraform.ResourceState{
   319  					"test_instance.foo": &terraform.ResourceState{
   320  						Type: "test_instance",
   321  						Primary: &terraform.InstanceState{
   322  							ID: "bar",
   323  						},
   324  					},
   325  				},
   326  			},
   327  		},
   328  	}
   329  	statePath := testStateFile(t, state)
   330  
   331  	ui := new(cli.MockUi)
   332  	c := &PushCommand{
   333  		Meta: Meta{
   334  			Ui: ui,
   335  		},
   336  	}
   337  
   338  	args := []string{
   339  		"-state", statePath,
   340  	}
   341  	if code := c.Run(args); code != 1 {
   342  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   343  	}
   344  }
   345  
   346  func TestPush_plan(t *testing.T) {
   347  	tmp, cwd := testCwd(t)
   348  	defer testFixCwd(t, tmp, cwd)
   349  
   350  	// Create remote state file, this should be pulled
   351  	conf, srv := testRemoteState(t, testState(), 200)
   352  	defer srv.Close()
   353  
   354  	// Persist local remote state
   355  	s := terraform.NewState()
   356  	s.Serial = 5
   357  	s.Remote = conf
   358  	testStateFileRemote(t, s)
   359  
   360  	// Create a plan
   361  	planPath := testPlanFile(t, &terraform.Plan{
   362  		Module: testModule(t, "apply"),
   363  	})
   364  
   365  	ui := new(cli.MockUi)
   366  	c := &PushCommand{
   367  		Meta: Meta{
   368  			ContextOpts: testCtxConfig(testProvider()),
   369  			Ui:          ui,
   370  		},
   371  	}
   372  
   373  	args := []string{planPath}
   374  	if code := c.Run(args); code != 1 {
   375  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   376  	}
   377  }
   378  
   379  func testArchiveStr(t *testing.T, path string) []string {
   380  	f, err := os.Open(path)
   381  	if err != nil {
   382  		t.Fatalf("err: %s", err)
   383  	}
   384  	defer f.Close()
   385  
   386  	// Ungzip
   387  	gzipR, err := gzip.NewReader(f)
   388  	if err != nil {
   389  		t.Fatalf("err: %s", err)
   390  	}
   391  
   392  	// Accumulator
   393  	result := make([]string, 0, 10)
   394  
   395  	// Untar
   396  	tarR := tar.NewReader(gzipR)
   397  	for {
   398  		header, err := tarR.Next()
   399  		if err == io.EOF {
   400  			break
   401  		}
   402  		if err != nil {
   403  			t.Fatalf("err: %s", err)
   404  		}
   405  
   406  		result = append(result, header.Name)
   407  	}
   408  
   409  	sort.Strings(result)
   410  	return result
   411  }