github.com/opentofu/opentofu@v1.7.1/internal/command/meta_backend_test.go (about)

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