github.com/ricardclau/terraform@v0.6.17-0.20160519222547-283e3ae6b5a9/command/plan_test.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/hashicorp/terraform/terraform"
    12  	"github.com/mitchellh/cli"
    13  )
    14  
    15  func TestPlan(t *testing.T) {
    16  	cwd, err := os.Getwd()
    17  	if err != nil {
    18  		t.Fatalf("err: %s", err)
    19  	}
    20  	if err := os.Chdir(testFixturePath("plan")); err != nil {
    21  		t.Fatalf("err: %s", err)
    22  	}
    23  	defer os.Chdir(cwd)
    24  
    25  	p := testProvider()
    26  	ui := new(cli.MockUi)
    27  	c := &PlanCommand{
    28  		Meta: Meta{
    29  			ContextOpts: testCtxConfig(p),
    30  			Ui:          ui,
    31  		},
    32  	}
    33  
    34  	args := []string{}
    35  	if code := c.Run(args); code != 0 {
    36  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    37  	}
    38  }
    39  
    40  func TestPlan_destroy(t *testing.T) {
    41  	originalState := &terraform.State{
    42  		Modules: []*terraform.ModuleState{
    43  			&terraform.ModuleState{
    44  				Path: []string{"root"},
    45  				Resources: map[string]*terraform.ResourceState{
    46  					"test_instance.foo": &terraform.ResourceState{
    47  						Type: "test_instance",
    48  						Primary: &terraform.InstanceState{
    49  							ID: "bar",
    50  						},
    51  					},
    52  				},
    53  			},
    54  		},
    55  	}
    56  
    57  	outPath := testTempFile(t)
    58  	statePath := testStateFile(t, originalState)
    59  
    60  	p := testProvider()
    61  	ui := new(cli.MockUi)
    62  	c := &PlanCommand{
    63  		Meta: Meta{
    64  			ContextOpts: testCtxConfig(p),
    65  			Ui:          ui,
    66  		},
    67  	}
    68  
    69  	args := []string{
    70  		"-destroy",
    71  		"-out", outPath,
    72  		"-state", statePath,
    73  		testFixturePath("plan"),
    74  	}
    75  	if code := c.Run(args); code != 0 {
    76  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    77  	}
    78  
    79  	if !p.RefreshCalled {
    80  		t.Fatal("refresh should be called")
    81  	}
    82  
    83  	plan := testReadPlan(t, outPath)
    84  	for _, m := range plan.Diff.Modules {
    85  		for _, r := range m.Resources {
    86  			if !r.Destroy {
    87  				t.Fatalf("bad: %#v", r)
    88  			}
    89  		}
    90  	}
    91  
    92  	f, err := os.Open(statePath + DefaultBackupExtension)
    93  	if err != nil {
    94  		t.Fatalf("err: %s", err)
    95  	}
    96  
    97  	backupState, err := terraform.ReadState(f)
    98  	f.Close()
    99  	if err != nil {
   100  		t.Fatalf("err: %s", err)
   101  	}
   102  
   103  	actualStr := strings.TrimSpace(backupState.String())
   104  	expectedStr := strings.TrimSpace(originalState.String())
   105  	if actualStr != expectedStr {
   106  		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
   107  	}
   108  }
   109  
   110  func TestPlan_noState(t *testing.T) {
   111  	tmp, cwd := testCwd(t)
   112  	defer testFixCwd(t, tmp, cwd)
   113  
   114  	p := testProvider()
   115  	ui := new(cli.MockUi)
   116  	c := &PlanCommand{
   117  		Meta: Meta{
   118  			ContextOpts: testCtxConfig(p),
   119  			Ui:          ui,
   120  		},
   121  	}
   122  
   123  	args := []string{
   124  		testFixturePath("plan"),
   125  	}
   126  	if code := c.Run(args); code != 0 {
   127  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   128  	}
   129  
   130  	// Verify that refresh was called
   131  	if p.RefreshCalled {
   132  		t.Fatal("refresh should not be called")
   133  	}
   134  
   135  	// Verify that the provider was called with the existing state
   136  	actual := strings.TrimSpace(p.DiffState.String())
   137  	expected := strings.TrimSpace(testPlanNoStateStr)
   138  	if actual != expected {
   139  		t.Fatalf("bad:\n\n%s", actual)
   140  	}
   141  }
   142  
   143  func TestPlan_outPath(t *testing.T) {
   144  	tf, err := ioutil.TempFile("", "tf")
   145  	if err != nil {
   146  		t.Fatalf("err: %s", err)
   147  	}
   148  	outPath := tf.Name()
   149  	os.Remove(tf.Name())
   150  
   151  	p := testProvider()
   152  	ui := new(cli.MockUi)
   153  	c := &PlanCommand{
   154  		Meta: Meta{
   155  			ContextOpts: testCtxConfig(p),
   156  			Ui:          ui,
   157  		},
   158  	}
   159  
   160  	p.DiffReturn = &terraform.InstanceDiff{
   161  		Destroy: true,
   162  	}
   163  
   164  	args := []string{
   165  		"-out", outPath,
   166  		testFixturePath("plan"),
   167  	}
   168  	if code := c.Run(args); code != 0 {
   169  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   170  	}
   171  
   172  	f, err := os.Open(outPath)
   173  	if err != nil {
   174  		t.Fatalf("err: %s", err)
   175  	}
   176  	defer f.Close()
   177  
   178  	if _, err := terraform.ReadPlan(f); err != nil {
   179  		t.Fatalf("err: %s", err)
   180  	}
   181  }
   182  
   183  func TestPlan_outPathNoChange(t *testing.T) {
   184  	originalState := &terraform.State{
   185  		Modules: []*terraform.ModuleState{
   186  			&terraform.ModuleState{
   187  				Path: []string{"root"},
   188  				Resources: map[string]*terraform.ResourceState{
   189  					"test_instance.foo": &terraform.ResourceState{
   190  						Type: "test_instance",
   191  						Primary: &terraform.InstanceState{
   192  							ID: "bar",
   193  						},
   194  					},
   195  				},
   196  			},
   197  		},
   198  	}
   199  	statePath := testStateFile(t, originalState)
   200  
   201  	tf, err := ioutil.TempFile("", "tf")
   202  	if err != nil {
   203  		t.Fatalf("err: %s", err)
   204  	}
   205  	outPath := tf.Name()
   206  	os.Remove(tf.Name())
   207  
   208  	p := testProvider()
   209  	ui := new(cli.MockUi)
   210  	c := &PlanCommand{
   211  		Meta: Meta{
   212  			ContextOpts: testCtxConfig(p),
   213  			Ui:          ui,
   214  		},
   215  	}
   216  
   217  	args := []string{
   218  		"-out", outPath,
   219  		"-state", statePath,
   220  		testFixturePath("plan"),
   221  	}
   222  	if code := c.Run(args); code != 0 {
   223  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   224  	}
   225  
   226  	plan := testReadPlan(t, outPath)
   227  	if !plan.Diff.Empty() {
   228  		t.Fatalf("Expected empty plan to be written to plan file, got: %s", plan)
   229  	}
   230  }
   231  
   232  func TestPlan_refresh(t *testing.T) {
   233  	p := testProvider()
   234  	ui := new(cli.MockUi)
   235  	c := &PlanCommand{
   236  		Meta: Meta{
   237  			ContextOpts: testCtxConfig(p),
   238  			Ui:          ui,
   239  		},
   240  	}
   241  
   242  	args := []string{
   243  		"-refresh=false",
   244  		testFixturePath("plan"),
   245  	}
   246  	if code := c.Run(args); code != 0 {
   247  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   248  	}
   249  
   250  	if p.RefreshCalled {
   251  		t.Fatal("refresh should not be called")
   252  	}
   253  }
   254  
   255  func TestPlan_state(t *testing.T) {
   256  	// Write out some prior state
   257  	tf, err := ioutil.TempFile("", "tf")
   258  	if err != nil {
   259  		t.Fatalf("err: %s", err)
   260  	}
   261  	statePath := tf.Name()
   262  	defer os.Remove(tf.Name())
   263  
   264  	originalState := testState()
   265  	err = terraform.WriteState(originalState, tf)
   266  	tf.Close()
   267  	if err != nil {
   268  		t.Fatalf("err: %s", err)
   269  	}
   270  
   271  	p := testProvider()
   272  	ui := new(cli.MockUi)
   273  	c := &PlanCommand{
   274  		Meta: Meta{
   275  			ContextOpts: testCtxConfig(p),
   276  			Ui:          ui,
   277  		},
   278  	}
   279  
   280  	args := []string{
   281  		"-state", statePath,
   282  		testFixturePath("plan"),
   283  	}
   284  	if code := c.Run(args); code != 0 {
   285  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   286  	}
   287  
   288  	// Verify that the provider was called with the existing state
   289  	actual := strings.TrimSpace(p.DiffState.String())
   290  	expected := strings.TrimSpace(testPlanStateStr)
   291  	if actual != expected {
   292  		t.Fatalf("bad:\n\n%s", actual)
   293  	}
   294  }
   295  
   296  func TestPlan_stateDefault(t *testing.T) {
   297  	originalState := testState()
   298  
   299  	// Write the state file in a temporary directory with the
   300  	// default filename.
   301  	td, err := ioutil.TempDir("", "tf")
   302  	if err != nil {
   303  		t.Fatalf("err: %s", err)
   304  	}
   305  	statePath := filepath.Join(td, DefaultStateFilename)
   306  
   307  	f, err := os.Create(statePath)
   308  	if err != nil {
   309  		t.Fatalf("err: %s", err)
   310  	}
   311  	err = terraform.WriteState(originalState, f)
   312  	f.Close()
   313  	if err != nil {
   314  		t.Fatalf("err: %s", err)
   315  	}
   316  
   317  	// Change to that directory
   318  	cwd, err := os.Getwd()
   319  	if err != nil {
   320  		t.Fatalf("err: %s", err)
   321  	}
   322  	if err := os.Chdir(filepath.Dir(statePath)); err != nil {
   323  		t.Fatalf("err: %s", err)
   324  	}
   325  	defer os.Chdir(cwd)
   326  
   327  	p := testProvider()
   328  	ui := new(cli.MockUi)
   329  	c := &PlanCommand{
   330  		Meta: Meta{
   331  			ContextOpts: testCtxConfig(p),
   332  			Ui:          ui,
   333  		},
   334  	}
   335  
   336  	args := []string{
   337  		testFixturePath("plan"),
   338  	}
   339  	if code := c.Run(args); code != 0 {
   340  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   341  	}
   342  
   343  	// Verify that the provider was called with the existing state
   344  	actual := strings.TrimSpace(p.DiffState.String())
   345  	expected := strings.TrimSpace(testPlanStateDefaultStr)
   346  	if actual != expected {
   347  		t.Fatalf("bad:\n\n%s", actual)
   348  	}
   349  }
   350  
   351  func TestPlan_stateFuture(t *testing.T) {
   352  	originalState := testState()
   353  	originalState.TFVersion = "99.99.99"
   354  	statePath := testStateFile(t, originalState)
   355  
   356  	p := testProvider()
   357  	ui := new(cli.MockUi)
   358  	c := &PlanCommand{
   359  		Meta: Meta{
   360  			ContextOpts: testCtxConfig(p),
   361  			Ui:          ui,
   362  		},
   363  	}
   364  
   365  	args := []string{
   366  		"-state", statePath,
   367  		testFixturePath("plan"),
   368  	}
   369  	if code := c.Run(args); code == 0 {
   370  		t.Fatal("should fail")
   371  	}
   372  
   373  	f, err := os.Open(statePath)
   374  	if err != nil {
   375  		t.Fatalf("err: %s", err)
   376  	}
   377  
   378  	newState, err := terraform.ReadState(f)
   379  	f.Close()
   380  	if err != nil {
   381  		t.Fatalf("err: %s", err)
   382  	}
   383  
   384  	if !newState.Equal(originalState) {
   385  		t.Fatalf("bad: %#v", newState)
   386  	}
   387  	if newState.TFVersion != originalState.TFVersion {
   388  		t.Fatalf("bad: %#v", newState)
   389  	}
   390  }
   391  
   392  func TestPlan_statePast(t *testing.T) {
   393  	originalState := testState()
   394  	originalState.TFVersion = "0.1.0"
   395  	statePath := testStateFile(t, originalState)
   396  
   397  	p := testProvider()
   398  	ui := new(cli.MockUi)
   399  	c := &PlanCommand{
   400  		Meta: Meta{
   401  			ContextOpts: testCtxConfig(p),
   402  			Ui:          ui,
   403  		},
   404  	}
   405  
   406  	args := []string{
   407  		"-state", statePath,
   408  		testFixturePath("plan"),
   409  	}
   410  	if code := c.Run(args); code != 0 {
   411  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   412  	}
   413  }
   414  
   415  func TestPlan_vars(t *testing.T) {
   416  	p := testProvider()
   417  	ui := new(cli.MockUi)
   418  	c := &PlanCommand{
   419  		Meta: Meta{
   420  			ContextOpts: testCtxConfig(p),
   421  			Ui:          ui,
   422  		},
   423  	}
   424  
   425  	actual := ""
   426  	p.DiffFn = func(
   427  		info *terraform.InstanceInfo,
   428  		s *terraform.InstanceState,
   429  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   430  		if v, ok := c.Config["value"]; ok {
   431  			actual = v.(string)
   432  		}
   433  
   434  		return nil, nil
   435  	}
   436  
   437  	args := []string{
   438  		"-var", "foo=bar",
   439  		testFixturePath("plan-vars"),
   440  	}
   441  	if code := c.Run(args); code != 0 {
   442  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   443  	}
   444  
   445  	if actual != "bar" {
   446  		t.Fatal("didn't work")
   447  	}
   448  }
   449  
   450  func TestPlan_varsUnset(t *testing.T) {
   451  	// Disable test mode so input would be asked
   452  	test = false
   453  	defer func() { test = true }()
   454  
   455  	defaultInputReader = bytes.NewBufferString("bar\n")
   456  
   457  	p := testProvider()
   458  	ui := new(cli.MockUi)
   459  	c := &PlanCommand{
   460  		Meta: Meta{
   461  			ContextOpts: testCtxConfig(p),
   462  			Ui:          ui,
   463  		},
   464  	}
   465  
   466  	args := []string{
   467  		testFixturePath("plan-vars"),
   468  	}
   469  	if code := c.Run(args); code != 0 {
   470  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   471  	}
   472  }
   473  
   474  func TestPlan_varFile(t *testing.T) {
   475  	varFilePath := testTempFile(t)
   476  	if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil {
   477  		t.Fatalf("err: %s", err)
   478  	}
   479  
   480  	p := testProvider()
   481  	ui := new(cli.MockUi)
   482  	c := &PlanCommand{
   483  		Meta: Meta{
   484  			ContextOpts: testCtxConfig(p),
   485  			Ui:          ui,
   486  		},
   487  	}
   488  
   489  	actual := ""
   490  	p.DiffFn = func(
   491  		info *terraform.InstanceInfo,
   492  		s *terraform.InstanceState,
   493  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   494  		if v, ok := c.Config["value"]; ok {
   495  			actual = v.(string)
   496  		}
   497  
   498  		return nil, nil
   499  	}
   500  
   501  	args := []string{
   502  		"-var-file", varFilePath,
   503  		testFixturePath("plan-vars"),
   504  	}
   505  	if code := c.Run(args); code != 0 {
   506  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   507  	}
   508  
   509  	if actual != "bar" {
   510  		t.Fatal("didn't work")
   511  	}
   512  }
   513  
   514  func TestPlan_varFileDefault(t *testing.T) {
   515  	varFileDir := testTempDir(t)
   516  	varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
   517  	if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil {
   518  		t.Fatalf("err: %s", err)
   519  	}
   520  
   521  	cwd, err := os.Getwd()
   522  	if err != nil {
   523  		t.Fatalf("err: %s", err)
   524  	}
   525  	if err := os.Chdir(varFileDir); err != nil {
   526  		t.Fatalf("err: %s", err)
   527  	}
   528  	defer os.Chdir(cwd)
   529  
   530  	p := testProvider()
   531  	ui := new(cli.MockUi)
   532  	c := &PlanCommand{
   533  		Meta: Meta{
   534  			ContextOpts: testCtxConfig(p),
   535  			Ui:          ui,
   536  		},
   537  	}
   538  
   539  	actual := ""
   540  	p.DiffFn = func(
   541  		info *terraform.InstanceInfo,
   542  		s *terraform.InstanceState,
   543  		c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   544  		if v, ok := c.Config["value"]; ok {
   545  			actual = v.(string)
   546  		}
   547  
   548  		return nil, nil
   549  	}
   550  
   551  	args := []string{
   552  		testFixturePath("plan-vars"),
   553  	}
   554  	if code := c.Run(args); code != 0 {
   555  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   556  	}
   557  
   558  	if actual != "bar" {
   559  		t.Fatal("didn't work")
   560  	}
   561  }
   562  
   563  func TestPlan_backup(t *testing.T) {
   564  	// Write out some prior state
   565  	tf, err := ioutil.TempFile("", "tf")
   566  	if err != nil {
   567  		t.Fatalf("err: %s", err)
   568  	}
   569  	statePath := tf.Name()
   570  	defer os.Remove(tf.Name())
   571  
   572  	// Write out some prior state
   573  	backupf, err := ioutil.TempFile("", "tf")
   574  	if err != nil {
   575  		t.Fatalf("err: %s", err)
   576  	}
   577  	backupPath := backupf.Name()
   578  	backupf.Close()
   579  	os.Remove(backupPath)
   580  	defer os.Remove(backupPath)
   581  
   582  	originalState := &terraform.State{
   583  		Modules: []*terraform.ModuleState{
   584  			&terraform.ModuleState{
   585  				Path: []string{"root"},
   586  				Resources: map[string]*terraform.ResourceState{
   587  					"test_instance.foo": &terraform.ResourceState{
   588  						Type: "test_instance",
   589  						Primary: &terraform.InstanceState{
   590  							ID: "bar",
   591  						},
   592  					},
   593  				},
   594  			},
   595  		},
   596  	}
   597  
   598  	err = terraform.WriteState(originalState, tf)
   599  	tf.Close()
   600  	if err != nil {
   601  		t.Fatalf("err: %s", err)
   602  	}
   603  
   604  	p := testProvider()
   605  	ui := new(cli.MockUi)
   606  	c := &PlanCommand{
   607  		Meta: Meta{
   608  			ContextOpts: testCtxConfig(p),
   609  			Ui:          ui,
   610  		},
   611  	}
   612  
   613  	args := []string{
   614  		"-state", statePath,
   615  		"-backup", backupPath,
   616  		testFixturePath("plan"),
   617  	}
   618  	if code := c.Run(args); code != 0 {
   619  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   620  	}
   621  
   622  	// Verify that the provider was called with the existing state
   623  	actual := strings.TrimSpace(p.DiffState.String())
   624  	expected := strings.TrimSpace(testPlanBackupStr)
   625  	if actual != expected {
   626  		t.Fatalf("bad:\n\n%s", actual)
   627  	}
   628  
   629  	// Verify the backup exist
   630  	f, err := os.Open(backupPath)
   631  	if err != nil {
   632  		t.Fatalf("err: %s", err)
   633  	}
   634  
   635  	backupState, err := terraform.ReadState(f)
   636  	f.Close()
   637  	if err != nil {
   638  		t.Fatalf("err: %s", err)
   639  	}
   640  
   641  	actualStr := strings.TrimSpace(backupState.String())
   642  	expectedStr := strings.TrimSpace(originalState.String())
   643  	if actualStr != expectedStr {
   644  		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
   645  	}
   646  }
   647  
   648  func TestPlan_disableBackup(t *testing.T) {
   649  	// Write out some prior state
   650  	tf, err := ioutil.TempFile("", "tf")
   651  	if err != nil {
   652  		t.Fatalf("err: %s", err)
   653  	}
   654  	statePath := tf.Name()
   655  	defer os.Remove(tf.Name())
   656  
   657  	originalState := &terraform.State{
   658  		Modules: []*terraform.ModuleState{
   659  			&terraform.ModuleState{
   660  				Path: []string{"root"},
   661  				Resources: map[string]*terraform.ResourceState{
   662  					"test_instance.foo": &terraform.ResourceState{
   663  						Type: "test_instance",
   664  						Primary: &terraform.InstanceState{
   665  							ID: "bar",
   666  						},
   667  					},
   668  				},
   669  			},
   670  		},
   671  	}
   672  
   673  	err = terraform.WriteState(originalState, tf)
   674  	tf.Close()
   675  	if err != nil {
   676  		t.Fatalf("err: %s", err)
   677  	}
   678  
   679  	p := testProvider()
   680  	ui := new(cli.MockUi)
   681  	c := &PlanCommand{
   682  		Meta: Meta{
   683  			ContextOpts: testCtxConfig(p),
   684  			Ui:          ui,
   685  		},
   686  	}
   687  
   688  	args := []string{
   689  		"-state", statePath,
   690  		"-backup", "-",
   691  		testFixturePath("plan"),
   692  	}
   693  	if code := c.Run(args); code != 0 {
   694  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   695  	}
   696  
   697  	// Verify that the provider was called with the existing state
   698  	actual := strings.TrimSpace(p.DiffState.String())
   699  	expected := strings.TrimSpace(testPlanDisableBackupStr)
   700  	if actual != expected {
   701  		t.Fatalf("bad:\n\n%s", actual)
   702  	}
   703  
   704  	// Ensure there is no backup
   705  	_, err = os.Stat(statePath + DefaultBackupExtension)
   706  	if err == nil || !os.IsNotExist(err) {
   707  		t.Fatalf("backup should not exist")
   708  	}
   709  }
   710  
   711  func TestPlan_detailedExitcode(t *testing.T) {
   712  	cwd, err := os.Getwd()
   713  	if err != nil {
   714  		t.Fatalf("err: %s", err)
   715  	}
   716  	if err := os.Chdir(testFixturePath("plan")); err != nil {
   717  		t.Fatalf("err: %s", err)
   718  	}
   719  	defer os.Chdir(cwd)
   720  
   721  	p := testProvider()
   722  	ui := new(cli.MockUi)
   723  	c := &PlanCommand{
   724  		Meta: Meta{
   725  			ContextOpts: testCtxConfig(p),
   726  			Ui:          ui,
   727  		},
   728  	}
   729  
   730  	args := []string{"-detailed-exitcode"}
   731  	if code := c.Run(args); code != 2 {
   732  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   733  	}
   734  }
   735  
   736  func TestPlan_detailedExitcode_emptyDiff(t *testing.T) {
   737  	cwd, err := os.Getwd()
   738  	if err != nil {
   739  		t.Fatalf("err: %s", err)
   740  	}
   741  	if err := os.Chdir(testFixturePath("plan-emptydiff")); err != nil {
   742  		t.Fatalf("err: %s", err)
   743  	}
   744  	defer os.Chdir(cwd)
   745  
   746  	p := testProvider()
   747  	ui := new(cli.MockUi)
   748  	c := &PlanCommand{
   749  		Meta: Meta{
   750  			ContextOpts: testCtxConfig(p),
   751  			Ui:          ui,
   752  		},
   753  	}
   754  
   755  	args := []string{"-detailed-exitcode"}
   756  	if code := c.Run(args); code != 0 {
   757  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   758  	}
   759  }
   760  
   761  const planVarFile = `
   762  foo = "bar"
   763  `
   764  
   765  const testPlanBackupStr = `
   766  ID = bar
   767  `
   768  
   769  const testPlanDisableBackupStr = `
   770  ID = bar
   771  `
   772  
   773  const testPlanNoStateStr = `
   774  <not created>
   775  `
   776  
   777  const testPlanStateStr = `
   778  ID = bar
   779  `
   780  
   781  const testPlanStateDefaultStr = `
   782  ID = bar
   783  `