github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/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  		testFixturePath("push"),
    48  	}
    49  	if code := c.Run(args); code != 0 {
    50  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    51  	}
    52  
    53  	actual := testArchiveStr(t, archivePath)
    54  	expected := []string{
    55  		".terraform/",
    56  		".terraform/terraform.tfstate",
    57  		"main.tf",
    58  	}
    59  	if !reflect.DeepEqual(actual, expected) {
    60  		t.Fatalf("bad: %#v", actual)
    61  	}
    62  
    63  	variables := make(map[string]string)
    64  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
    65  		t.Fatalf("bad: %#v", client.UpsertOptions)
    66  	}
    67  
    68  	if client.UpsertOptions.Name != "foo" {
    69  		t.Fatalf("bad: %#v", client.UpsertOptions)
    70  	}
    71  }
    72  
    73  func TestPush_input(t *testing.T) {
    74  	tmp, cwd := testCwd(t)
    75  	defer testFixCwd(t, tmp, cwd)
    76  
    77  	// Create remote state file, this should be pulled
    78  	conf, srv := testRemoteState(t, testState(), 200)
    79  	defer srv.Close()
    80  
    81  	// Persist local remote state
    82  	s := terraform.NewState()
    83  	s.Serial = 5
    84  	s.Remote = conf
    85  	testStateFileRemote(t, s)
    86  
    87  	// Path where the archive will be "uploaded" to
    88  	archivePath := testTempFile(t)
    89  	defer os.Remove(archivePath)
    90  
    91  	client := &mockPushClient{File: archivePath}
    92  	ui := new(cli.MockUi)
    93  	c := &PushCommand{
    94  		Meta: Meta{
    95  			ContextOpts: testCtxConfig(testProvider()),
    96  			Ui:          ui,
    97  		},
    98  
    99  		client: client,
   100  	}
   101  
   102  	// Disable test mode so input would be asked and setup the
   103  	// input reader/writers.
   104  	test = false
   105  	defer func() { test = true }()
   106  	defaultInputReader = bytes.NewBufferString("foo\n")
   107  	defaultInputWriter = new(bytes.Buffer)
   108  
   109  	args := []string{
   110  		testFixturePath("push-input"),
   111  	}
   112  	if code := c.Run(args); code != 0 {
   113  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   114  	}
   115  
   116  	variables := map[string]string{
   117  		"foo": "foo",
   118  	}
   119  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
   120  		t.Fatalf("bad: %#v", client.UpsertOptions)
   121  	}
   122  }
   123  
   124  func TestPush_inputPartial(t *testing.T) {
   125  	tmp, cwd := testCwd(t)
   126  	defer testFixCwd(t, tmp, cwd)
   127  
   128  	// Create remote state file, this should be pulled
   129  	conf, srv := testRemoteState(t, testState(), 200)
   130  	defer srv.Close()
   131  
   132  	// Persist local remote state
   133  	s := terraform.NewState()
   134  	s.Serial = 5
   135  	s.Remote = conf
   136  	testStateFileRemote(t, s)
   137  
   138  	// Path where the archive will be "uploaded" to
   139  	archivePath := testTempFile(t)
   140  	defer os.Remove(archivePath)
   141  
   142  	client := &mockPushClient{
   143  		File:      archivePath,
   144  		GetResult: map[string]string{"foo": "bar"},
   145  	}
   146  	ui := new(cli.MockUi)
   147  	c := &PushCommand{
   148  		Meta: Meta{
   149  			ContextOpts: testCtxConfig(testProvider()),
   150  			Ui:          ui,
   151  		},
   152  
   153  		client: client,
   154  	}
   155  
   156  	// Disable test mode so input would be asked and setup the
   157  	// input reader/writers.
   158  	test = false
   159  	defer func() { test = true }()
   160  	defaultInputReader = bytes.NewBufferString("foo\n")
   161  	defaultInputWriter = new(bytes.Buffer)
   162  
   163  	args := []string{
   164  		testFixturePath("push-input-partial"),
   165  	}
   166  	if code := c.Run(args); code != 0 {
   167  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   168  	}
   169  
   170  	variables := map[string]string{
   171  		"foo": "bar",
   172  		"bar": "foo",
   173  	}
   174  	if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
   175  		t.Fatalf("bad: %#v", client.UpsertOptions)
   176  	}
   177  }
   178  
   179  func TestPush_name(t *testing.T) {
   180  	tmp, cwd := testCwd(t)
   181  	defer testFixCwd(t, tmp, cwd)
   182  
   183  	// Create remote state file, this should be pulled
   184  	conf, srv := testRemoteState(t, testState(), 200)
   185  	defer srv.Close()
   186  
   187  	// Persist local remote state
   188  	s := terraform.NewState()
   189  	s.Serial = 5
   190  	s.Remote = conf
   191  	testStateFileRemote(t, s)
   192  
   193  	// Path where the archive will be "uploaded" to
   194  	archivePath := testTempFile(t)
   195  	defer os.Remove(archivePath)
   196  
   197  	client := &mockPushClient{File: archivePath}
   198  	ui := new(cli.MockUi)
   199  	c := &PushCommand{
   200  		Meta: Meta{
   201  			ContextOpts: testCtxConfig(testProvider()),
   202  			Ui:          ui,
   203  		},
   204  
   205  		client: client,
   206  	}
   207  
   208  	args := []string{
   209  		"-name", "bar",
   210  		testFixturePath("push"),
   211  	}
   212  	if code := c.Run(args); code != 0 {
   213  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   214  	}
   215  
   216  	if client.UpsertOptions.Name != "bar" {
   217  		t.Fatalf("bad: %#v", client.UpsertOptions)
   218  	}
   219  }
   220  
   221  func TestPush_noState(t *testing.T) {
   222  	tmp, cwd := testCwd(t)
   223  	defer testFixCwd(t, tmp, cwd)
   224  
   225  	ui := new(cli.MockUi)
   226  	c := &PushCommand{
   227  		Meta: Meta{
   228  			ContextOpts: testCtxConfig(testProvider()),
   229  			Ui:          ui,
   230  		},
   231  	}
   232  
   233  	args := []string{}
   234  	if code := c.Run(args); code != 1 {
   235  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   236  	}
   237  }
   238  
   239  func TestPush_noRemoteState(t *testing.T) {
   240  	state := &terraform.State{
   241  		Modules: []*terraform.ModuleState{
   242  			&terraform.ModuleState{
   243  				Path: []string{"root"},
   244  				Resources: map[string]*terraform.ResourceState{
   245  					"test_instance.foo": &terraform.ResourceState{
   246  						Type: "test_instance",
   247  						Primary: &terraform.InstanceState{
   248  							ID: "bar",
   249  						},
   250  					},
   251  				},
   252  			},
   253  		},
   254  	}
   255  	statePath := testStateFile(t, state)
   256  
   257  	ui := new(cli.MockUi)
   258  	c := &PushCommand{
   259  		Meta: Meta{
   260  			Ui: ui,
   261  		},
   262  	}
   263  
   264  	args := []string{
   265  		"-state", statePath,
   266  	}
   267  	if code := c.Run(args); code != 1 {
   268  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   269  	}
   270  }
   271  
   272  func TestPush_plan(t *testing.T) {
   273  	tmp, cwd := testCwd(t)
   274  	defer testFixCwd(t, tmp, cwd)
   275  
   276  	// Create remote state file, this should be pulled
   277  	conf, srv := testRemoteState(t, testState(), 200)
   278  	defer srv.Close()
   279  
   280  	// Persist local remote state
   281  	s := terraform.NewState()
   282  	s.Serial = 5
   283  	s.Remote = conf
   284  	testStateFileRemote(t, s)
   285  
   286  	// Create a plan
   287  	planPath := testPlanFile(t, &terraform.Plan{
   288  		Module: testModule(t, "apply"),
   289  	})
   290  
   291  	ui := new(cli.MockUi)
   292  	c := &PushCommand{
   293  		Meta: Meta{
   294  			ContextOpts: testCtxConfig(testProvider()),
   295  			Ui:          ui,
   296  		},
   297  	}
   298  
   299  	args := []string{planPath}
   300  	if code := c.Run(args); code != 1 {
   301  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   302  	}
   303  }
   304  
   305  func testArchiveStr(t *testing.T, path string) []string {
   306  	f, err := os.Open(path)
   307  	if err != nil {
   308  		t.Fatalf("err: %s", err)
   309  	}
   310  	defer f.Close()
   311  
   312  	// Ungzip
   313  	gzipR, err := gzip.NewReader(f)
   314  	if err != nil {
   315  		t.Fatalf("err: %s", err)
   316  	}
   317  
   318  	// Accumulator
   319  	result := make([]string, 0, 10)
   320  
   321  	// Untar
   322  	tarR := tar.NewReader(gzipR)
   323  	for {
   324  		header, err := tarR.Next()
   325  		if err == io.EOF {
   326  			break
   327  		}
   328  		if err != nil {
   329  			t.Fatalf("err: %s", err)
   330  		}
   331  
   332  		result = append(result, header.Name)
   333  	}
   334  
   335  	sort.Strings(result)
   336  	return result
   337  }