github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/command/meta_backend_test.go (about)

     1  package command
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"reflect"
     8  	"sort"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/muratcelep/terraform/not-internal/addrs"
    13  	"github.com/muratcelep/terraform/not-internal/backend"
    14  	"github.com/muratcelep/terraform/not-internal/configs"
    15  	"github.com/muratcelep/terraform/not-internal/copy"
    16  	"github.com/muratcelep/terraform/not-internal/plans"
    17  	"github.com/muratcelep/terraform/not-internal/states"
    18  	"github.com/muratcelep/terraform/not-internal/states/statefile"
    19  	"github.com/muratcelep/terraform/not-internal/states/statemgr"
    20  	"github.com/mitchellh/cli"
    21  	"github.com/zclconf/go-cty/cty"
    22  
    23  	backendInit "github.com/muratcelep/terraform/not-internal/backend/init"
    24  	backendLocal "github.com/muratcelep/terraform/not-internal/backend/local"
    25  	backendInmem "github.com/muratcelep/terraform/not-internal/backend/remote-state/inmem"
    26  )
    27  
    28  // Test empty directory with no config/state creates a local state.
    29  func TestMetaBackend_emptyDir(t *testing.T) {
    30  	// Create a temporary working directory that is empty
    31  	td := tempDir(t)
    32  	os.MkdirAll(td, 0755)
    33  	defer os.RemoveAll(td)
    34  	defer testChdir(t, td)()
    35  
    36  	// Get the backend
    37  	m := testMetaBackend(t, nil)
    38  	b, diags := m.Backend(&BackendOpts{Init: true})
    39  	if diags.HasErrors() {
    40  		t.Fatal(diags.Err())
    41  	}
    42  
    43  	// Write some state
    44  	s, err := b.StateMgr(backend.DefaultStateName)
    45  	if err != nil {
    46  		t.Fatalf("unexpected error: %s", err)
    47  	}
    48  	s.WriteState(testState())
    49  	if err := s.PersistState(); err != nil {
    50  		t.Fatalf("unexpected error: %s", err)
    51  	}
    52  
    53  	// Verify it exists where we expect it to
    54  	if isEmptyState(DefaultStateFilename) {
    55  		t.Fatalf("no state was written")
    56  	}
    57  
    58  	// Verify no backup since it was empty to start
    59  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
    60  		t.Fatal("backup state should be empty")
    61  	}
    62  
    63  	// Verify no backend state was made
    64  	if !isEmptyState(filepath.Join(m.DataDir(), DefaultStateFilename)) {
    65  		t.Fatal("backend state should be empty")
    66  	}
    67  }
    68  
    69  // check for no state. Either the file doesn't exist, or is empty
    70  func isEmptyState(path string) bool {
    71  	fi, err := os.Stat(path)
    72  	if os.IsNotExist(err) {
    73  		return true
    74  	}
    75  
    76  	if fi.Size() == 0 {
    77  		return true
    78  	}
    79  
    80  	return false
    81  }
    82  
    83  // Test a directory with a legacy state and no config continues to
    84  // use the legacy state.
    85  func TestMetaBackend_emptyWithDefaultState(t *testing.T) {
    86  	// Create a temporary working directory that is empty
    87  	td := tempDir(t)
    88  	os.MkdirAll(td, 0755)
    89  	defer os.RemoveAll(td)
    90  	defer testChdir(t, td)()
    91  
    92  	// Write the legacy state
    93  	statePath := DefaultStateFilename
    94  	{
    95  		f, err := os.Create(statePath)
    96  		if err != nil {
    97  			t.Fatalf("err: %s", err)
    98  		}
    99  		err = writeStateForTesting(testState(), f)
   100  		f.Close()
   101  		if err != nil {
   102  			t.Fatalf("err: %s", err)
   103  		}
   104  	}
   105  
   106  	// Get the backend
   107  	m := testMetaBackend(t, nil)
   108  	b, diags := m.Backend(&BackendOpts{Init: true})
   109  	if diags.HasErrors() {
   110  		t.Fatal(diags.Err())
   111  	}
   112  
   113  	// Check the state
   114  	s, err := b.StateMgr(backend.DefaultStateName)
   115  	if err != nil {
   116  		t.Fatalf("unexpected error: %s", err)
   117  	}
   118  	if err := s.RefreshState(); err != nil {
   119  		t.Fatalf("err: %s", err)
   120  	}
   121  	if actual := s.State().String(); actual != testState().String() {
   122  		t.Fatalf("bad: %s", actual)
   123  	}
   124  
   125  	// Verify it exists where we expect it to
   126  	if _, err := os.Stat(DefaultStateFilename); err != nil {
   127  		t.Fatalf("err: %s", err)
   128  	}
   129  
   130  	stateName := filepath.Join(m.DataDir(), DefaultStateFilename)
   131  	if !isEmptyState(stateName) {
   132  		t.Fatal("expected no state at", stateName)
   133  	}
   134  
   135  	// Write some state
   136  	next := testState()
   137  	next.RootModule().SetOutputValue("foo", cty.StringVal("bar"), false)
   138  	s.WriteState(next)
   139  	if err := s.PersistState(); err != nil {
   140  		t.Fatalf("unexpected error: %s", err)
   141  	}
   142  
   143  	// Verify a backup was made since we're modifying a pre-existing state
   144  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   145  		t.Fatal("backup state should not be empty")
   146  	}
   147  }
   148  
   149  // Test an empty directory with an explicit state path (outside the dir)
   150  func TestMetaBackend_emptyWithExplicitState(t *testing.T) {
   151  	// Create a temporary working directory that is empty
   152  	td := tempDir(t)
   153  	os.MkdirAll(td, 0755)
   154  	defer os.RemoveAll(td)
   155  	defer testChdir(t, td)()
   156  
   157  	// Create another directory to store our state
   158  	stateDir := tempDir(t)
   159  	os.MkdirAll(stateDir, 0755)
   160  	defer os.RemoveAll(stateDir)
   161  
   162  	// Write the legacy state
   163  	statePath := filepath.Join(stateDir, "foo")
   164  	{
   165  		f, err := os.Create(statePath)
   166  		if err != nil {
   167  			t.Fatalf("err: %s", err)
   168  		}
   169  		err = writeStateForTesting(testState(), f)
   170  		f.Close()
   171  		if err != nil {
   172  			t.Fatalf("err: %s", err)
   173  		}
   174  	}
   175  
   176  	// Setup the meta
   177  	m := testMetaBackend(t, nil)
   178  	m.statePath = statePath
   179  
   180  	// Get the backend
   181  	b, diags := m.Backend(&BackendOpts{Init: true})
   182  	if diags.HasErrors() {
   183  		t.Fatal(diags.Err())
   184  	}
   185  
   186  	// Check the state
   187  	s, err := b.StateMgr(backend.DefaultStateName)
   188  	if err != nil {
   189  		t.Fatalf("unexpected error: %s", err)
   190  	}
   191  	if err := s.RefreshState(); err != nil {
   192  		t.Fatalf("err: %s", err)
   193  	}
   194  	if actual := s.State().String(); actual != testState().String() {
   195  		t.Fatalf("bad: %s", actual)
   196  	}
   197  
   198  	// Verify neither defaults exist
   199  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   200  		t.Fatal("file should not exist")
   201  	}
   202  
   203  	stateName := filepath.Join(m.DataDir(), DefaultStateFilename)
   204  	if !isEmptyState(stateName) {
   205  		t.Fatal("expected no state at", stateName)
   206  	}
   207  
   208  	// Write some state
   209  	next := testState()
   210  	markStateForMatching(next, "bar") // just any change so it shows as different than before
   211  	s.WriteState(next)
   212  	if err := s.PersistState(); err != nil {
   213  		t.Fatalf("unexpected error: %s", err)
   214  	}
   215  
   216  	// Verify a backup was made since we're modifying a pre-existing state
   217  	if isEmptyState(statePath + DefaultBackupExtension) {
   218  		t.Fatal("backup state should not be empty")
   219  	}
   220  }
   221  
   222  // Verify that interpolations result in an error
   223  func TestMetaBackend_configureInterpolation(t *testing.T) {
   224  	// Create a temporary working directory that is empty
   225  	td := tempDir(t)
   226  	testCopyDir(t, testFixturePath("backend-new-interp"), td)
   227  	defer os.RemoveAll(td)
   228  	defer testChdir(t, td)()
   229  
   230  	// Setup the meta
   231  	m := testMetaBackend(t, nil)
   232  
   233  	// Get the backend
   234  	_, err := m.Backend(&BackendOpts{Init: true})
   235  	if err == nil {
   236  		t.Fatal("should error")
   237  	}
   238  }
   239  
   240  // Newly configured backend
   241  func TestMetaBackend_configureNew(t *testing.T) {
   242  	td := tempDir(t)
   243  	testCopyDir(t, testFixturePath("backend-new"), td)
   244  	defer os.RemoveAll(td)
   245  	defer testChdir(t, td)()
   246  
   247  	// Setup the meta
   248  	m := testMetaBackend(t, nil)
   249  
   250  	// Get the backend
   251  	b, diags := m.Backend(&BackendOpts{Init: true})
   252  	if diags.HasErrors() {
   253  		t.Fatal(diags.Err())
   254  	}
   255  
   256  	// Check the state
   257  	s, err := b.StateMgr(backend.DefaultStateName)
   258  	if err != nil {
   259  		t.Fatalf("unexpected error: %s", err)
   260  	}
   261  	if err := s.RefreshState(); err != nil {
   262  		t.Fatalf("unexpected error: %s", err)
   263  	}
   264  	state := s.State()
   265  	if state != nil {
   266  		t.Fatal("state should be nil")
   267  	}
   268  
   269  	// Write some state
   270  	state = states.NewState()
   271  	mark := markStateForMatching(state, "changing")
   272  
   273  	s.WriteState(state)
   274  	if err := s.PersistState(); err != nil {
   275  		t.Fatalf("unexpected error: %s", err)
   276  	}
   277  
   278  	// Verify the state is where we expect
   279  	{
   280  		f, err := os.Open("local-state.tfstate")
   281  		if err != nil {
   282  			t.Fatalf("err: %s", err)
   283  		}
   284  		actual, err := statefile.Read(f)
   285  		f.Close()
   286  		if err != nil {
   287  			t.Fatalf("err: %s", err)
   288  		}
   289  
   290  		assertStateHasMarker(t, actual.State, mark)
   291  	}
   292  
   293  	// Verify the default paths don't exist
   294  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   295  		t.Fatal("file should not exist")
   296  	}
   297  
   298  	// Verify a backup doesn't exist
   299  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   300  		t.Fatal("file should not exist")
   301  	}
   302  }
   303  
   304  // Newly configured backend with prior local state and no remote state
   305  func TestMetaBackend_configureNewWithState(t *testing.T) {
   306  	// Create a temporary working directory that is empty
   307  	td := tempDir(t)
   308  	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
   309  	defer os.RemoveAll(td)
   310  	defer testChdir(t, td)()
   311  
   312  	// Ask input
   313  	defer testInteractiveInput(t, []string{"yes"})()
   314  
   315  	// Setup the meta
   316  	m := testMetaBackend(t, nil)
   317  
   318  	// This combination should not require the extra -migrate-state flag, since
   319  	// there is no existing backend config
   320  	m.migrateState = false
   321  
   322  	// Get the backend
   323  	b, diags := m.Backend(&BackendOpts{Init: true})
   324  	if diags.HasErrors() {
   325  		t.Fatal(diags.Err())
   326  	}
   327  
   328  	// Check the state
   329  	s, err := b.StateMgr(backend.DefaultStateName)
   330  	if err != nil {
   331  		t.Fatalf("unexpected error: %s", err)
   332  	}
   333  	state, err := statemgr.RefreshAndRead(s)
   334  	if err != nil {
   335  		t.Fatalf("unexpected error: %s", err)
   336  	}
   337  	if state == nil {
   338  		t.Fatal("state is nil")
   339  	}
   340  
   341  	if got, want := testStateMgrCurrentLineage(s), "backend-new-migrate"; got != want {
   342  		t.Fatalf("lineage changed during migration\nnow: %s\nwas: %s", got, want)
   343  	}
   344  
   345  	// Write some state
   346  	state = states.NewState()
   347  	mark := markStateForMatching(state, "changing")
   348  
   349  	if err := statemgr.WriteAndPersist(s, state); err != nil {
   350  		t.Fatalf("unexpected error: %s", err)
   351  	}
   352  
   353  	// Verify the state is where we expect
   354  	{
   355  		f, err := os.Open("local-state.tfstate")
   356  		if err != nil {
   357  			t.Fatalf("err: %s", err)
   358  		}
   359  		actual, err := statefile.Read(f)
   360  		f.Close()
   361  		if err != nil {
   362  			t.Fatalf("err: %s", err)
   363  		}
   364  
   365  		assertStateHasMarker(t, actual.State, mark)
   366  	}
   367  
   368  	// Verify the default paths don't exist
   369  	if !isEmptyState(DefaultStateFilename) {
   370  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   371  
   372  		t.Fatal("state should not exist, but contains:\n", string(data))
   373  	}
   374  
   375  	// Verify a backup does exist
   376  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   377  		t.Fatal("backup state is empty or missing")
   378  	}
   379  }
   380  
   381  // Newly configured backend with matching local and remote state doesn't prompt
   382  // for copy.
   383  func TestMetaBackend_configureNewWithoutCopy(t *testing.T) {
   384  	// Create a temporary working directory that is empty
   385  	td := tempDir(t)
   386  	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
   387  	defer os.RemoveAll(td)
   388  	defer testChdir(t, td)()
   389  
   390  	if err := copy.CopyFile(DefaultStateFilename, "local-state.tfstate"); err != nil {
   391  		t.Fatal(err)
   392  	}
   393  
   394  	// Setup the meta
   395  	m := testMetaBackend(t, nil)
   396  	m.input = false
   397  
   398  	// init the backend
   399  	_, diags := m.Backend(&BackendOpts{Init: true})
   400  	if diags.HasErrors() {
   401  		t.Fatal(diags.Err())
   402  	}
   403  
   404  	// Verify the state is where we expect
   405  	f, err := os.Open("local-state.tfstate")
   406  	if err != nil {
   407  		t.Fatalf("err: %s", err)
   408  	}
   409  	actual, err := statefile.Read(f)
   410  	f.Close()
   411  	if err != nil {
   412  		t.Fatalf("err: %s", err)
   413  	}
   414  
   415  	if actual.Lineage != "backend-new-migrate" {
   416  		t.Fatalf("incorrect state lineage: %q", actual.Lineage)
   417  	}
   418  
   419  	// Verify the default paths don't exist
   420  	if !isEmptyState(DefaultStateFilename) {
   421  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   422  
   423  		t.Fatal("state should not exist, but contains:\n", string(data))
   424  	}
   425  
   426  	// Verify a backup does exist
   427  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   428  		t.Fatal("backup state is empty or missing")
   429  	}
   430  }
   431  
   432  // Newly configured backend with prior local state and no remote state,
   433  // but opting to not migrate.
   434  func TestMetaBackend_configureNewWithStateNoMigrate(t *testing.T) {
   435  	// Create a temporary working directory that is empty
   436  	td := tempDir(t)
   437  	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
   438  	defer os.RemoveAll(td)
   439  	defer testChdir(t, td)()
   440  
   441  	// Ask input
   442  	defer testInteractiveInput(t, []string{"no"})()
   443  
   444  	// Setup the meta
   445  	m := testMetaBackend(t, nil)
   446  
   447  	// Get the backend
   448  	b, diags := m.Backend(&BackendOpts{Init: true})
   449  	if diags.HasErrors() {
   450  		t.Fatal(diags.Err())
   451  	}
   452  
   453  	// Check the state
   454  	s, err := b.StateMgr(backend.DefaultStateName)
   455  	if err != nil {
   456  		t.Fatalf("unexpected error: %s", err)
   457  	}
   458  	if err := s.RefreshState(); err != nil {
   459  		t.Fatalf("unexpected error: %s", err)
   460  	}
   461  	if state := s.State(); state != nil {
   462  		t.Fatal("state is not nil")
   463  	}
   464  
   465  	// Verify the default paths don't exist
   466  	if !isEmptyState(DefaultStateFilename) {
   467  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   468  
   469  		t.Fatal("state should not exist, but contains:\n", string(data))
   470  	}
   471  
   472  	// Verify a backup does exist
   473  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   474  		t.Fatal("backup state is empty or missing")
   475  	}
   476  }
   477  
   478  // Newly configured backend with prior local state and remote state
   479  func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
   480  	// Create a temporary working directory that is empty
   481  	td := tempDir(t)
   482  	testCopyDir(t, testFixturePath("backend-new-migrate-existing"), td)
   483  	defer os.RemoveAll(td)
   484  	defer testChdir(t, td)()
   485  
   486  	// Setup the meta
   487  	m := testMetaBackend(t, nil)
   488  	// suppress input
   489  	m.forceInitCopy = true
   490  
   491  	// Get the backend
   492  	b, diags := m.Backend(&BackendOpts{Init: true})
   493  	if diags.HasErrors() {
   494  		t.Fatal(diags.Err())
   495  	}
   496  
   497  	// Check the state
   498  	s, err := b.StateMgr(backend.DefaultStateName)
   499  	if err != nil {
   500  		t.Fatalf("unexpected error: %s", err)
   501  	}
   502  	if err := s.RefreshState(); err != nil {
   503  		t.Fatalf("unexpected error: %s", err)
   504  	}
   505  	state := s.State()
   506  	if state == nil {
   507  		t.Fatal("state is nil")
   508  	}
   509  	if got, want := testStateMgrCurrentLineage(s), "local"; got != want {
   510  		t.Fatalf("wrong lineage %q; want %q", got, want)
   511  	}
   512  
   513  	// Write some state
   514  	state = states.NewState()
   515  	mark := markStateForMatching(state, "changing")
   516  
   517  	s.WriteState(state)
   518  	if err := s.PersistState(); err != nil {
   519  		t.Fatalf("unexpected error: %s", err)
   520  	}
   521  
   522  	// Verify the state is where we expect
   523  	{
   524  		f, err := os.Open("local-state.tfstate")
   525  		if err != nil {
   526  			t.Fatalf("err: %s", err)
   527  		}
   528  		actual, err := statefile.Read(f)
   529  		f.Close()
   530  		if err != nil {
   531  			t.Fatalf("err: %s", err)
   532  		}
   533  
   534  		assertStateHasMarker(t, actual.State, mark)
   535  	}
   536  
   537  	// Verify the default paths don't exist
   538  	if !isEmptyState(DefaultStateFilename) {
   539  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   540  
   541  		t.Fatal("state should not exist, but contains:\n", string(data))
   542  	}
   543  
   544  	// Verify a backup does exist
   545  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   546  		t.Fatal("backup state is empty or missing")
   547  	}
   548  }
   549  
   550  // Newly configured backend with prior local state and remote state
   551  func TestMetaBackend_configureNewWithStateExistingNoMigrate(t *testing.T) {
   552  	// Create a temporary working directory that is empty
   553  	td := tempDir(t)
   554  	testCopyDir(t, testFixturePath("backend-new-migrate-existing"), td)
   555  	defer os.RemoveAll(td)
   556  	defer testChdir(t, td)()
   557  
   558  	// Ask input
   559  	defer testInteractiveInput(t, []string{"no"})()
   560  
   561  	// Setup the meta
   562  	m := testMetaBackend(t, nil)
   563  
   564  	// Get the backend
   565  	b, diags := m.Backend(&BackendOpts{Init: true})
   566  	if diags.HasErrors() {
   567  		t.Fatal(diags.Err())
   568  	}
   569  
   570  	// Check the state
   571  	s, err := b.StateMgr(backend.DefaultStateName)
   572  	if err != nil {
   573  		t.Fatalf("unexpected error: %s", err)
   574  	}
   575  	if err := s.RefreshState(); err != nil {
   576  		t.Fatalf("unexpected error: %s", err)
   577  	}
   578  	state := s.State()
   579  	if state == nil {
   580  		t.Fatal("state is nil")
   581  	}
   582  	if testStateMgrCurrentLineage(s) != "remote" {
   583  		t.Fatalf("bad: %#v", state)
   584  	}
   585  
   586  	// Write some state
   587  	state = states.NewState()
   588  	mark := markStateForMatching(state, "changing")
   589  	s.WriteState(state)
   590  	if err := s.PersistState(); err != nil {
   591  		t.Fatalf("unexpected error: %s", err)
   592  	}
   593  
   594  	// Verify the state is where we expect
   595  	{
   596  		f, err := os.Open("local-state.tfstate")
   597  		if err != nil {
   598  			t.Fatalf("err: %s", err)
   599  		}
   600  		actual, err := statefile.Read(f)
   601  		f.Close()
   602  		if err != nil {
   603  			t.Fatalf("err: %s", err)
   604  		}
   605  
   606  		assertStateHasMarker(t, actual.State, mark)
   607  	}
   608  
   609  	// Verify the default paths don't exist
   610  	if !isEmptyState(DefaultStateFilename) {
   611  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   612  
   613  		t.Fatal("state should not exist, but contains:\n", string(data))
   614  	}
   615  
   616  	// Verify a backup does exist
   617  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   618  		t.Fatal("backup state is empty or missing")
   619  	}
   620  }
   621  
   622  // Saved backend state matching config
   623  func TestMetaBackend_configuredUnchanged(t *testing.T) {
   624  	defer testChdir(t, testFixturePath("backend-unchanged"))()
   625  
   626  	// Setup the meta
   627  	m := testMetaBackend(t, nil)
   628  
   629  	// Get the backend
   630  	b, diags := m.Backend(&BackendOpts{Init: true})
   631  	if diags.HasErrors() {
   632  		t.Fatal(diags.Err())
   633  	}
   634  
   635  	// Check the state
   636  	s, err := b.StateMgr(backend.DefaultStateName)
   637  	if err != nil {
   638  		t.Fatalf("unexpected error: %s", err)
   639  	}
   640  	if err := s.RefreshState(); err != nil {
   641  		t.Fatalf("unexpected error: %s", err)
   642  	}
   643  	state := s.State()
   644  	if state == nil {
   645  		t.Fatal("nil state")
   646  	}
   647  	if testStateMgrCurrentLineage(s) != "configuredUnchanged" {
   648  		t.Fatalf("bad: %#v", state)
   649  	}
   650  
   651  	// Verify the default paths don't exist
   652  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   653  		t.Fatal("file should not exist")
   654  	}
   655  
   656  	// Verify a backup doesn't exist
   657  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   658  		t.Fatal("file should not exist")
   659  	}
   660  }
   661  
   662  // Changing a configured backend
   663  func TestMetaBackend_configuredChange(t *testing.T) {
   664  	// Create a temporary working directory that is empty
   665  	td := tempDir(t)
   666  	testCopyDir(t, testFixturePath("backend-change"), td)
   667  	defer os.RemoveAll(td)
   668  	defer testChdir(t, td)()
   669  
   670  	// Ask input
   671  	defer testInteractiveInput(t, []string{"no"})()
   672  
   673  	// Setup the meta
   674  	m := testMetaBackend(t, nil)
   675  
   676  	// Get the backend
   677  	b, diags := m.Backend(&BackendOpts{Init: true})
   678  	if diags.HasErrors() {
   679  		t.Fatal(diags.Err())
   680  	}
   681  
   682  	// Check the state
   683  	s, err := b.StateMgr(backend.DefaultStateName)
   684  	if err != nil {
   685  		t.Fatalf("unexpected error: %s", err)
   686  	}
   687  	if err := s.RefreshState(); err != nil {
   688  		t.Fatalf("unexpected error: %s", err)
   689  	}
   690  	state := s.State()
   691  	if state != nil {
   692  		t.Fatal("state should be nil")
   693  	}
   694  
   695  	// Verify the default paths don't exist
   696  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   697  		t.Fatal("file should not exist")
   698  	}
   699  
   700  	// Verify a backup doesn't exist
   701  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   702  		t.Fatal("file should not exist")
   703  	}
   704  
   705  	// Write some state
   706  	state = states.NewState()
   707  	mark := markStateForMatching(state, "changing")
   708  
   709  	s.WriteState(state)
   710  	if err := s.PersistState(); err != nil {
   711  		t.Fatalf("unexpected error: %s", err)
   712  	}
   713  
   714  	// Verify the state is where we expect
   715  	{
   716  		f, err := os.Open("local-state-2.tfstate")
   717  		if err != nil {
   718  			t.Fatalf("err: %s", err)
   719  		}
   720  		actual, err := statefile.Read(f)
   721  		f.Close()
   722  		if err != nil {
   723  			t.Fatalf("err: %s", err)
   724  		}
   725  
   726  		assertStateHasMarker(t, actual.State, mark)
   727  	}
   728  
   729  	// Verify no local state
   730  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   731  		t.Fatal("file should not exist")
   732  	}
   733  
   734  	// Verify no local backup
   735  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   736  		t.Fatal("file should not exist")
   737  	}
   738  }
   739  
   740  // Reconfiguring with an already configured backend.
   741  // This should ignore the existing backend config, and configure the new
   742  // backend is if this is the first time.
   743  func TestMetaBackend_reconfigureChange(t *testing.T) {
   744  	// Create a temporary working directory that is empty
   745  	td := tempDir(t)
   746  	testCopyDir(t, testFixturePath("backend-change-single-to-single"), td)
   747  	defer os.RemoveAll(td)
   748  	defer testChdir(t, td)()
   749  
   750  	// Register the single-state backend
   751  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
   752  	defer backendInit.Set("local-single", nil)
   753  
   754  	// Setup the meta
   755  	m := testMetaBackend(t, nil)
   756  
   757  	// this should not ask for input
   758  	m.input = false
   759  
   760  	// cli flag -reconfigure
   761  	m.reconfigure = true
   762  
   763  	// Get the backend
   764  	b, diags := m.Backend(&BackendOpts{Init: true})
   765  	if diags.HasErrors() {
   766  		t.Fatal(diags.Err())
   767  	}
   768  
   769  	// Check the state
   770  	s, err := b.StateMgr(backend.DefaultStateName)
   771  	if err != nil {
   772  		t.Fatalf("unexpected error: %s", err)
   773  	}
   774  	if err := s.RefreshState(); err != nil {
   775  		t.Fatalf("unexpected error: %s", err)
   776  	}
   777  	newState := s.State()
   778  	if newState != nil || !newState.Empty() {
   779  		t.Fatal("state should be nil/empty after forced reconfiguration")
   780  	}
   781  
   782  	// verify that the old state is still there
   783  	s = statemgr.NewFilesystem("local-state.tfstate")
   784  	if err := s.RefreshState(); err != nil {
   785  		t.Fatal(err)
   786  	}
   787  	oldState := s.State()
   788  	if oldState == nil || oldState.Empty() {
   789  		t.Fatal("original state should be untouched")
   790  	}
   791  }
   792  
   793  // Initializing a backend which supports workspaces and does *not* have
   794  // the currently selected workspace should prompt the user with a list of
   795  // workspaces to choose from to select a valid one, if more than one workspace
   796  // is available.
   797  func TestMetaBackend_initSelectedWorkspaceDoesNotExist(t *testing.T) {
   798  	// Create a temporary working directory that is empty
   799  	td := tempDir(t)
   800  	testCopyDir(t, testFixturePath("init-backend-selected-workspace-doesnt-exist-multi"), td)
   801  	defer os.RemoveAll(td)
   802  	defer testChdir(t, td)()
   803  
   804  	// Setup the meta
   805  	m := testMetaBackend(t, nil)
   806  
   807  	defer testInputMap(t, map[string]string{
   808  		"select-workspace": "2",
   809  	})()
   810  
   811  	// Get the backend
   812  	_, diags := m.Backend(&BackendOpts{Init: true})
   813  	if diags.HasErrors() {
   814  		t.Fatal(diags.Err())
   815  	}
   816  
   817  	expected := "foo"
   818  	actual, err := m.Workspace()
   819  	if err != nil {
   820  		t.Fatal(err)
   821  	}
   822  
   823  	if actual != expected {
   824  		t.Fatalf("expected selected workspace to be %q, but was %q", expected, actual)
   825  	}
   826  }
   827  
   828  // Initializing a backend which supports workspaces and does *not* have the
   829  // currently selected workspace - and which only has a single workspace - should
   830  // automatically select that single workspace.
   831  func TestMetaBackend_initSelectedWorkspaceDoesNotExistAutoSelect(t *testing.T) {
   832  	// Create a temporary working directory that is empty
   833  	td := tempDir(t)
   834  	testCopyDir(t, testFixturePath("init-backend-selected-workspace-doesnt-exist-single"), td)
   835  	defer os.RemoveAll(td)
   836  	defer testChdir(t, td)()
   837  
   838  	// Setup the meta
   839  	m := testMetaBackend(t, nil)
   840  
   841  	// this should not ask for input
   842  	m.input = false
   843  
   844  	// Assert test precondition: The current selected workspace is "bar"
   845  	previousName, err := m.Workspace()
   846  	if err != nil {
   847  		t.Fatal(err)
   848  	}
   849  
   850  	if previousName != "bar" {
   851  		t.Fatalf("expected test fixture to start with 'bar' as the current selected workspace")
   852  	}
   853  
   854  	// Get the backend
   855  	_, diags := m.Backend(&BackendOpts{Init: true})
   856  	if diags.HasErrors() {
   857  		t.Fatal(diags.Err())
   858  	}
   859  
   860  	expected := "default"
   861  	actual, err := m.Workspace()
   862  	if err != nil {
   863  		t.Fatal(err)
   864  	}
   865  
   866  	if actual != expected {
   867  		t.Fatalf("expected selected workspace to be %q, but was %q", expected, actual)
   868  	}
   869  }
   870  
   871  // Initializing a backend which supports workspaces and does *not* have
   872  // the currently selected workspace with input=false should fail.
   873  func TestMetaBackend_initSelectedWorkspaceDoesNotExistInputFalse(t *testing.T) {
   874  	// Create a temporary working directory that is empty
   875  	td := tempDir(t)
   876  	testCopyDir(t, testFixturePath("init-backend-selected-workspace-doesnt-exist-multi"), td)
   877  	defer os.RemoveAll(td)
   878  	defer testChdir(t, td)()
   879  
   880  	// Setup the meta
   881  	m := testMetaBackend(t, nil)
   882  	m.input = false
   883  
   884  	// Get the backend
   885  	_, diags := m.Backend(&BackendOpts{Init: true})
   886  
   887  	// Should fail immediately
   888  	if got, want := diags.ErrWithWarnings().Error(), `Currently selected workspace "bar" does not exist`; !strings.Contains(got, want) {
   889  		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
   890  	}
   891  }
   892  
   893  // Changing a configured backend, copying state
   894  func TestMetaBackend_configuredChangeCopy(t *testing.T) {
   895  	// Create a temporary working directory that is empty
   896  	td := tempDir(t)
   897  	testCopyDir(t, testFixturePath("backend-change"), td)
   898  	defer os.RemoveAll(td)
   899  	defer testChdir(t, td)()
   900  
   901  	// Ask input
   902  	defer testInteractiveInput(t, []string{"yes", "yes"})()
   903  
   904  	// Setup the meta
   905  	m := testMetaBackend(t, nil)
   906  
   907  	// Get the backend
   908  	b, diags := m.Backend(&BackendOpts{Init: true})
   909  	if diags.HasErrors() {
   910  		t.Fatal(diags.Err())
   911  	}
   912  
   913  	// Check the state
   914  	s, err := b.StateMgr(backend.DefaultStateName)
   915  	if err != nil {
   916  		t.Fatalf("unexpected error: %s", err)
   917  	}
   918  	if err := s.RefreshState(); err != nil {
   919  		t.Fatalf("unexpected error: %s", err)
   920  	}
   921  	state := s.State()
   922  	if state == nil {
   923  		t.Fatal("state should not be nil")
   924  	}
   925  	if testStateMgrCurrentLineage(s) != "backend-change" {
   926  		t.Fatalf("bad: %#v", state)
   927  	}
   928  
   929  	// Verify no local state
   930  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   931  		t.Fatal("file should not exist")
   932  	}
   933  
   934  	// Verify no local backup
   935  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   936  		t.Fatal("file should not exist")
   937  	}
   938  }
   939  
   940  // Changing a configured backend that supports only single states to another
   941  // backend that only supports single states.
   942  func TestMetaBackend_configuredChangeCopy_singleState(t *testing.T) {
   943  	// Create a temporary working directory that is empty
   944  	td := tempDir(t)
   945  	testCopyDir(t, testFixturePath("backend-change-single-to-single"), td)
   946  	defer os.RemoveAll(td)
   947  	defer testChdir(t, td)()
   948  
   949  	// Register the single-state backend
   950  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
   951  	defer backendInit.Set("local-single", nil)
   952  
   953  	// Ask input
   954  	defer testInputMap(t, map[string]string{
   955  		"backend-migrate-copy-to-empty": "yes",
   956  	})()
   957  
   958  	// Setup the meta
   959  	m := testMetaBackend(t, nil)
   960  
   961  	// Get the backend
   962  	b, diags := m.Backend(&BackendOpts{Init: true})
   963  	if diags.HasErrors() {
   964  		t.Fatal(diags.Err())
   965  	}
   966  
   967  	// Check the state
   968  	s, err := b.StateMgr(backend.DefaultStateName)
   969  	if err != nil {
   970  		t.Fatalf("unexpected error: %s", err)
   971  	}
   972  	if err := s.RefreshState(); err != nil {
   973  		t.Fatalf("unexpected error: %s", err)
   974  	}
   975  	state := s.State()
   976  	if state == nil {
   977  		t.Fatal("state should not be nil")
   978  	}
   979  	if testStateMgrCurrentLineage(s) != "backend-change" {
   980  		t.Fatalf("bad: %#v", state)
   981  	}
   982  
   983  	// Verify no local state
   984  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   985  		t.Fatal("file should not exist")
   986  	}
   987  
   988  	// Verify no local backup
   989  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   990  		t.Fatal("file should not exist")
   991  	}
   992  }
   993  
   994  // Changing a configured backend that supports multi-state to a
   995  // backend that only supports single states. The multi-state only has
   996  // a default state.
   997  func TestMetaBackend_configuredChangeCopy_multiToSingleDefault(t *testing.T) {
   998  	// Create a temporary working directory that is empty
   999  	td := tempDir(t)
  1000  	testCopyDir(t, testFixturePath("backend-change-multi-default-to-single"), td)
  1001  	defer os.RemoveAll(td)
  1002  	defer testChdir(t, td)()
  1003  
  1004  	// Register the single-state backend
  1005  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
  1006  	defer backendInit.Set("local-single", nil)
  1007  
  1008  	// Ask input
  1009  	defer testInputMap(t, map[string]string{
  1010  		"backend-migrate-copy-to-empty": "yes",
  1011  	})()
  1012  
  1013  	// Setup the meta
  1014  	m := testMetaBackend(t, nil)
  1015  
  1016  	// Get the backend
  1017  	b, diags := m.Backend(&BackendOpts{Init: true})
  1018  	if diags.HasErrors() {
  1019  		t.Fatal(diags.Err())
  1020  	}
  1021  
  1022  	// Check the state
  1023  	s, err := b.StateMgr(backend.DefaultStateName)
  1024  	if err != nil {
  1025  		t.Fatalf("unexpected error: %s", err)
  1026  	}
  1027  	if err := s.RefreshState(); err != nil {
  1028  		t.Fatalf("unexpected error: %s", err)
  1029  	}
  1030  	state := s.State()
  1031  	if state == nil {
  1032  		t.Fatal("state should not be nil")
  1033  	}
  1034  	if testStateMgrCurrentLineage(s) != "backend-change" {
  1035  		t.Fatalf("bad: %#v", state)
  1036  	}
  1037  
  1038  	// Verify no local state
  1039  	if _, err := os.Stat(DefaultStateFilename); err == nil {
  1040  		t.Fatal("file should not exist")
  1041  	}
  1042  
  1043  	// Verify no local backup
  1044  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1045  		t.Fatal("file should not exist")
  1046  	}
  1047  }
  1048  
  1049  // Changing a configured backend that supports multi-state to a
  1050  // backend that only supports single states.
  1051  func TestMetaBackend_configuredChangeCopy_multiToSingle(t *testing.T) {
  1052  	// Create a temporary working directory that is empty
  1053  	td := tempDir(t)
  1054  	testCopyDir(t, testFixturePath("backend-change-multi-to-single"), td)
  1055  	defer os.RemoveAll(td)
  1056  	defer testChdir(t, td)()
  1057  
  1058  	// Register the single-state backend
  1059  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
  1060  	defer backendInit.Set("local-single", nil)
  1061  
  1062  	// Ask input
  1063  	defer testInputMap(t, map[string]string{
  1064  		"backend-migrate-multistate-to-single": "yes",
  1065  		"backend-migrate-copy-to-empty":        "yes",
  1066  	})()
  1067  
  1068  	// Setup the meta
  1069  	m := testMetaBackend(t, nil)
  1070  
  1071  	// Get the backend
  1072  	b, diags := m.Backend(&BackendOpts{Init: true})
  1073  	if diags.HasErrors() {
  1074  		t.Fatal(diags.Err())
  1075  	}
  1076  
  1077  	// Check the state
  1078  	s, err := b.StateMgr(backend.DefaultStateName)
  1079  	if err != nil {
  1080  		t.Fatalf("unexpected error: %s", err)
  1081  	}
  1082  	if err := s.RefreshState(); err != nil {
  1083  		t.Fatalf("unexpected error: %s", err)
  1084  	}
  1085  	state := s.State()
  1086  	if state == nil {
  1087  		t.Fatal("state should not be nil")
  1088  	}
  1089  	if testStateMgrCurrentLineage(s) != "backend-change" {
  1090  		t.Fatalf("bad: %#v", state)
  1091  	}
  1092  
  1093  	// Verify no local state
  1094  	if _, err := os.Stat(DefaultStateFilename); err == nil {
  1095  		t.Fatal("file should not exist")
  1096  	}
  1097  
  1098  	// Verify no local backup
  1099  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1100  		t.Fatal("file should not exist")
  1101  	}
  1102  
  1103  	// Verify existing workspaces exist
  1104  	envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1105  	if _, err := os.Stat(envPath); err != nil {
  1106  		t.Fatal("env should exist")
  1107  	}
  1108  
  1109  	// Verify we are now in the default env, or we may not be able to access the new backend
  1110  	env, err := m.Workspace()
  1111  	if err != nil {
  1112  		t.Fatal(err)
  1113  	}
  1114  	if env != backend.DefaultStateName {
  1115  		t.Fatal("using non-default env with single-env backend")
  1116  	}
  1117  }
  1118  
  1119  // Changing a configured backend that supports multi-state to a
  1120  // backend that only supports single states.
  1121  func TestMetaBackend_configuredChangeCopy_multiToSingleCurrentEnv(t *testing.T) {
  1122  	// Create a temporary working directory that is empty
  1123  	td := tempDir(t)
  1124  	testCopyDir(t, testFixturePath("backend-change-multi-to-single"), td)
  1125  	defer os.RemoveAll(td)
  1126  	defer testChdir(t, td)()
  1127  
  1128  	// Register the single-state backend
  1129  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
  1130  	defer backendInit.Set("local-single", nil)
  1131  
  1132  	// Ask input
  1133  	defer testInputMap(t, map[string]string{
  1134  		"backend-migrate-multistate-to-single": "yes",
  1135  		"backend-migrate-copy-to-empty":        "yes",
  1136  	})()
  1137  
  1138  	// Setup the meta
  1139  	m := testMetaBackend(t, nil)
  1140  
  1141  	// Change env
  1142  	if err := m.SetWorkspace("env2"); err != nil {
  1143  		t.Fatalf("unexpected error: %s", err)
  1144  	}
  1145  
  1146  	// Get the backend
  1147  	b, diags := m.Backend(&BackendOpts{Init: true})
  1148  	if diags.HasErrors() {
  1149  		t.Fatal(diags.Err())
  1150  	}
  1151  
  1152  	// Check the state
  1153  	s, err := b.StateMgr(backend.DefaultStateName)
  1154  	if err != nil {
  1155  		t.Fatalf("unexpected error: %s", err)
  1156  	}
  1157  	if err := s.RefreshState(); err != nil {
  1158  		t.Fatalf("unexpected error: %s", err)
  1159  	}
  1160  	state := s.State()
  1161  	if state == nil {
  1162  		t.Fatal("state should not be nil")
  1163  	}
  1164  	if testStateMgrCurrentLineage(s) != "backend-change-env2" {
  1165  		t.Fatalf("bad: %#v", state)
  1166  	}
  1167  
  1168  	// Verify no local state
  1169  	if _, err := os.Stat(DefaultStateFilename); err == nil {
  1170  		t.Fatal("file should not exist")
  1171  	}
  1172  
  1173  	// Verify no local backup
  1174  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1175  		t.Fatal("file should not exist")
  1176  	}
  1177  
  1178  	// Verify existing workspaces exist
  1179  	envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1180  	if _, err := os.Stat(envPath); err != nil {
  1181  		t.Fatal("env should exist")
  1182  	}
  1183  }
  1184  
  1185  // Changing a configured backend that supports multi-state to a
  1186  // backend that also supports multi-state.
  1187  func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) {
  1188  	// Create a temporary working directory that is empty
  1189  	td := tempDir(t)
  1190  	testCopyDir(t, testFixturePath("backend-change-multi-to-multi"), td)
  1191  	defer os.RemoveAll(td)
  1192  	defer testChdir(t, td)()
  1193  
  1194  	// Ask input
  1195  	defer testInputMap(t, map[string]string{
  1196  		"backend-migrate-multistate-to-multistate": "yes",
  1197  	})()
  1198  
  1199  	// Setup the meta
  1200  	m := testMetaBackend(t, nil)
  1201  
  1202  	// Get the backend
  1203  	b, diags := m.Backend(&BackendOpts{Init: true})
  1204  	if diags.HasErrors() {
  1205  		t.Fatal(diags.Err())
  1206  	}
  1207  
  1208  	// Check resulting states
  1209  	workspaces, err := b.Workspaces()
  1210  	if err != nil {
  1211  		t.Fatalf("unexpected error: %s", err)
  1212  	}
  1213  
  1214  	sort.Strings(workspaces)
  1215  	expected := []string{"default", "env2"}
  1216  	if !reflect.DeepEqual(workspaces, expected) {
  1217  		t.Fatalf("bad: %#v", workspaces)
  1218  	}
  1219  
  1220  	{
  1221  		// Check the default state
  1222  		s, err := b.StateMgr(backend.DefaultStateName)
  1223  		if err != nil {
  1224  			t.Fatalf("unexpected error: %s", err)
  1225  		}
  1226  		if err := s.RefreshState(); err != nil {
  1227  			t.Fatalf("unexpected error: %s", err)
  1228  		}
  1229  		state := s.State()
  1230  		if state == nil {
  1231  			t.Fatal("state should not be nil")
  1232  		}
  1233  		if testStateMgrCurrentLineage(s) != "backend-change" {
  1234  			t.Fatalf("bad: %#v", state)
  1235  		}
  1236  	}
  1237  
  1238  	{
  1239  		// Check the other state
  1240  		s, err := b.StateMgr("env2")
  1241  		if err != nil {
  1242  			t.Fatalf("unexpected error: %s", err)
  1243  		}
  1244  		if err := s.RefreshState(); err != nil {
  1245  			t.Fatalf("unexpected error: %s", err)
  1246  		}
  1247  		state := s.State()
  1248  		if state == nil {
  1249  			t.Fatal("state should not be nil")
  1250  		}
  1251  		if testStateMgrCurrentLineage(s) != "backend-change-env2" {
  1252  			t.Fatalf("bad: %#v", state)
  1253  		}
  1254  	}
  1255  
  1256  	// Verify no local backup
  1257  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1258  		t.Fatal("file should not exist")
  1259  	}
  1260  
  1261  	{
  1262  		// Verify existing workspaces exist
  1263  		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1264  		if _, err := os.Stat(envPath); err != nil {
  1265  			t.Fatalf("%s should exist, but does not", envPath)
  1266  		}
  1267  	}
  1268  
  1269  	{
  1270  		// Verify new workspaces exist
  1271  		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
  1272  		if _, err := os.Stat(envPath); err != nil {
  1273  			t.Fatalf("%s should exist, but does not", envPath)
  1274  		}
  1275  	}
  1276  }
  1277  
  1278  // Changing a configured backend that supports multi-state to a
  1279  // backend that also supports multi-state, but doesn't allow a
  1280  // default state while the default state is non-empty.
  1281  func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithDefault(t *testing.T) {
  1282  	// Create a temporary working directory that is empty
  1283  	td := tempDir(t)
  1284  	testCopyDir(t, testFixturePath("backend-change-multi-to-no-default-with-default"), td)
  1285  	defer os.RemoveAll(td)
  1286  	defer testChdir(t, td)()
  1287  
  1288  	// Register the single-state backend
  1289  	backendInit.Set("local-no-default", backendLocal.TestNewLocalNoDefault)
  1290  	defer backendInit.Set("local-no-default", nil)
  1291  
  1292  	// Ask input
  1293  	defer testInputMap(t, map[string]string{
  1294  		"backend-migrate-multistate-to-multistate": "yes",
  1295  		"new-state-name": "env1",
  1296  	})()
  1297  
  1298  	// Setup the meta
  1299  	m := testMetaBackend(t, nil)
  1300  
  1301  	// Get the backend
  1302  	b, diags := m.Backend(&BackendOpts{Init: true})
  1303  	if diags.HasErrors() {
  1304  		t.Fatal(diags.Err())
  1305  	}
  1306  
  1307  	// Check resulting states
  1308  	workspaces, err := b.Workspaces()
  1309  	if err != nil {
  1310  		t.Fatalf("unexpected error: %s", err)
  1311  	}
  1312  
  1313  	sort.Strings(workspaces)
  1314  	expected := []string{"env1", "env2"}
  1315  	if !reflect.DeepEqual(workspaces, expected) {
  1316  		t.Fatalf("bad: %#v", workspaces)
  1317  	}
  1318  
  1319  	{
  1320  		// Check the renamed default state
  1321  		s, err := b.StateMgr("env1")
  1322  		if err != nil {
  1323  			t.Fatalf("unexpected error: %s", err)
  1324  		}
  1325  		if err := s.RefreshState(); err != nil {
  1326  			t.Fatalf("unexpected error: %s", err)
  1327  		}
  1328  		state := s.State()
  1329  		if state == nil {
  1330  			t.Fatal("state should not be nil")
  1331  		}
  1332  		if testStateMgrCurrentLineage(s) != "backend-change-env1" {
  1333  			t.Fatalf("bad: %#v", state)
  1334  		}
  1335  	}
  1336  
  1337  	{
  1338  		// Verify existing workspaces exist
  1339  		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1340  		if _, err := os.Stat(envPath); err != nil {
  1341  			t.Fatal("env should exist")
  1342  		}
  1343  	}
  1344  
  1345  	{
  1346  		// Verify new workspaces exist
  1347  		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
  1348  		if _, err := os.Stat(envPath); err != nil {
  1349  			t.Fatal("env should exist")
  1350  		}
  1351  	}
  1352  }
  1353  
  1354  // Changing a configured backend that supports multi-state to a
  1355  // backend that also supports multi-state, but doesn't allow a
  1356  // default state while the default state is empty.
  1357  func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithoutDefault(t *testing.T) {
  1358  	// Create a temporary working directory that is empty
  1359  	td := tempDir(t)
  1360  	testCopyDir(t, testFixturePath("backend-change-multi-to-no-default-without-default"), td)
  1361  	defer os.RemoveAll(td)
  1362  	defer testChdir(t, td)()
  1363  
  1364  	// Register the single-state backend
  1365  	backendInit.Set("local-no-default", backendLocal.TestNewLocalNoDefault)
  1366  	defer backendInit.Set("local-no-default", nil)
  1367  
  1368  	// Ask input
  1369  	defer testInputMap(t, map[string]string{
  1370  		"backend-migrate-multistate-to-multistate": "yes",
  1371  	})()
  1372  
  1373  	// Setup the meta
  1374  	m := testMetaBackend(t, nil)
  1375  
  1376  	// Get the backend
  1377  	b, diags := m.Backend(&BackendOpts{Init: true})
  1378  	if diags.HasErrors() {
  1379  		t.Fatal(diags.Err())
  1380  	}
  1381  
  1382  	// Check resulting states
  1383  	workspaces, err := b.Workspaces()
  1384  	if err != nil {
  1385  		t.Fatalf("unexpected error: %s", err)
  1386  	}
  1387  
  1388  	sort.Strings(workspaces)
  1389  	expected := []string{"env2"} // default is skipped because it is absent in the source backend
  1390  	if !reflect.DeepEqual(workspaces, expected) {
  1391  		t.Fatalf("wrong workspaces\ngot:  %#v\nwant: %#v", workspaces, expected)
  1392  	}
  1393  
  1394  	{
  1395  		// Check the named state
  1396  		s, err := b.StateMgr("env2")
  1397  		if err != nil {
  1398  			t.Fatalf("unexpected error: %s", err)
  1399  		}
  1400  		if err := s.RefreshState(); err != nil {
  1401  			t.Fatalf("unexpected error: %s", err)
  1402  		}
  1403  		state := s.State()
  1404  		if state == nil {
  1405  			t.Fatal("state should not be nil")
  1406  		}
  1407  		if testStateMgrCurrentLineage(s) != "backend-change-env2" {
  1408  			t.Fatalf("bad: %#v", state)
  1409  		}
  1410  	}
  1411  
  1412  	{
  1413  		// Verify existing workspaces exist
  1414  		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1415  		if _, err := os.Stat(envPath); err != nil {
  1416  			t.Fatalf("%s should exist, but does not", envPath)
  1417  		}
  1418  	}
  1419  
  1420  	{
  1421  		// Verify new workspaces exist
  1422  		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
  1423  		if _, err := os.Stat(envPath); err != nil {
  1424  			t.Fatalf("%s should exist, but does not", envPath)
  1425  		}
  1426  	}
  1427  }
  1428  
  1429  // Unsetting a saved backend
  1430  func TestMetaBackend_configuredUnset(t *testing.T) {
  1431  	// Create a temporary working directory that is empty
  1432  	td := tempDir(t)
  1433  	testCopyDir(t, testFixturePath("backend-unset"), td)
  1434  	defer os.RemoveAll(td)
  1435  	defer testChdir(t, td)()
  1436  
  1437  	// Ask input
  1438  	defer testInteractiveInput(t, []string{"no"})()
  1439  
  1440  	// Setup the meta
  1441  	m := testMetaBackend(t, nil)
  1442  
  1443  	// Get the backend
  1444  	b, diags := m.Backend(&BackendOpts{Init: true})
  1445  	if diags.HasErrors() {
  1446  		t.Fatal(diags.Err())
  1447  	}
  1448  
  1449  	// Check the state
  1450  	s, err := b.StateMgr(backend.DefaultStateName)
  1451  	if err != nil {
  1452  		t.Fatalf("unexpected error: %s", err)
  1453  	}
  1454  	if err := s.RefreshState(); err != nil {
  1455  		t.Fatalf("unexpected error: %s", err)
  1456  	}
  1457  	state := s.State()
  1458  	if state != nil {
  1459  		t.Fatal("state should be nil")
  1460  	}
  1461  
  1462  	// Verify the default paths don't exist
  1463  	if !isEmptyState(DefaultStateFilename) {
  1464  		data, _ := ioutil.ReadFile(DefaultStateFilename)
  1465  		t.Fatal("state should not exist, but contains:\n", string(data))
  1466  	}
  1467  
  1468  	// Verify a backup doesn't exist
  1469  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1470  		data, _ := ioutil.ReadFile(DefaultStateFilename + DefaultBackupExtension)
  1471  		t.Fatal("backup should not exist, but contains:\n", string(data))
  1472  	}
  1473  
  1474  	// Write some state
  1475  	s.WriteState(testState())
  1476  	if err := s.PersistState(); err != nil {
  1477  		t.Fatalf("unexpected error: %s", err)
  1478  	}
  1479  
  1480  	// Verify it exists where we expect it to
  1481  	if isEmptyState(DefaultStateFilename) {
  1482  		t.Fatal(DefaultStateFilename, "is empty")
  1483  	}
  1484  
  1485  	// Verify no backup since it was empty to start
  1486  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1487  		data, _ := ioutil.ReadFile(DefaultStateFilename + DefaultBackupExtension)
  1488  		t.Fatal("backup state should be empty, but contains:\n", string(data))
  1489  	}
  1490  }
  1491  
  1492  // Unsetting a saved backend and copying the remote state
  1493  func TestMetaBackend_configuredUnsetCopy(t *testing.T) {
  1494  	// Create a temporary working directory that is empty
  1495  	td := tempDir(t)
  1496  	testCopyDir(t, testFixturePath("backend-unset"), td)
  1497  	defer os.RemoveAll(td)
  1498  	defer testChdir(t, td)()
  1499  
  1500  	// Ask input
  1501  	defer testInteractiveInput(t, []string{"yes", "yes"})()
  1502  
  1503  	// Setup the meta
  1504  	m := testMetaBackend(t, nil)
  1505  
  1506  	// Get the backend
  1507  	b, diags := m.Backend(&BackendOpts{Init: true})
  1508  	if diags.HasErrors() {
  1509  		t.Fatal(diags.Err())
  1510  	}
  1511  
  1512  	// Check the state
  1513  	s, err := b.StateMgr(backend.DefaultStateName)
  1514  	if err != nil {
  1515  		t.Fatalf("unexpected error: %s", err)
  1516  	}
  1517  	if err := s.RefreshState(); err != nil {
  1518  		t.Fatalf("unexpected error: %s", err)
  1519  	}
  1520  	state := s.State()
  1521  	if state == nil {
  1522  		t.Fatal("state is nil")
  1523  	}
  1524  	if got, want := testStateMgrCurrentLineage(s), "configuredUnset"; got != want {
  1525  		t.Fatalf("wrong state lineage %q; want %q", got, want)
  1526  	}
  1527  
  1528  	// Verify a backup doesn't exist
  1529  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1530  		t.Fatalf("backup state should be empty")
  1531  	}
  1532  
  1533  	// Write some state
  1534  	s.WriteState(testState())
  1535  	if err := s.PersistState(); err != nil {
  1536  		t.Fatalf("unexpected error: %s", err)
  1537  	}
  1538  
  1539  	// Verify it exists where we expect it to
  1540  	if _, err := os.Stat(DefaultStateFilename); err != nil {
  1541  		t.Fatalf("err: %s", err)
  1542  	}
  1543  
  1544  	// Verify a backup since it wasn't empty to start
  1545  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1546  		t.Fatal("backup is empty")
  1547  	}
  1548  }
  1549  
  1550  // A plan that has uses the local backend
  1551  func TestMetaBackend_planLocal(t *testing.T) {
  1552  	// Create a temporary working directory that is empty
  1553  	td := tempDir(t)
  1554  	testCopyDir(t, testFixturePath("backend-plan-local"), td)
  1555  	defer os.RemoveAll(td)
  1556  	defer testChdir(t, td)()
  1557  
  1558  	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
  1559  		"path":          cty.NullVal(cty.String),
  1560  		"workspace_dir": cty.NullVal(cty.String),
  1561  	})
  1562  	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
  1563  	if err != nil {
  1564  		t.Fatal(err)
  1565  	}
  1566  	backendConfig := plans.Backend{
  1567  		Type:      "local",
  1568  		Config:    backendConfigRaw,
  1569  		Workspace: "default",
  1570  	}
  1571  
  1572  	// Setup the meta
  1573  	m := testMetaBackend(t, nil)
  1574  
  1575  	// Get the backend
  1576  	b, diags := m.BackendForPlan(backendConfig)
  1577  	if diags.HasErrors() {
  1578  		t.Fatal(diags.Err())
  1579  	}
  1580  
  1581  	// Check the state
  1582  	s, err := b.StateMgr(backend.DefaultStateName)
  1583  	if err != nil {
  1584  		t.Fatalf("unexpected error: %s", err)
  1585  	}
  1586  	if err := s.RefreshState(); err != nil {
  1587  		t.Fatalf("unexpected error: %s", err)
  1588  	}
  1589  	state := s.State()
  1590  	if state != nil {
  1591  		t.Fatalf("state should be nil: %#v", state)
  1592  	}
  1593  
  1594  	// The default state file should not exist yet
  1595  	if !isEmptyState(DefaultStateFilename) {
  1596  		t.Fatal("expected empty state")
  1597  	}
  1598  
  1599  	// A backup file shouldn't exist yet either.
  1600  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1601  		t.Fatal("expected empty backup")
  1602  	}
  1603  
  1604  	// Verify we have no configured backend
  1605  	path := filepath.Join(m.DataDir(), DefaultStateFilename)
  1606  	if _, err := os.Stat(path); err == nil {
  1607  		t.Fatalf("should not have backend configured")
  1608  	}
  1609  
  1610  	// Write some state
  1611  	state = states.NewState()
  1612  	mark := markStateForMatching(state, "changing")
  1613  
  1614  	s.WriteState(state)
  1615  	if err := s.PersistState(); err != nil {
  1616  		t.Fatalf("unexpected error: %s", err)
  1617  	}
  1618  
  1619  	// Verify the state is where we expect
  1620  	{
  1621  		f, err := os.Open(DefaultStateFilename)
  1622  		if err != nil {
  1623  			t.Fatalf("err: %s", err)
  1624  		}
  1625  		actual, err := statefile.Read(f)
  1626  		f.Close()
  1627  		if err != nil {
  1628  			t.Fatalf("err: %s", err)
  1629  		}
  1630  
  1631  		assertStateHasMarker(t, actual.State, mark)
  1632  	}
  1633  
  1634  	// Verify no local backup
  1635  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1636  		t.Fatalf("backup state should be empty")
  1637  	}
  1638  }
  1639  
  1640  // A plan with a custom state save path
  1641  func TestMetaBackend_planLocalStatePath(t *testing.T) {
  1642  	td := tempDir(t)
  1643  	testCopyDir(t, testFixturePath("backend-plan-local"), td)
  1644  	defer os.RemoveAll(td)
  1645  	defer testChdir(t, td)()
  1646  
  1647  	original := testState()
  1648  	markStateForMatching(original, "hello")
  1649  
  1650  	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
  1651  		"path":          cty.NullVal(cty.String),
  1652  		"workspace_dir": cty.NullVal(cty.String),
  1653  	})
  1654  	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
  1655  	if err != nil {
  1656  		t.Fatal(err)
  1657  	}
  1658  	plannedBackend := plans.Backend{
  1659  		Type:      "local",
  1660  		Config:    backendConfigRaw,
  1661  		Workspace: "default",
  1662  	}
  1663  
  1664  	// Create an alternate output path
  1665  	statePath := "foo.tfstate"
  1666  
  1667  	// put an initial state there that needs to be backed up
  1668  	err = (statemgr.NewFilesystem(statePath)).WriteState(original)
  1669  	if err != nil {
  1670  		t.Fatal(err)
  1671  	}
  1672  
  1673  	// Setup the meta
  1674  	m := testMetaBackend(t, nil)
  1675  	m.stateOutPath = statePath
  1676  
  1677  	// Get the backend
  1678  	b, diags := m.BackendForPlan(plannedBackend)
  1679  	if diags.HasErrors() {
  1680  		t.Fatal(diags.Err())
  1681  	}
  1682  
  1683  	// Check the state
  1684  	s, err := b.StateMgr(backend.DefaultStateName)
  1685  	if err != nil {
  1686  		t.Fatalf("unexpected error: %s", err)
  1687  	}
  1688  	if err := s.RefreshState(); err != nil {
  1689  		t.Fatalf("unexpected error: %s", err)
  1690  	}
  1691  	state := s.State()
  1692  	if state != nil {
  1693  		t.Fatal("default workspace state is not nil, but should be because we've not put anything there")
  1694  	}
  1695  
  1696  	// Verify the default path doesn't exist
  1697  	if _, err := os.Stat(DefaultStateFilename); err == nil {
  1698  		t.Fatalf("err: %s", err)
  1699  	}
  1700  
  1701  	// Verify a backup doesn't exists
  1702  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1703  		t.Fatal("file should not exist")
  1704  	}
  1705  
  1706  	// Verify we have no configured backend/legacy
  1707  	path := filepath.Join(m.DataDir(), DefaultStateFilename)
  1708  	if _, err := os.Stat(path); err == nil {
  1709  		t.Fatalf("should not have backend configured")
  1710  	}
  1711  
  1712  	// Write some state
  1713  	state = states.NewState()
  1714  	mark := markStateForMatching(state, "changing")
  1715  
  1716  	s.WriteState(state)
  1717  	if err := s.PersistState(); err != nil {
  1718  		t.Fatalf("unexpected error: %s", err)
  1719  	}
  1720  
  1721  	// Verify the state is where we expect
  1722  	{
  1723  		f, err := os.Open(statePath)
  1724  		if err != nil {
  1725  			t.Fatalf("err: %s", err)
  1726  		}
  1727  		actual, err := statefile.Read(f)
  1728  		f.Close()
  1729  		if err != nil {
  1730  			t.Fatalf("err: %s", err)
  1731  		}
  1732  
  1733  		assertStateHasMarker(t, actual.State, mark)
  1734  	}
  1735  
  1736  	// Verify we have a backup
  1737  	if isEmptyState(statePath + DefaultBackupExtension) {
  1738  		t.Fatal("backup is empty")
  1739  	}
  1740  }
  1741  
  1742  // A plan that has no backend config, matching local state
  1743  func TestMetaBackend_planLocalMatch(t *testing.T) {
  1744  	// Create a temporary working directory that is empty
  1745  	td := tempDir(t)
  1746  	testCopyDir(t, testFixturePath("backend-plan-local-match"), td)
  1747  	defer os.RemoveAll(td)
  1748  	defer testChdir(t, td)()
  1749  
  1750  	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
  1751  		"path":          cty.NullVal(cty.String),
  1752  		"workspace_dir": cty.NullVal(cty.String),
  1753  	})
  1754  	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
  1755  	if err != nil {
  1756  		t.Fatal(err)
  1757  	}
  1758  	backendConfig := plans.Backend{
  1759  		Type:      "local",
  1760  		Config:    backendConfigRaw,
  1761  		Workspace: "default",
  1762  	}
  1763  
  1764  	// Setup the meta
  1765  	m := testMetaBackend(t, nil)
  1766  
  1767  	// Get the backend
  1768  	b, diags := m.BackendForPlan(backendConfig)
  1769  	if diags.HasErrors() {
  1770  		t.Fatal(diags.Err())
  1771  	}
  1772  
  1773  	// Check the state
  1774  	s, err := b.StateMgr(backend.DefaultStateName)
  1775  	if err != nil {
  1776  		t.Fatalf("unexpected error: %s", err)
  1777  	}
  1778  	if err := s.RefreshState(); err != nil {
  1779  		t.Fatalf("unexpected error: %s", err)
  1780  	}
  1781  	state := s.State()
  1782  	if state == nil {
  1783  		t.Fatal("should is nil")
  1784  	}
  1785  	if testStateMgrCurrentLineage(s) != "hello" {
  1786  		t.Fatalf("bad: %#v", state)
  1787  	}
  1788  
  1789  	// Verify the default path
  1790  	if isEmptyState(DefaultStateFilename) {
  1791  		t.Fatal("state is empty")
  1792  	}
  1793  
  1794  	// Verify we have no configured backend/legacy
  1795  	path := filepath.Join(m.DataDir(), DefaultStateFilename)
  1796  	if _, err := os.Stat(path); err == nil {
  1797  		t.Fatalf("should not have backend configured")
  1798  	}
  1799  
  1800  	// Write some state
  1801  	state = states.NewState()
  1802  	mark := markStateForMatching(state, "changing")
  1803  
  1804  	s.WriteState(state)
  1805  	if err := s.PersistState(); err != nil {
  1806  		t.Fatalf("unexpected error: %s", err)
  1807  	}
  1808  
  1809  	// Verify the state is where we expect
  1810  	{
  1811  		f, err := os.Open(DefaultStateFilename)
  1812  		if err != nil {
  1813  			t.Fatalf("err: %s", err)
  1814  		}
  1815  		actual, err := statefile.Read(f)
  1816  		f.Close()
  1817  		if err != nil {
  1818  			t.Fatalf("err: %s", err)
  1819  		}
  1820  
  1821  		assertStateHasMarker(t, actual.State, mark)
  1822  	}
  1823  
  1824  	// Verify local backup
  1825  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1826  		t.Fatal("backup is empty")
  1827  	}
  1828  }
  1829  
  1830  // init a backend using -backend-config options multiple times
  1831  func TestMetaBackend_configureWithExtra(t *testing.T) {
  1832  	// Create a temporary working directory that is empty
  1833  	td := tempDir(t)
  1834  	testCopyDir(t, testFixturePath("init-backend-empty"), td)
  1835  	defer os.RemoveAll(td)
  1836  	defer testChdir(t, td)()
  1837  
  1838  	extras := map[string]cty.Value{"path": cty.StringVal("hello")}
  1839  	m := testMetaBackend(t, nil)
  1840  	opts := &BackendOpts{
  1841  		ConfigOverride: configs.SynthBody("synth", extras),
  1842  		Init:           true,
  1843  	}
  1844  
  1845  	_, cHash, err := m.backendConfig(opts)
  1846  	if err != nil {
  1847  		t.Fatal(err)
  1848  	}
  1849  
  1850  	// init the backend
  1851  	_, diags := m.Backend(&BackendOpts{
  1852  		ConfigOverride: configs.SynthBody("synth", extras),
  1853  		Init:           true,
  1854  	})
  1855  	if diags.HasErrors() {
  1856  		t.Fatal(diags.Err())
  1857  	}
  1858  
  1859  	// Check the state
  1860  	s := testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1861  	if s.Backend.Hash != uint64(cHash) {
  1862  		t.Fatal("mismatched state and config backend hashes")
  1863  	}
  1864  
  1865  	// init the backend again with the same options
  1866  	m = testMetaBackend(t, nil)
  1867  	_, err = m.Backend(&BackendOpts{
  1868  		ConfigOverride: configs.SynthBody("synth", extras),
  1869  		Init:           true,
  1870  	})
  1871  	if err != nil {
  1872  		t.Fatalf("unexpected error: %s", err)
  1873  	}
  1874  
  1875  	// Check the state
  1876  	s = testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1877  	if s.Backend.Hash != uint64(cHash) {
  1878  		t.Fatal("mismatched state and config backend hashes")
  1879  	}
  1880  }
  1881  
  1882  // when configuring a default local state, don't delete local state
  1883  func TestMetaBackend_localDoesNotDeleteLocal(t *testing.T) {
  1884  	// Create a temporary working directory that is empty
  1885  	td := tempDir(t)
  1886  	testCopyDir(t, testFixturePath("init-backend-empty"), td)
  1887  	defer os.RemoveAll(td)
  1888  	defer testChdir(t, td)()
  1889  
  1890  	// // create our local state
  1891  	orig := states.NewState()
  1892  	orig.Module(addrs.RootModuleInstance).SetOutputValue("foo", cty.StringVal("bar"), false)
  1893  	testStateFileDefault(t, orig)
  1894  
  1895  	m := testMetaBackend(t, nil)
  1896  	m.forceInitCopy = true
  1897  	// init the backend
  1898  	_, diags := m.Backend(&BackendOpts{Init: true})
  1899  	if diags.HasErrors() {
  1900  		t.Fatal(diags.Err())
  1901  	}
  1902  
  1903  	// check that we can read the state
  1904  	s := testStateRead(t, DefaultStateFilename)
  1905  	if s.Empty() {
  1906  		t.Fatal("our state was deleted")
  1907  	}
  1908  }
  1909  
  1910  // move options from config to -backend-config
  1911  func TestMetaBackend_configToExtra(t *testing.T) {
  1912  	// Create a temporary working directory that is empty
  1913  	td := tempDir(t)
  1914  	testCopyDir(t, testFixturePath("init-backend"), td)
  1915  	defer os.RemoveAll(td)
  1916  	defer testChdir(t, td)()
  1917  
  1918  	// init the backend
  1919  	m := testMetaBackend(t, nil)
  1920  	_, err := m.Backend(&BackendOpts{
  1921  		Init: true,
  1922  	})
  1923  	if err != nil {
  1924  		t.Fatalf("unexpected error: %s", err)
  1925  	}
  1926  
  1927  	// Check the state
  1928  	s := testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1929  	backendHash := s.Backend.Hash
  1930  
  1931  	// init again but remove the path option from the config
  1932  	cfg := "terraform {\n  backend \"local\" {}\n}\n"
  1933  	if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil {
  1934  		t.Fatal(err)
  1935  	}
  1936  
  1937  	// init the backend again with the  options
  1938  	extras := map[string]cty.Value{"path": cty.StringVal("hello")}
  1939  	m = testMetaBackend(t, nil)
  1940  	m.forceInitCopy = true
  1941  	_, diags := m.Backend(&BackendOpts{
  1942  		ConfigOverride: configs.SynthBody("synth", extras),
  1943  		Init:           true,
  1944  	})
  1945  	if diags.HasErrors() {
  1946  		t.Fatal(diags.Err())
  1947  	}
  1948  
  1949  	s = testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1950  
  1951  	if s.Backend.Hash == backendHash {
  1952  		t.Fatal("state.Backend.Hash was not updated")
  1953  	}
  1954  }
  1955  
  1956  // no config; return inmem backend stored in state
  1957  func TestBackendFromState(t *testing.T) {
  1958  	wd := tempWorkingDirFixture(t, "backend-from-state")
  1959  	defer testChdir(t, wd.RootModuleDir())()
  1960  
  1961  	// Setup the meta
  1962  	m := testMetaBackend(t, nil)
  1963  	m.WorkingDir = wd
  1964  	// terraform caches a small "state" file that stores the backend config.
  1965  	// This test must override m.dataDir so it loads the "terraform.tfstate" file in the
  1966  	// test directory as the backend config cache. This fixture is really a
  1967  	// fixture for the data dir rather than the module dir, so we'll override
  1968  	// them to match just for this test.
  1969  	wd.OverrideDataDir(".")
  1970  
  1971  	stateBackend, diags := m.backendFromState()
  1972  	if diags.HasErrors() {
  1973  		t.Fatal(diags.Err())
  1974  	}
  1975  
  1976  	if _, ok := stateBackend.(*backendInmem.Backend); !ok {
  1977  		t.Fatal("did not get expected inmem backend")
  1978  	}
  1979  }
  1980  
  1981  func testMetaBackend(t *testing.T, args []string) *Meta {
  1982  	var m Meta
  1983  	m.Ui = new(cli.MockUi)
  1984  	view, _ := testView(t)
  1985  	m.View = view
  1986  	m.process(args)
  1987  	f := m.extendedFlagSet("test")
  1988  	if err := f.Parse(args); err != nil {
  1989  		t.Fatalf("unexpected error: %s", err)
  1990  	}
  1991  
  1992  	// metaBackend tests are verifying migrate actions
  1993  	m.migrateState = true
  1994  
  1995  	return &m
  1996  }