github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/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  	// Provided vars should override existing ones
   209  	client.GetResult = map[string]string{
   210  		"foo": "old",
   211  	}
   212  	ui := new(cli.MockUi)
   213  	c := &PushCommand{
   214  		Meta: Meta{
   215  			ContextOpts: testCtxConfig(testProvider()),
   216  			Ui:          ui,
   217  		},
   218  
   219  		client: client,
   220  	}
   221  
   222  	path := testFixturePath("push-tfvars")
   223  	args := []string{
   224  		"-var-file", path + "/terraform.tfvars",
   225  		"-vcs=false",
   226  		path,
   227  	}
   228  	if code := c.Run(args); code != 0 {
   229  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   230  	}
   231  
   232  	actual := testArchiveStr(t, archivePath)
   233  	expected := []string{
   234  		".terraform/",
   235  		".terraform/terraform.tfstate",
   236  		"main.tf",
   237  		"terraform.tfvars",
   238  	}
   239  	if !reflect.DeepEqual(actual, expected) {
   240  		t.Fatalf("bad: %#v", actual)
   241  	}
   242  
   243  	if client.UpsertOptions.Name != "foo" {
   244  		t.Fatalf("bad: %#v", client.UpsertOptions)
   245  	}
   246  
   247  	variables := map[string]string{
   248  		"foo": "bar",
   249  		"bar": "foo",
   250  	}
   251  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
   252  		t.Fatalf("bad: %#v", client.UpsertOptions)
   253  	}
   254  }
   255  
   256  func TestPush_name(t *testing.T) {
   257  	tmp, cwd := testCwd(t)
   258  	defer testFixCwd(t, tmp, cwd)
   259  
   260  	// Create remote state file, this should be pulled
   261  	conf, srv := testRemoteState(t, testState(), 200)
   262  	defer srv.Close()
   263  
   264  	// Persist local remote state
   265  	s := terraform.NewState()
   266  	s.Serial = 5
   267  	s.Remote = conf
   268  	testStateFileRemote(t, s)
   269  
   270  	// Path where the archive will be "uploaded" to
   271  	archivePath := testTempFile(t)
   272  	defer os.Remove(archivePath)
   273  
   274  	client := &mockPushClient{File: archivePath}
   275  	ui := new(cli.MockUi)
   276  	c := &PushCommand{
   277  		Meta: Meta{
   278  			ContextOpts: testCtxConfig(testProvider()),
   279  			Ui:          ui,
   280  		},
   281  
   282  		client: client,
   283  	}
   284  
   285  	args := []string{
   286  		"-name", "bar",
   287  		"-vcs=false",
   288  		testFixturePath("push"),
   289  	}
   290  	if code := c.Run(args); code != 0 {
   291  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   292  	}
   293  
   294  	if client.UpsertOptions.Name != "bar" {
   295  		t.Fatalf("bad: %#v", client.UpsertOptions)
   296  	}
   297  }
   298  
   299  func TestPush_noState(t *testing.T) {
   300  	tmp, cwd := testCwd(t)
   301  	defer testFixCwd(t, tmp, cwd)
   302  
   303  	ui := new(cli.MockUi)
   304  	c := &PushCommand{
   305  		Meta: Meta{
   306  			ContextOpts: testCtxConfig(testProvider()),
   307  			Ui:          ui,
   308  		},
   309  	}
   310  
   311  	args := []string{}
   312  	if code := c.Run(args); code != 1 {
   313  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   314  	}
   315  }
   316  
   317  func TestPush_noRemoteState(t *testing.T) {
   318  	state := &terraform.State{
   319  		Modules: []*terraform.ModuleState{
   320  			&terraform.ModuleState{
   321  				Path: []string{"root"},
   322  				Resources: map[string]*terraform.ResourceState{
   323  					"test_instance.foo": &terraform.ResourceState{
   324  						Type: "test_instance",
   325  						Primary: &terraform.InstanceState{
   326  							ID: "bar",
   327  						},
   328  					},
   329  				},
   330  			},
   331  		},
   332  	}
   333  	statePath := testStateFile(t, state)
   334  
   335  	ui := new(cli.MockUi)
   336  	c := &PushCommand{
   337  		Meta: Meta{
   338  			Ui: ui,
   339  		},
   340  	}
   341  
   342  	args := []string{
   343  		"-state", statePath,
   344  	}
   345  	if code := c.Run(args); code != 1 {
   346  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   347  	}
   348  }
   349  
   350  func TestPush_plan(t *testing.T) {
   351  	tmp, cwd := testCwd(t)
   352  	defer testFixCwd(t, tmp, cwd)
   353  
   354  	// Create remote state file, this should be pulled
   355  	conf, srv := testRemoteState(t, testState(), 200)
   356  	defer srv.Close()
   357  
   358  	// Persist local remote state
   359  	s := terraform.NewState()
   360  	s.Serial = 5
   361  	s.Remote = conf
   362  	testStateFileRemote(t, s)
   363  
   364  	// Create a plan
   365  	planPath := testPlanFile(t, &terraform.Plan{
   366  		Module: testModule(t, "apply"),
   367  	})
   368  
   369  	ui := new(cli.MockUi)
   370  	c := &PushCommand{
   371  		Meta: Meta{
   372  			ContextOpts: testCtxConfig(testProvider()),
   373  			Ui:          ui,
   374  		},
   375  	}
   376  
   377  	args := []string{planPath}
   378  	if code := c.Run(args); code != 1 {
   379  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   380  	}
   381  }
   382  
   383  func testArchiveStr(t *testing.T, path string) []string {
   384  	f, err := os.Open(path)
   385  	if err != nil {
   386  		t.Fatalf("err: %s", err)
   387  	}
   388  	defer f.Close()
   389  
   390  	// Ungzip
   391  	gzipR, err := gzip.NewReader(f)
   392  	if err != nil {
   393  		t.Fatalf("err: %s", err)
   394  	}
   395  
   396  	// Accumulator
   397  	result := make([]string, 0, 10)
   398  
   399  	// Untar
   400  	tarR := tar.NewReader(gzipR)
   401  	for {
   402  		header, err := tarR.Next()
   403  		if err == io.EOF {
   404  			break
   405  		}
   406  		if err != nil {
   407  			t.Fatalf("err: %s", err)
   408  		}
   409  
   410  		result = append(result, header.Name)
   411  	}
   412  
   413  	sort.Strings(result)
   414  	return result
   415  }