github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/command/apply_test.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"log"
     8  	"net"
     9  	"net/http"
    10  	"net/url"
    11  	"os"
    12  	"path/filepath"
    13  	"reflect"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/hashicorp/terraform/state"
    20  	"github.com/hashicorp/terraform/terraform"
    21  	"github.com/mitchellh/cli"
    22  )
    23  
    24  func TestApply(t *testing.T) {
    25  	statePath := testTempFile(t)
    26  
    27  	p := testProvider()
    28  	ui := new(cli.MockUi)
    29  	c := &ApplyCommand{
    30  		Meta: Meta{
    31  			testingOverrides: metaOverridesForProvider(p),
    32  			Ui:               ui,
    33  		},
    34  	}
    35  
    36  	args := []string{
    37  		"-state", statePath,
    38  		testFixturePath("apply"),
    39  	}
    40  	if code := c.Run(args); code != 0 {
    41  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    42  	}
    43  
    44  	if _, err := os.Stat(statePath); err != nil {
    45  		t.Fatalf("err: %s", err)
    46  	}
    47  
    48  	f, err := os.Open(statePath)
    49  	if err != nil {
    50  		t.Fatalf("err: %s", err)
    51  	}
    52  	defer f.Close()
    53  
    54  	state, err := terraform.ReadState(f)
    55  	if err != nil {
    56  		t.Fatalf("err: %s", err)
    57  	}
    58  	if state == nil {
    59  		t.Fatal("state should not be nil")
    60  	}
    61  }
    62  
    63  // test apply with locked state
    64  func TestApply_lockedState(t *testing.T) {
    65  	statePath := testTempFile(t)
    66  
    67  	unlock, err := testLockState("./testdata", statePath)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	defer unlock()
    72  
    73  	p := testProvider()
    74  	ui := new(cli.MockUi)
    75  	c := &ApplyCommand{
    76  		Meta: Meta{
    77  			testingOverrides: metaOverridesForProvider(p),
    78  			Ui:               ui,
    79  		},
    80  	}
    81  
    82  	args := []string{
    83  		"-state", statePath,
    84  		testFixturePath("apply"),
    85  	}
    86  	if code := c.Run(args); code == 0 {
    87  		t.Fatal("expected error")
    88  	}
    89  
    90  	output := ui.ErrorWriter.String()
    91  	if !strings.Contains(output, "lock") {
    92  		t.Fatal("command output does not look like a lock error:", output)
    93  	}
    94  }
    95  
    96  // test apply with locked state, waiting for unlock
    97  func TestApply_lockedStateWait(t *testing.T) {
    98  	statePath := testTempFile(t)
    99  
   100  	unlock, err := testLockState("./testdata", statePath)
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	// unlock during apply
   106  	go func() {
   107  		time.Sleep(500 * time.Millisecond)
   108  		unlock()
   109  	}()
   110  
   111  	p := testProvider()
   112  	ui := new(cli.MockUi)
   113  	c := &ApplyCommand{
   114  		Meta: Meta{
   115  			testingOverrides: metaOverridesForProvider(p),
   116  			Ui:               ui,
   117  		},
   118  	}
   119  
   120  	// wait 4s just in case the lock process doesn't release in under a second,
   121  	// and we want our context to be alive for a second retry at the 3s mark.
   122  	args := []string{
   123  		"-state", statePath,
   124  		"-lock-timeout", "4s",
   125  		testFixturePath("apply"),
   126  	}
   127  	if code := c.Run(args); code != 0 {
   128  		log.Fatalf("lock should have succeed in less than 3s: %s", ui.ErrorWriter)
   129  	}
   130  }
   131  
   132  // high water mark counter
   133  type hwm struct {
   134  	sync.Mutex
   135  	val int
   136  	max int
   137  }
   138  
   139  func (t *hwm) Inc() {
   140  	t.Lock()
   141  	defer t.Unlock()
   142  	t.val++
   143  	if t.val > t.max {
   144  		t.max = t.val
   145  	}
   146  }
   147  
   148  func (t *hwm) Dec() {
   149  	t.Lock()
   150  	defer t.Unlock()
   151  	t.val--
   152  }
   153  
   154  func (t *hwm) Max() int {
   155  	t.Lock()
   156  	defer t.Unlock()
   157  	return t.max
   158  }
   159  
   160  func TestApply_parallelism(t *testing.T) {
   161  	provider := testProvider()
   162  	statePath := testTempFile(t)
   163  
   164  	par := 4
   165  
   166  	// This blocks all the appy functions. We close it when we exit so
   167  	// they end quickly after this test finishes.
   168  	block := make(chan struct{})
   169  	// signal how many goroutines have started
   170  	started := make(chan int, 100)
   171  
   172  	runCount := &hwm{}
   173  
   174  	provider.ApplyFn = func(
   175  		i *terraform.InstanceInfo,
   176  		s *terraform.InstanceState,
   177  		d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   178  		// Increment so we're counting parallelism
   179  		started <- 1
   180  		runCount.Inc()
   181  		defer runCount.Dec()
   182  		// Block here to stage up our max number of parallel instances
   183  		<-block
   184  
   185  		return nil, nil
   186  	}
   187  
   188  	ui := new(cli.MockUi)
   189  	c := &ApplyCommand{
   190  		Meta: Meta{
   191  			testingOverrides: metaOverridesForProvider(provider),
   192  			Ui:               ui,
   193  		},
   194  	}
   195  
   196  	args := []string{
   197  		"-state", statePath,
   198  		fmt.Sprintf("-parallelism=%d", par),
   199  		testFixturePath("parallelism"),
   200  	}
   201  
   202  	// Run in a goroutine. We can get any errors from the ui.OutputWriter
   203  	doneCh := make(chan int, 1)
   204  	go func() {
   205  		doneCh <- c.Run(args)
   206  	}()
   207  
   208  	timeout := time.After(5 * time.Second)
   209  
   210  	// ensure things are running
   211  	for i := 0; i < par; i++ {
   212  		select {
   213  		case <-timeout:
   214  			t.Fatal("timeout waiting for all goroutines to start")
   215  		case <-started:
   216  		}
   217  	}
   218  
   219  	// a little extra sleep, since we can't ensure all goroutines from the walk have
   220  	// really started
   221  	time.Sleep(100 * time.Millisecond)
   222  	close(block)
   223  
   224  	select {
   225  	case res := <-doneCh:
   226  		if res != 0 {
   227  			t.Fatal(ui.OutputWriter.String())
   228  		}
   229  	case <-timeout:
   230  		t.Fatal("timeout waiting from Run()")
   231  	}
   232  
   233  	// The total in flight should equal the parallelism
   234  	if runCount.Max() != par {
   235  		t.Fatalf("Expected parallelism: %d, got: %d", par, runCount.Max())
   236  	}
   237  }
   238  
   239  func TestApply_configInvalid(t *testing.T) {
   240  	p := testProvider()
   241  	ui := new(cli.MockUi)
   242  	c := &ApplyCommand{
   243  		Meta: Meta{
   244  			testingOverrides: metaOverridesForProvider(p),
   245  			Ui:               ui,
   246  		},
   247  	}
   248  
   249  	args := []string{
   250  		"-state", testTempFile(t),
   251  		testFixturePath("apply-config-invalid"),
   252  	}
   253  	if code := c.Run(args); code != 1 {
   254  		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
   255  	}
   256  }
   257  
   258  func TestApply_defaultState(t *testing.T) {
   259  	td, err := ioutil.TempDir("", "tf")
   260  	if err != nil {
   261  		t.Fatalf("err: %s", err)
   262  	}
   263  	statePath := filepath.Join(td, DefaultStateFilename)
   264  
   265  	// Change to the temporary directory
   266  	cwd, err := os.Getwd()
   267  	if err != nil {
   268  		t.Fatalf("err: %s", err)
   269  	}
   270  	if err := os.Chdir(filepath.Dir(statePath)); err != nil {
   271  		t.Fatalf("err: %s", err)
   272  	}
   273  	defer os.Chdir(cwd)
   274  
   275  	p := testProvider()
   276  	ui := new(cli.MockUi)
   277  	c := &ApplyCommand{
   278  		Meta: Meta{
   279  			testingOverrides: metaOverridesForProvider(p),
   280  			Ui:               ui,
   281  		},
   282  	}
   283  
   284  	args := []string{
   285  		testFixturePath("apply"),
   286  	}
   287  	if code := c.Run(args); code != 0 {
   288  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   289  	}
   290  
   291  	if _, err := os.Stat(statePath); err != nil {
   292  		t.Fatalf("err: %s", err)
   293  	}
   294  
   295  	f, err := os.Open(statePath)
   296  	if err != nil {
   297  		t.Fatalf("err: %s", err)
   298  	}
   299  	defer f.Close()
   300  
   301  	state, err := terraform.ReadState(f)
   302  	if err != nil {
   303  		t.Fatalf("err: %s", err)
   304  	}
   305  	if state == nil {
   306  		t.Fatal("state should not be nil")
   307  	}
   308  }
   309  
   310  func TestApply_error(t *testing.T) {
   311  	statePath := testTempFile(t)
   312  
   313  	p := testProvider()
   314  	ui := new(cli.MockUi)
   315  	c := &ApplyCommand{
   316  		Meta: Meta{
   317  			testingOverrides: metaOverridesForProvider(p),
   318  			Ui:               ui,
   319  		},
   320  	}
   321  
   322  	var lock sync.Mutex
   323  	errored := false
   324  	p.ApplyFn = func(
   325  		info *terraform.InstanceInfo,
   326  		s *terraform.InstanceState,
   327  		d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   328  		lock.Lock()
   329  		defer lock.Unlock()
   330  
   331  		if !errored {
   332  			errored = true
   333  			return nil, fmt.Errorf("error")
   334  		}
   335  
   336  		return &terraform.InstanceState{ID: "foo"}, nil
   337  	}
   338  	p.DiffFn = func(
   339  		*terraform.InstanceInfo,
   340  		*terraform.InstanceState,
   341  		*terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   342  		return &terraform.InstanceDiff{
   343  			Attributes: map[string]*terraform.ResourceAttrDiff{
   344  				"ami": &terraform.ResourceAttrDiff{
   345  					New: "bar",
   346  				},
   347  			},
   348  		}, nil
   349  	}
   350  
   351  	args := []string{
   352  		"-state", statePath,
   353  		testFixturePath("apply-error"),
   354  	}
   355  	if code := c.Run(args); code != 1 {
   356  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   357  	}
   358  
   359  	if _, err := os.Stat(statePath); err != nil {
   360  		t.Fatalf("err: %s", err)
   361  	}
   362  
   363  	f, err := os.Open(statePath)
   364  	if err != nil {
   365  		t.Fatalf("err: %s", err)
   366  	}
   367  	defer f.Close()
   368  
   369  	state, err := terraform.ReadState(f)
   370  	if err != nil {
   371  		t.Fatalf("err: %s", err)
   372  	}
   373  	if state == nil {
   374  		t.Fatal("state should not be nil")
   375  	}
   376  	if len(state.RootModule().Resources) == 0 {
   377  		t.Fatal("no resources in state")
   378  	}
   379  }
   380  
   381  func TestApply_input(t *testing.T) {
   382  	// Disable test mode so input would be asked
   383  	test = false
   384  	defer func() { test = true }()
   385  
   386  	// Set some default reader/writers for the inputs
   387  	defaultInputReader = bytes.NewBufferString("foo\n")
   388  	defaultInputWriter = new(bytes.Buffer)
   389  
   390  	statePath := testTempFile(t)
   391  
   392  	p := testProvider()
   393  	ui := new(cli.MockUi)
   394  	c := &ApplyCommand{
   395  		Meta: Meta{
   396  			testingOverrides: metaOverridesForProvider(p),
   397  			Ui:               ui,
   398  		},
   399  	}
   400  
   401  	args := []string{
   402  		"-state", statePath,
   403  		testFixturePath("apply-input"),
   404  	}
   405  	if code := c.Run(args); code != 0 {
   406  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   407  	}
   408  
   409  	if !p.InputCalled {
   410  		t.Fatal("input should be called")
   411  	}
   412  }
   413  
   414  // When only a partial set of the variables are set, Terraform
   415  // should still ask for the unset ones by default (with -input=true)
   416  func TestApply_inputPartial(t *testing.T) {
   417  	// Disable test mode so input would be asked
   418  	test = false
   419  	defer func() { test = true }()
   420  
   421  	// Set some default reader/writers for the inputs
   422  	defaultInputReader = bytes.NewBufferString("one\ntwo\n")
   423  	defaultInputWriter = new(bytes.Buffer)
   424  
   425  	statePath := testTempFile(t)
   426  
   427  	p := testProvider()
   428  	ui := new(cli.MockUi)
   429  	c := &ApplyCommand{
   430  		Meta: Meta{
   431  			testingOverrides: metaOverridesForProvider(p),
   432  			Ui:               ui,
   433  		},
   434  	}
   435  
   436  	args := []string{
   437  		"-state", statePath,
   438  		"-var", "foo=foovalue",
   439  		testFixturePath("apply-input-partial"),
   440  	}
   441  	if code := c.Run(args); code != 0 {
   442  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   443  	}
   444  
   445  	expected := strings.TrimSpace(`
   446  <no state>
   447  Outputs:
   448  
   449  bar = one
   450  foo = foovalue
   451  	`)
   452  	testStateOutput(t, statePath, expected)
   453  }
   454  
   455  func TestApply_noArgs(t *testing.T) {
   456  	cwd, err := os.Getwd()
   457  	if err != nil {
   458  		t.Fatalf("err: %s", err)
   459  	}
   460  	if err := os.Chdir(testFixturePath("plan")); err != nil {
   461  		t.Fatalf("err: %s", err)
   462  	}
   463  	defer os.Chdir(cwd)
   464  
   465  	statePath := testTempFile(t)
   466  
   467  	p := testProvider()
   468  	ui := new(cli.MockUi)
   469  	c := &ApplyCommand{
   470  		Meta: Meta{
   471  			testingOverrides: metaOverridesForProvider(p),
   472  			Ui:               ui,
   473  		},
   474  	}
   475  
   476  	args := []string{
   477  		"-state", statePath,
   478  	}
   479  	if code := c.Run(args); code != 0 {
   480  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   481  	}
   482  
   483  	if _, err := os.Stat(statePath); err != nil {
   484  		t.Fatalf("err: %s", err)
   485  	}
   486  
   487  	f, err := os.Open(statePath)
   488  	if err != nil {
   489  		t.Fatalf("err: %s", err)
   490  	}
   491  	defer f.Close()
   492  
   493  	state, err := terraform.ReadState(f)
   494  	if err != nil {
   495  		t.Fatalf("err: %s", err)
   496  	}
   497  	if state == nil {
   498  		t.Fatal("state should not be nil")
   499  	}
   500  }
   501  
   502  func TestApply_plan(t *testing.T) {
   503  	// Disable test mode so input would be asked
   504  	test = false
   505  	defer func() { test = true }()
   506  
   507  	// Set some default reader/writers for the inputs
   508  	defaultInputReader = new(bytes.Buffer)
   509  	defaultInputWriter = new(bytes.Buffer)
   510  
   511  	planPath := testPlanFile(t, &terraform.Plan{
   512  		Module: testModule(t, "apply"),
   513  	})
   514  	statePath := testTempFile(t)
   515  
   516  	p := testProvider()
   517  	ui := new(cli.MockUi)
   518  	c := &ApplyCommand{
   519  		Meta: Meta{
   520  			testingOverrides: metaOverridesForProvider(p),
   521  			Ui:               ui,
   522  		},
   523  	}
   524  
   525  	args := []string{
   526  		"-state-out", statePath,
   527  		planPath,
   528  	}
   529  	if code := c.Run(args); code != 0 {
   530  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   531  	}
   532  
   533  	if p.InputCalled {
   534  		t.Fatalf("input should not be called for plans")
   535  	}
   536  
   537  	if _, err := os.Stat(statePath); err != nil {
   538  		t.Fatalf("err: %s", err)
   539  	}
   540  
   541  	f, err := os.Open(statePath)
   542  	if err != nil {
   543  		t.Fatalf("err: %s", err)
   544  	}
   545  	defer f.Close()
   546  
   547  	state, err := terraform.ReadState(f)
   548  	if err != nil {
   549  		t.Fatalf("err: %s", err)
   550  	}
   551  	if state == nil {
   552  		t.Fatal("state should not be nil")
   553  	}
   554  }
   555  
   556  func TestApply_plan_backup(t *testing.T) {
   557  	plan := testPlan(t)
   558  	planPath := testPlanFile(t, plan)
   559  	statePath := testTempFile(t)
   560  	backupPath := testTempFile(t)
   561  
   562  	p := testProvider()
   563  	ui := new(cli.MockUi)
   564  	c := &ApplyCommand{
   565  		Meta: Meta{
   566  			testingOverrides: metaOverridesForProvider(p),
   567  			Ui:               ui,
   568  		},
   569  	}
   570  
   571  	// create a state file that needs to be backed up
   572  	err := (&state.LocalState{Path: statePath}).WriteState(plan.State)
   573  	if err != nil {
   574  		t.Fatal(err)
   575  	}
   576  	args := []string{
   577  		"-state-out", statePath,
   578  		"-backup", backupPath,
   579  		planPath,
   580  	}
   581  	if code := c.Run(args); code != 0 {
   582  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   583  	}
   584  
   585  	{
   586  		// Should have a backup file
   587  		f, err := os.Open(backupPath)
   588  		if err != nil {
   589  			t.Fatalf("err: %s", err)
   590  		}
   591  
   592  		_, err = terraform.ReadState(f)
   593  		f.Close()
   594  		if err != nil {
   595  			t.Fatalf("err: %s", err)
   596  		}
   597  	}
   598  }
   599  
   600  func TestApply_plan_noBackup(t *testing.T) {
   601  	planPath := testPlanFile(t, testPlan(t))
   602  	statePath := testTempFile(t)
   603  
   604  	p := testProvider()
   605  	ui := new(cli.MockUi)
   606  	c := &ApplyCommand{
   607  		Meta: Meta{
   608  			testingOverrides: metaOverridesForProvider(p),
   609  			Ui:               ui,
   610  		},
   611  	}
   612  
   613  	args := []string{
   614  		"-state-out", statePath,
   615  		"-backup", "-",
   616  		planPath,
   617  	}
   618  	if code := c.Run(args); code != 0 {
   619  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   620  	}
   621  
   622  	// Ensure there is no backup
   623  	_, err := os.Stat(statePath + DefaultBackupExtension)
   624  	if err == nil || !os.IsNotExist(err) {
   625  		t.Fatalf("backup should not exist")
   626  	}
   627  
   628  	// Ensure there is no literal "-"
   629  	_, err = os.Stat("-")
   630  	if err == nil || !os.IsNotExist(err) {
   631  		t.Fatalf("backup should not exist")
   632  	}
   633  }
   634  
   635  func TestApply_plan_remoteState(t *testing.T) {
   636  	// Disable test mode so input would be asked
   637  	test = false
   638  	defer func() { test = true }()
   639  	tmp, cwd := testCwd(t)
   640  	defer testFixCwd(t, tmp, cwd)
   641  	remoteStatePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
   642  	if err := os.MkdirAll(filepath.Dir(remoteStatePath), 0755); err != nil {
   643  		t.Fatalf("err: %s", err)
   644  	}
   645  
   646  	// Set some default reader/writers for the inputs
   647  	defaultInputReader = new(bytes.Buffer)
   648  	defaultInputWriter = new(bytes.Buffer)
   649  
   650  	// Create a remote state
   651  	state := testState()
   652  	conf, srv := testRemoteState(t, state, 200)
   653  	defer srv.Close()
   654  	state.Remote = conf
   655  
   656  	planPath := testPlanFile(t, &terraform.Plan{
   657  		Module: testModule(t, "apply"),
   658  		State:  state,
   659  	})
   660  
   661  	p := testProvider()
   662  	ui := new(cli.MockUi)
   663  	c := &ApplyCommand{
   664  		Meta: Meta{
   665  			testingOverrides: metaOverridesForProvider(p),
   666  			Ui:               ui,
   667  		},
   668  	}
   669  
   670  	args := []string{
   671  		planPath,
   672  	}
   673  	if code := c.Run(args); code != 0 {
   674  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   675  	}
   676  
   677  	if p.InputCalled {
   678  		t.Fatalf("input should not be called for plans")
   679  	}
   680  
   681  	// State file should be not be installed
   682  	if _, err := os.Stat(filepath.Join(tmp, DefaultStateFilename)); err == nil {
   683  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   684  		t.Fatalf("State path should not exist: %s", string(data))
   685  	}
   686  
   687  	// Check that there is no remote state config
   688  	if _, err := os.Stat(remoteStatePath); err == nil {
   689  		t.Fatalf("has remote state config")
   690  	}
   691  }
   692  
   693  func TestApply_planWithVarFile(t *testing.T) {
   694  	varFileDir := testTempDir(t)
   695  	varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
   696  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
   697  		t.Fatalf("err: %s", err)
   698  	}
   699  
   700  	planPath := testPlanFile(t, &terraform.Plan{
   701  		Module: testModule(t, "apply"),
   702  	})
   703  	statePath := testTempFile(t)
   704  
   705  	cwd, err := os.Getwd()
   706  	if err != nil {
   707  		t.Fatalf("err: %s", err)
   708  	}
   709  	if err := os.Chdir(varFileDir); err != nil {
   710  		t.Fatalf("err: %s", err)
   711  	}
   712  	defer os.Chdir(cwd)
   713  
   714  	p := testProvider()
   715  	ui := new(cli.MockUi)
   716  	c := &ApplyCommand{
   717  		Meta: Meta{
   718  			testingOverrides: metaOverridesForProvider(p),
   719  			Ui:               ui,
   720  		},
   721  	}
   722  
   723  	args := []string{
   724  		"-state-out", statePath,
   725  		planPath,
   726  	}
   727  	if code := c.Run(args); code != 0 {
   728  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   729  	}
   730  
   731  	if _, err := os.Stat(statePath); err != nil {
   732  		t.Fatalf("err: %s", err)
   733  	}
   734  
   735  	f, err := os.Open(statePath)
   736  	if err != nil {
   737  		t.Fatalf("err: %s", err)
   738  	}
   739  	defer f.Close()
   740  
   741  	state, err := terraform.ReadState(f)
   742  	if err != nil {
   743  		t.Fatalf("err: %s", err)
   744  	}
   745  	if state == nil {
   746  		t.Fatal("state should not be nil")
   747  	}
   748  }
   749  
   750  func TestApply_planVars(t *testing.T) {
   751  	planPath := testPlanFile(t, &terraform.Plan{
   752  		Module: testModule(t, "apply"),
   753  	})
   754  	statePath := testTempFile(t)
   755  
   756  	p := testProvider()
   757  	ui := new(cli.MockUi)
   758  	c := &ApplyCommand{
   759  		Meta: Meta{
   760  			testingOverrides: metaOverridesForProvider(p),
   761  			Ui:               ui,
   762  		},
   763  	}
   764  
   765  	args := []string{
   766  		"-state", statePath,
   767  		"-var", "foo=bar",
   768  		planPath,
   769  	}
   770  	if code := c.Run(args); code == 0 {
   771  		t.Fatal("should've failed")
   772  	}
   773  }
   774  
   775  // we should be able to apply a plan file with no other file dependencies
   776  func TestApply_planNoModuleFiles(t *testing.T) {
   777  	// temporary data directory which we can remove between commands
   778  	td, err := ioutil.TempDir("", "tf")
   779  	if err != nil {
   780  		t.Fatal(err)
   781  	}
   782  	defer os.RemoveAll(td)
   783  
   784  	defer testChdir(t, td)()
   785  
   786  	p := testProvider()
   787  	planFile := testPlanFile(t, &terraform.Plan{
   788  		Module: testModule(t, "apply-plan-no-module"),
   789  	})
   790  
   791  	apply := &ApplyCommand{
   792  		Meta: Meta{
   793  			testingOverrides: metaOverridesForProvider(p),
   794  			Ui:               new(cli.MockUi),
   795  		},
   796  	}
   797  	args := []string{
   798  		planFile,
   799  	}
   800  	apply.Run(args)
   801  	if p.ValidateCalled {
   802  		t.Fatal("Validate should not be called with a plan")
   803  	}
   804  }
   805  
   806  func TestApply_refresh(t *testing.T) {
   807  	originalState := &terraform.State{
   808  		Modules: []*terraform.ModuleState{
   809  			&terraform.ModuleState{
   810  				Path: []string{"root"},
   811  				Resources: map[string]*terraform.ResourceState{
   812  					"test_instance.foo": &terraform.ResourceState{
   813  						Type: "test_instance",
   814  						Primary: &terraform.InstanceState{
   815  							ID: "bar",
   816  						},
   817  					},
   818  				},
   819  			},
   820  		},
   821  	}
   822  
   823  	statePath := testStateFile(t, originalState)
   824  
   825  	p := testProvider()
   826  	ui := new(cli.MockUi)
   827  	c := &ApplyCommand{
   828  		Meta: Meta{
   829  			testingOverrides: metaOverridesForProvider(p),
   830  			Ui:               ui,
   831  		},
   832  	}
   833  
   834  	args := []string{
   835  		"-state", statePath,
   836  		testFixturePath("apply"),
   837  	}
   838  	if code := c.Run(args); code != 0 {
   839  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   840  	}
   841  
   842  	if !p.RefreshCalled {
   843  		t.Fatal("should call refresh")
   844  	}
   845  
   846  	if _, err := os.Stat(statePath); err != nil {
   847  		t.Fatalf("err: %s", err)
   848  	}
   849  
   850  	f, err := os.Open(statePath)
   851  	if err != nil {
   852  		t.Fatalf("err: %s", err)
   853  	}
   854  	defer f.Close()
   855  
   856  	state, err := terraform.ReadState(f)
   857  	if err != nil {
   858  		t.Fatalf("err: %s", err)
   859  	}
   860  	if state == nil {
   861  		t.Fatal("state should not be nil")
   862  	}
   863  
   864  	// Should have a backup file
   865  	f, err = os.Open(statePath + DefaultBackupExtension)
   866  	if err != nil {
   867  		t.Fatalf("err: %s", err)
   868  	}
   869  
   870  	backupState, err := terraform.ReadState(f)
   871  	f.Close()
   872  	if err != nil {
   873  		t.Fatalf("err: %s", err)
   874  	}
   875  
   876  	actualStr := strings.TrimSpace(backupState.String())
   877  	expectedStr := strings.TrimSpace(originalState.String())
   878  	if actualStr != expectedStr {
   879  		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
   880  	}
   881  }
   882  
   883  func TestApply_shutdown(t *testing.T) {
   884  	stopped := false
   885  	stopCh := make(chan struct{})
   886  	stopReplyCh := make(chan struct{})
   887  
   888  	statePath := testTempFile(t)
   889  
   890  	p := testProvider()
   891  	shutdownCh := make(chan struct{})
   892  	ui := new(cli.MockUi)
   893  	c := &ApplyCommand{
   894  		Meta: Meta{
   895  			testingOverrides: metaOverridesForProvider(p),
   896  			Ui:               ui,
   897  		},
   898  
   899  		ShutdownCh: shutdownCh,
   900  	}
   901  
   902  	p.DiffFn = func(
   903  		*terraform.InstanceInfo,
   904  		*terraform.InstanceState,
   905  		*terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   906  		return &terraform.InstanceDiff{
   907  			Attributes: map[string]*terraform.ResourceAttrDiff{
   908  				"ami": &terraform.ResourceAttrDiff{
   909  					New: "bar",
   910  				},
   911  			},
   912  		}, nil
   913  	}
   914  	p.ApplyFn = func(
   915  		*terraform.InstanceInfo,
   916  		*terraform.InstanceState,
   917  		*terraform.InstanceDiff) (*terraform.InstanceState, error) {
   918  		if !stopped {
   919  			stopped = true
   920  			close(stopCh)
   921  			<-stopReplyCh
   922  		}
   923  
   924  		return &terraform.InstanceState{
   925  			ID: "foo",
   926  			Attributes: map[string]string{
   927  				"ami": "2",
   928  			},
   929  		}, nil
   930  	}
   931  
   932  	go func() {
   933  		<-stopCh
   934  		shutdownCh <- struct{}{}
   935  
   936  		// This is really dirty, but we have no other way to assure that
   937  		// tf.Stop() has been called. This doesn't assure it either, but
   938  		// it makes it much more certain.
   939  		time.Sleep(50 * time.Millisecond)
   940  
   941  		close(stopReplyCh)
   942  	}()
   943  
   944  	args := []string{
   945  		"-state", statePath,
   946  		testFixturePath("apply-shutdown"),
   947  	}
   948  	if code := c.Run(args); code != 0 {
   949  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   950  	}
   951  
   952  	if _, err := os.Stat(statePath); err != nil {
   953  		t.Fatalf("err: %s", err)
   954  	}
   955  
   956  	f, err := os.Open(statePath)
   957  	if err != nil {
   958  		t.Fatalf("err: %s", err)
   959  	}
   960  	defer f.Close()
   961  
   962  	state, err := terraform.ReadState(f)
   963  	if err != nil {
   964  		t.Fatalf("err: %s", err)
   965  	}
   966  	if state == nil {
   967  		t.Fatal("state should not be nil")
   968  	}
   969  
   970  	if len(state.RootModule().Resources) != 1 {
   971  		t.Fatalf("bad: %d", len(state.RootModule().Resources))
   972  	}
   973  }
   974  
   975  func TestApply_state(t *testing.T) {
   976  	originalState := &terraform.State{
   977  		Modules: []*terraform.ModuleState{
   978  			&terraform.ModuleState{
   979  				Path: []string{"root"},
   980  				Resources: map[string]*terraform.ResourceState{
   981  					"test_instance.foo": &terraform.ResourceState{
   982  						Type: "test_instance",
   983  						Primary: &terraform.InstanceState{
   984  							ID: "bar",
   985  						},
   986  					},
   987  				},
   988  			},
   989  		},
   990  	}
   991  
   992  	statePath := testStateFile(t, originalState)
   993  
   994  	p := testProvider()
   995  	p.DiffReturn = &terraform.InstanceDiff{
   996  		Attributes: map[string]*terraform.ResourceAttrDiff{
   997  			"ami": &terraform.ResourceAttrDiff{
   998  				New: "bar",
   999  			},
  1000  		},
  1001  	}
  1002  
  1003  	ui := new(cli.MockUi)
  1004  	c := &ApplyCommand{
  1005  		Meta: Meta{
  1006  			testingOverrides: metaOverridesForProvider(p),
  1007  			Ui:               ui,
  1008  		},
  1009  	}
  1010  
  1011  	// Run the apply command pointing to our existing state
  1012  	args := []string{
  1013  		"-state", statePath,
  1014  		testFixturePath("apply"),
  1015  	}
  1016  	if code := c.Run(args); code != 0 {
  1017  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1018  	}
  1019  
  1020  	// Verify that the provider was called with the existing state
  1021  	actual := strings.TrimSpace(p.DiffState.String())
  1022  	expected := strings.TrimSpace(testApplyStateDiffStr)
  1023  	if actual != expected {
  1024  		t.Fatalf("bad:\n\n%s", actual)
  1025  	}
  1026  
  1027  	actual = strings.TrimSpace(p.ApplyState.String())
  1028  	expected = strings.TrimSpace(testApplyStateStr)
  1029  	if actual != expected {
  1030  		t.Fatalf("bad:\n\n%s", actual)
  1031  	}
  1032  
  1033  	// Verify a new state exists
  1034  	if _, err := os.Stat(statePath); err != nil {
  1035  		t.Fatalf("err: %s", err)
  1036  	}
  1037  
  1038  	f, err := os.Open(statePath)
  1039  	if err != nil {
  1040  		t.Fatalf("err: %s", err)
  1041  	}
  1042  	defer f.Close()
  1043  
  1044  	state, err := terraform.ReadState(f)
  1045  	if err != nil {
  1046  		t.Fatalf("err: %s", err)
  1047  	}
  1048  	if state == nil {
  1049  		t.Fatal("state should not be nil")
  1050  	}
  1051  
  1052  	// Should have a backup file
  1053  	f, err = os.Open(statePath + DefaultBackupExtension)
  1054  	if err != nil {
  1055  		t.Fatalf("err: %s", err)
  1056  	}
  1057  
  1058  	backupState, err := terraform.ReadState(f)
  1059  	f.Close()
  1060  	if err != nil {
  1061  		t.Fatalf("err: %s", err)
  1062  	}
  1063  
  1064  	// nil out the ConnInfo since that should not be restored
  1065  	originalState.RootModule().Resources["test_instance.foo"].Primary.Ephemeral.ConnInfo = nil
  1066  
  1067  	actualStr := strings.TrimSpace(backupState.String())
  1068  	expectedStr := strings.TrimSpace(originalState.String())
  1069  	if actualStr != expectedStr {
  1070  		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
  1071  	}
  1072  }
  1073  
  1074  func TestApply_stateNoExist(t *testing.T) {
  1075  	p := testProvider()
  1076  	ui := new(cli.MockUi)
  1077  	c := &ApplyCommand{
  1078  		Meta: Meta{
  1079  			testingOverrides: metaOverridesForProvider(p),
  1080  			Ui:               ui,
  1081  		},
  1082  	}
  1083  
  1084  	args := []string{
  1085  		"idontexist.tfstate",
  1086  		testFixturePath("apply"),
  1087  	}
  1088  	if code := c.Run(args); code != 1 {
  1089  		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
  1090  	}
  1091  }
  1092  
  1093  func TestApply_sensitiveOutput(t *testing.T) {
  1094  	p := testProvider()
  1095  	ui := new(cli.MockUi)
  1096  	c := &ApplyCommand{
  1097  		Meta: Meta{
  1098  			testingOverrides: metaOverridesForProvider(p),
  1099  			Ui:               ui,
  1100  		},
  1101  	}
  1102  
  1103  	statePath := testTempFile(t)
  1104  
  1105  	args := []string{
  1106  		"-state", statePath,
  1107  		testFixturePath("apply-sensitive-output"),
  1108  	}
  1109  
  1110  	if code := c.Run(args); code != 0 {
  1111  		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
  1112  	}
  1113  
  1114  	output := ui.OutputWriter.String()
  1115  	if !strings.Contains(output, "notsensitive = Hello world") {
  1116  		t.Fatalf("bad: output should contain 'notsensitive' output\n%s", output)
  1117  	}
  1118  	if !strings.Contains(output, "sensitive = <sensitive>") {
  1119  		t.Fatalf("bad: output should contain 'sensitive' output\n%s", output)
  1120  	}
  1121  }
  1122  
  1123  func TestApply_stateFuture(t *testing.T) {
  1124  	originalState := testState()
  1125  	originalState.TFVersion = "99.99.99"
  1126  	statePath := testStateFile(t, originalState)
  1127  
  1128  	p := testProvider()
  1129  	ui := new(cli.MockUi)
  1130  	c := &ApplyCommand{
  1131  		Meta: Meta{
  1132  			testingOverrides: metaOverridesForProvider(p),
  1133  			Ui:               ui,
  1134  		},
  1135  	}
  1136  
  1137  	args := []string{
  1138  		"-state", statePath,
  1139  		testFixturePath("apply"),
  1140  	}
  1141  	if code := c.Run(args); code == 0 {
  1142  		t.Fatal("should fail")
  1143  	}
  1144  
  1145  	f, err := os.Open(statePath)
  1146  	if err != nil {
  1147  		t.Fatalf("err: %s", err)
  1148  	}
  1149  
  1150  	newState, err := terraform.ReadState(f)
  1151  	f.Close()
  1152  	if err != nil {
  1153  		t.Fatalf("err: %s", err)
  1154  	}
  1155  
  1156  	if !newState.Equal(originalState) {
  1157  		t.Fatalf("bad: %#v", newState)
  1158  	}
  1159  	if newState.TFVersion != originalState.TFVersion {
  1160  		t.Fatalf("bad: %#v", newState)
  1161  	}
  1162  }
  1163  
  1164  func TestApply_statePast(t *testing.T) {
  1165  	originalState := testState()
  1166  	originalState.TFVersion = "0.1.0"
  1167  	statePath := testStateFile(t, originalState)
  1168  
  1169  	p := testProvider()
  1170  	ui := new(cli.MockUi)
  1171  	c := &ApplyCommand{
  1172  		Meta: Meta{
  1173  			testingOverrides: metaOverridesForProvider(p),
  1174  			Ui:               ui,
  1175  		},
  1176  	}
  1177  
  1178  	args := []string{
  1179  		"-state", statePath,
  1180  		testFixturePath("apply"),
  1181  	}
  1182  	if code := c.Run(args); code != 0 {
  1183  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1184  	}
  1185  }
  1186  
  1187  func TestApply_vars(t *testing.T) {
  1188  	statePath := testTempFile(t)
  1189  
  1190  	p := testProvider()
  1191  	ui := new(cli.MockUi)
  1192  	c := &ApplyCommand{
  1193  		Meta: Meta{
  1194  			testingOverrides: metaOverridesForProvider(p),
  1195  			Ui:               ui,
  1196  		},
  1197  	}
  1198  
  1199  	actual := ""
  1200  	p.DiffFn = func(
  1201  		info *terraform.InstanceInfo,
  1202  		s *terraform.InstanceState,
  1203  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
  1204  		if v, ok := c.Config["value"]; ok {
  1205  			actual = v.(string)
  1206  		}
  1207  
  1208  		return &terraform.InstanceDiff{}, nil
  1209  	}
  1210  
  1211  	args := []string{
  1212  		"-var", "foo=bar",
  1213  		"-state", statePath,
  1214  		testFixturePath("apply-vars"),
  1215  	}
  1216  	if code := c.Run(args); code != 0 {
  1217  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1218  	}
  1219  
  1220  	if actual != "bar" {
  1221  		t.Fatal("didn't work")
  1222  	}
  1223  }
  1224  
  1225  func TestApply_varFile(t *testing.T) {
  1226  	varFilePath := testTempFile(t)
  1227  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
  1228  		t.Fatalf("err: %s", err)
  1229  	}
  1230  
  1231  	statePath := testTempFile(t)
  1232  
  1233  	p := testProvider()
  1234  	ui := new(cli.MockUi)
  1235  	c := &ApplyCommand{
  1236  		Meta: Meta{
  1237  			testingOverrides: metaOverridesForProvider(p),
  1238  			Ui:               ui,
  1239  		},
  1240  	}
  1241  
  1242  	actual := ""
  1243  	p.DiffFn = func(
  1244  		info *terraform.InstanceInfo,
  1245  		s *terraform.InstanceState,
  1246  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
  1247  		if v, ok := c.Config["value"]; ok {
  1248  			actual = v.(string)
  1249  		}
  1250  
  1251  		return &terraform.InstanceDiff{}, nil
  1252  	}
  1253  
  1254  	args := []string{
  1255  		"-var-file", varFilePath,
  1256  		"-state", statePath,
  1257  		testFixturePath("apply-vars"),
  1258  	}
  1259  	if code := c.Run(args); code != 0 {
  1260  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1261  	}
  1262  
  1263  	if actual != "bar" {
  1264  		t.Fatal("didn't work")
  1265  	}
  1266  }
  1267  
  1268  func TestApply_varFileDefault(t *testing.T) {
  1269  	varFileDir := testTempDir(t)
  1270  	varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
  1271  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
  1272  		t.Fatalf("err: %s", err)
  1273  	}
  1274  
  1275  	statePath := testTempFile(t)
  1276  
  1277  	cwd, err := os.Getwd()
  1278  	if err != nil {
  1279  		t.Fatalf("err: %s", err)
  1280  	}
  1281  	if err := os.Chdir(varFileDir); err != nil {
  1282  		t.Fatalf("err: %s", err)
  1283  	}
  1284  	defer os.Chdir(cwd)
  1285  
  1286  	p := testProvider()
  1287  	ui := new(cli.MockUi)
  1288  	c := &ApplyCommand{
  1289  		Meta: Meta{
  1290  			testingOverrides: metaOverridesForProvider(p),
  1291  			Ui:               ui,
  1292  		},
  1293  	}
  1294  
  1295  	actual := ""
  1296  	p.DiffFn = func(
  1297  		info *terraform.InstanceInfo,
  1298  		s *terraform.InstanceState,
  1299  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
  1300  		if v, ok := c.Config["value"]; ok {
  1301  			actual = v.(string)
  1302  		}
  1303  
  1304  		return &terraform.InstanceDiff{}, nil
  1305  	}
  1306  
  1307  	args := []string{
  1308  		"-state", statePath,
  1309  		testFixturePath("apply-vars"),
  1310  	}
  1311  	if code := c.Run(args); code != 0 {
  1312  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1313  	}
  1314  
  1315  	if actual != "bar" {
  1316  		t.Fatal("didn't work")
  1317  	}
  1318  }
  1319  
  1320  func TestApply_varFileDefaultJSON(t *testing.T) {
  1321  	varFileDir := testTempDir(t)
  1322  	varFilePath := filepath.Join(varFileDir, "terraform.tfvars.json")
  1323  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFileJSON), 0644); err != nil {
  1324  		t.Fatalf("err: %s", err)
  1325  	}
  1326  
  1327  	statePath := testTempFile(t)
  1328  
  1329  	cwd, err := os.Getwd()
  1330  	if err != nil {
  1331  		t.Fatalf("err: %s", err)
  1332  	}
  1333  	if err := os.Chdir(varFileDir); err != nil {
  1334  		t.Fatalf("err: %s", err)
  1335  	}
  1336  	defer os.Chdir(cwd)
  1337  
  1338  	p := testProvider()
  1339  	ui := new(cli.MockUi)
  1340  	c := &ApplyCommand{
  1341  		Meta: Meta{
  1342  			testingOverrides: metaOverridesForProvider(p),
  1343  			Ui:               ui,
  1344  		},
  1345  	}
  1346  
  1347  	actual := ""
  1348  	p.DiffFn = func(
  1349  		info *terraform.InstanceInfo,
  1350  		s *terraform.InstanceState,
  1351  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
  1352  		if v, ok := c.Config["value"]; ok {
  1353  			actual = v.(string)
  1354  		}
  1355  
  1356  		return &terraform.InstanceDiff{}, nil
  1357  	}
  1358  
  1359  	args := []string{
  1360  		"-state", statePath,
  1361  		testFixturePath("apply-vars"),
  1362  	}
  1363  	if code := c.Run(args); code != 0 {
  1364  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1365  	}
  1366  
  1367  	if actual != "bar" {
  1368  		t.Fatal("didn't work")
  1369  	}
  1370  }
  1371  
  1372  func TestApply_backup(t *testing.T) {
  1373  	originalState := &terraform.State{
  1374  		Modules: []*terraform.ModuleState{
  1375  			&terraform.ModuleState{
  1376  				Path: []string{"root"},
  1377  				Resources: map[string]*terraform.ResourceState{
  1378  					"test_instance.foo": &terraform.ResourceState{
  1379  						Type: "test_instance",
  1380  						Primary: &terraform.InstanceState{
  1381  							ID: "bar",
  1382  						},
  1383  					},
  1384  				},
  1385  			},
  1386  		},
  1387  	}
  1388  	originalState.Init()
  1389  
  1390  	statePath := testStateFile(t, originalState)
  1391  	backupPath := testTempFile(t)
  1392  
  1393  	p := testProvider()
  1394  	p.DiffReturn = &terraform.InstanceDiff{
  1395  		Attributes: map[string]*terraform.ResourceAttrDiff{
  1396  			"ami": &terraform.ResourceAttrDiff{
  1397  				New: "bar",
  1398  			},
  1399  		},
  1400  	}
  1401  
  1402  	ui := new(cli.MockUi)
  1403  	c := &ApplyCommand{
  1404  		Meta: Meta{
  1405  			testingOverrides: metaOverridesForProvider(p),
  1406  			Ui:               ui,
  1407  		},
  1408  	}
  1409  
  1410  	// Run the apply command pointing to our existing state
  1411  	args := []string{
  1412  		"-state", statePath,
  1413  		"-backup", backupPath,
  1414  		testFixturePath("apply"),
  1415  	}
  1416  	if code := c.Run(args); code != 0 {
  1417  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1418  	}
  1419  
  1420  	// Verify a new state exists
  1421  	if _, err := os.Stat(statePath); err != nil {
  1422  		t.Fatalf("err: %s", err)
  1423  	}
  1424  
  1425  	f, err := os.Open(statePath)
  1426  	if err != nil {
  1427  		t.Fatalf("err: %s", err)
  1428  	}
  1429  	defer f.Close()
  1430  
  1431  	state, err := terraform.ReadState(f)
  1432  	if err != nil {
  1433  		t.Fatalf("err: %s", err)
  1434  	}
  1435  	if state == nil {
  1436  		t.Fatal("state should not be nil")
  1437  	}
  1438  
  1439  	// Should have a backup file
  1440  	f, err = os.Open(backupPath)
  1441  	if err != nil {
  1442  		t.Fatalf("err: %s", err)
  1443  	}
  1444  
  1445  	backupState, err := terraform.ReadState(f)
  1446  	f.Close()
  1447  	if err != nil {
  1448  		t.Fatalf("err: %s", err)
  1449  	}
  1450  
  1451  	actual := backupState.RootModule().Resources["test_instance.foo"]
  1452  	expected := originalState.RootModule().Resources["test_instance.foo"]
  1453  	if !reflect.DeepEqual(actual, expected) {
  1454  		t.Fatalf("bad: %#v %#v", actual, expected)
  1455  	}
  1456  }
  1457  
  1458  func TestApply_disableBackup(t *testing.T) {
  1459  	originalState := testState()
  1460  	statePath := testStateFile(t, originalState)
  1461  
  1462  	p := testProvider()
  1463  	p.DiffReturn = &terraform.InstanceDiff{
  1464  		Attributes: map[string]*terraform.ResourceAttrDiff{
  1465  			"ami": &terraform.ResourceAttrDiff{
  1466  				New: "bar",
  1467  			},
  1468  		},
  1469  	}
  1470  
  1471  	ui := new(cli.MockUi)
  1472  	c := &ApplyCommand{
  1473  		Meta: Meta{
  1474  			testingOverrides: metaOverridesForProvider(p),
  1475  			Ui:               ui,
  1476  		},
  1477  	}
  1478  
  1479  	// Run the apply command pointing to our existing state
  1480  	args := []string{
  1481  		"-state", statePath,
  1482  		"-backup", "-",
  1483  		testFixturePath("apply"),
  1484  	}
  1485  	if code := c.Run(args); code != 0 {
  1486  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1487  	}
  1488  
  1489  	// Verify that the provider was called with the existing state
  1490  	actual := strings.TrimSpace(p.DiffState.String())
  1491  	expected := strings.TrimSpace(testApplyDisableBackupStr)
  1492  	if actual != expected {
  1493  		t.Fatalf("bad:\n\n%s", actual)
  1494  	}
  1495  
  1496  	actual = strings.TrimSpace(p.ApplyState.String())
  1497  	expected = strings.TrimSpace(testApplyDisableBackupStateStr)
  1498  	if actual != expected {
  1499  		t.Fatalf("bad:\n\n%s", actual)
  1500  	}
  1501  
  1502  	// Verify a new state exists
  1503  	if _, err := os.Stat(statePath); err != nil {
  1504  		t.Fatalf("err: %s", err)
  1505  	}
  1506  
  1507  	f, err := os.Open(statePath)
  1508  	if err != nil {
  1509  		t.Fatalf("err: %s", err)
  1510  	}
  1511  	defer f.Close()
  1512  
  1513  	state, err := terraform.ReadState(f)
  1514  	if err != nil {
  1515  		t.Fatalf("err: %s", err)
  1516  	}
  1517  	if state == nil {
  1518  		t.Fatal("state should not be nil")
  1519  	}
  1520  
  1521  	// Ensure there is no backup
  1522  	_, err = os.Stat(statePath + DefaultBackupExtension)
  1523  	if err == nil || !os.IsNotExist(err) {
  1524  		t.Fatalf("backup should not exist")
  1525  	}
  1526  
  1527  	// Ensure there is no literal "-"
  1528  	_, err = os.Stat("-")
  1529  	if err == nil || !os.IsNotExist(err) {
  1530  		t.Fatalf("backup should not exist")
  1531  	}
  1532  }
  1533  
  1534  // Test that the Terraform env is passed through
  1535  func TestApply_terraformEnv(t *testing.T) {
  1536  	statePath := testTempFile(t)
  1537  
  1538  	p := testProvider()
  1539  	ui := new(cli.MockUi)
  1540  	c := &ApplyCommand{
  1541  		Meta: Meta{
  1542  			testingOverrides: metaOverridesForProvider(p),
  1543  			Ui:               ui,
  1544  		},
  1545  	}
  1546  
  1547  	args := []string{
  1548  		"-state", statePath,
  1549  		testFixturePath("apply-terraform-env"),
  1550  	}
  1551  	if code := c.Run(args); code != 0 {
  1552  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1553  	}
  1554  
  1555  	expected := strings.TrimSpace(`
  1556  <no state>
  1557  Outputs:
  1558  
  1559  output = default
  1560  	`)
  1561  	testStateOutput(t, statePath, expected)
  1562  }
  1563  
  1564  // Test that the Terraform env is passed through
  1565  func TestApply_terraformEnvNonDefault(t *testing.T) {
  1566  	// Create a temporary working directory that is empty
  1567  	td := tempDir(t)
  1568  	os.MkdirAll(td, 0755)
  1569  	defer os.RemoveAll(td)
  1570  	defer testChdir(t, td)()
  1571  
  1572  	// Create new env
  1573  	{
  1574  		ui := new(cli.MockUi)
  1575  		newCmd := &WorkspaceNewCommand{}
  1576  		newCmd.Meta = Meta{Ui: ui}
  1577  		if code := newCmd.Run([]string{"test"}); code != 0 {
  1578  			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
  1579  		}
  1580  	}
  1581  
  1582  	// Switch to it
  1583  	{
  1584  		args := []string{"test"}
  1585  		ui := new(cli.MockUi)
  1586  		selCmd := &WorkspaceSelectCommand{}
  1587  		selCmd.Meta = Meta{Ui: ui}
  1588  		if code := selCmd.Run(args); code != 0 {
  1589  			t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
  1590  		}
  1591  	}
  1592  
  1593  	p := testProvider()
  1594  	ui := new(cli.MockUi)
  1595  	c := &ApplyCommand{
  1596  		Meta: Meta{
  1597  			testingOverrides: metaOverridesForProvider(p),
  1598  			Ui:               ui,
  1599  		},
  1600  	}
  1601  
  1602  	args := []string{
  1603  		testFixturePath("apply-terraform-env"),
  1604  	}
  1605  	if code := c.Run(args); code != 0 {
  1606  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
  1607  	}
  1608  
  1609  	statePath := filepath.Join("terraform.tfstate.d", "test", "terraform.tfstate")
  1610  	expected := strings.TrimSpace(`
  1611  <no state>
  1612  Outputs:
  1613  
  1614  output = test
  1615  	`)
  1616  	testStateOutput(t, statePath, expected)
  1617  }
  1618  
  1619  func testHttpServer(t *testing.T) net.Listener {
  1620  	ln, err := net.Listen("tcp", "127.0.0.1:0")
  1621  	if err != nil {
  1622  		t.Fatalf("err: %s", err)
  1623  	}
  1624  
  1625  	mux := http.NewServeMux()
  1626  	mux.HandleFunc("/header", testHttpHandlerHeader)
  1627  
  1628  	var server http.Server
  1629  	server.Handler = mux
  1630  	go server.Serve(ln)
  1631  
  1632  	return ln
  1633  }
  1634  
  1635  func testHttpHandlerHeader(w http.ResponseWriter, r *http.Request) {
  1636  	var url url.URL
  1637  	url.Scheme = "file"
  1638  	url.Path = filepath.ToSlash(testFixturePath("init"))
  1639  
  1640  	w.Header().Add("X-Terraform-Get", url.String())
  1641  	w.WriteHeader(200)
  1642  }
  1643  
  1644  const applyVarFile = `
  1645  foo = "bar"
  1646  `
  1647  
  1648  const applyVarFileJSON = `
  1649  { "foo": "bar" }
  1650  `
  1651  
  1652  const testApplyDisableBackupStr = `
  1653  ID = bar
  1654  Tainted = false
  1655  `
  1656  
  1657  const testApplyDisableBackupStateStr = `
  1658  ID = bar
  1659  Tainted = false
  1660  `
  1661  
  1662  const testApplyStateStr = `
  1663  ID = bar
  1664  Tainted = false
  1665  `
  1666  
  1667  const testApplyStateDiffStr = `
  1668  ID = bar
  1669  Tainted = false
  1670  `