github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/state_push_test.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/terraform/backend"
    10  	"github.com/hashicorp/terraform/backend/remote-state/inmem"
    11  	"github.com/hashicorp/terraform/helper/copy"
    12  	"github.com/hashicorp/terraform/states"
    13  	"github.com/mitchellh/cli"
    14  )
    15  
    16  func TestStatePush_empty(t *testing.T) {
    17  	// Create a temporary working directory that is empty
    18  	td := tempDir(t)
    19  	copy.CopyDir(testFixturePath("state-push-good"), td)
    20  	defer os.RemoveAll(td)
    21  	defer testChdir(t, td)()
    22  
    23  	expected := testStateRead(t, "replace.tfstate")
    24  
    25  	p := testProvider()
    26  	ui := new(cli.MockUi)
    27  	c := &StatePushCommand{
    28  		Meta: Meta{
    29  			testingOverrides: metaOverridesForProvider(p),
    30  			Ui:               ui,
    31  		},
    32  	}
    33  
    34  	args := []string{"replace.tfstate"}
    35  	if code := c.Run(args); code != 0 {
    36  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    37  	}
    38  
    39  	actual := testStateRead(t, "local-state.tfstate")
    40  	if !actual.Equal(expected) {
    41  		t.Fatalf("bad: %#v", actual)
    42  	}
    43  }
    44  
    45  func TestStatePush_lockedState(t *testing.T) {
    46  	// Create a temporary working directory that is empty
    47  	td := tempDir(t)
    48  	copy.CopyDir(testFixturePath("state-push-good"), td)
    49  	defer os.RemoveAll(td)
    50  	defer testChdir(t, td)()
    51  
    52  	p := testProvider()
    53  	ui := new(cli.MockUi)
    54  	c := &StatePushCommand{
    55  		Meta: Meta{
    56  			testingOverrides: metaOverridesForProvider(p),
    57  			Ui:               ui,
    58  		},
    59  	}
    60  
    61  	unlock, err := testLockState(testDataDir, "local-state.tfstate")
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  	defer unlock()
    66  
    67  	args := []string{"replace.tfstate"}
    68  	if code := c.Run(args); code != 1 {
    69  		t.Fatalf("bad: %d", code)
    70  	}
    71  	if !strings.Contains(ui.ErrorWriter.String(), "Error acquiring the state lock") {
    72  		t.Fatalf("expected a lock error, got: %s", ui.ErrorWriter.String())
    73  	}
    74  }
    75  
    76  func TestStatePush_replaceMatch(t *testing.T) {
    77  	// Create a temporary working directory that is empty
    78  	td := tempDir(t)
    79  	copy.CopyDir(testFixturePath("state-push-replace-match"), td)
    80  	defer os.RemoveAll(td)
    81  	defer testChdir(t, td)()
    82  
    83  	expected := testStateRead(t, "replace.tfstate")
    84  
    85  	p := testProvider()
    86  	ui := new(cli.MockUi)
    87  	c := &StatePushCommand{
    88  		Meta: Meta{
    89  			testingOverrides: metaOverridesForProvider(p),
    90  			Ui:               ui,
    91  		},
    92  	}
    93  
    94  	args := []string{"replace.tfstate"}
    95  	if code := c.Run(args); code != 0 {
    96  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    97  	}
    98  
    99  	actual := testStateRead(t, "local-state.tfstate")
   100  	if !actual.Equal(expected) {
   101  		t.Fatalf("bad: %#v", actual)
   102  	}
   103  }
   104  
   105  func TestStatePush_replaceMatchStdin(t *testing.T) {
   106  	// Create a temporary working directory that is empty
   107  	td := tempDir(t)
   108  	copy.CopyDir(testFixturePath("state-push-replace-match"), td)
   109  	defer os.RemoveAll(td)
   110  	defer testChdir(t, td)()
   111  
   112  	expected := testStateRead(t, "replace.tfstate")
   113  
   114  	// Setup the replacement to come from stdin
   115  	var buf bytes.Buffer
   116  	if err := writeStateForTesting(expected, &buf); err != nil {
   117  		t.Fatalf("err: %s", err)
   118  	}
   119  	defer testStdinPipe(t, &buf)()
   120  
   121  	p := testProvider()
   122  	ui := new(cli.MockUi)
   123  	c := &StatePushCommand{
   124  		Meta: Meta{
   125  			testingOverrides: metaOverridesForProvider(p),
   126  			Ui:               ui,
   127  		},
   128  	}
   129  
   130  	args := []string{"-force", "-"}
   131  	if code := c.Run(args); code != 0 {
   132  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   133  	}
   134  
   135  	actual := testStateRead(t, "local-state.tfstate")
   136  	if !actual.Equal(expected) {
   137  		t.Fatalf("bad: %#v", actual)
   138  	}
   139  }
   140  
   141  func TestStatePush_lineageMismatch(t *testing.T) {
   142  	// Create a temporary working directory that is empty
   143  	td := tempDir(t)
   144  	copy.CopyDir(testFixturePath("state-push-bad-lineage"), td)
   145  	defer os.RemoveAll(td)
   146  	defer testChdir(t, td)()
   147  
   148  	expected := testStateRead(t, "local-state.tfstate")
   149  
   150  	p := testProvider()
   151  	ui := cli.NewMockUi()
   152  	c := &StatePushCommand{
   153  		Meta: Meta{
   154  			testingOverrides: metaOverridesForProvider(p),
   155  			Ui:               ui,
   156  		},
   157  	}
   158  
   159  	args := []string{"replace.tfstate"}
   160  	if code := c.Run(args); code != 1 {
   161  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   162  	}
   163  
   164  	actual := testStateRead(t, "local-state.tfstate")
   165  	if !actual.Equal(expected) {
   166  		t.Fatalf("bad: %#v", actual)
   167  	}
   168  }
   169  
   170  func TestStatePush_serialNewer(t *testing.T) {
   171  	// Create a temporary working directory that is empty
   172  	td := tempDir(t)
   173  	copy.CopyDir(testFixturePath("state-push-serial-newer"), td)
   174  	defer os.RemoveAll(td)
   175  	defer testChdir(t, td)()
   176  
   177  	expected := testStateRead(t, "local-state.tfstate")
   178  
   179  	p := testProvider()
   180  	ui := new(cli.MockUi)
   181  	c := &StatePushCommand{
   182  		Meta: Meta{
   183  			testingOverrides: metaOverridesForProvider(p),
   184  			Ui:               ui,
   185  		},
   186  	}
   187  
   188  	args := []string{"replace.tfstate"}
   189  	if code := c.Run(args); code != 1 {
   190  		t.Fatalf("bad: %d", code)
   191  	}
   192  
   193  	actual := testStateRead(t, "local-state.tfstate")
   194  	if !actual.Equal(expected) {
   195  		t.Fatalf("bad: %#v", actual)
   196  	}
   197  }
   198  
   199  func TestStatePush_serialOlder(t *testing.T) {
   200  	// Create a temporary working directory that is empty
   201  	td := tempDir(t)
   202  	copy.CopyDir(testFixturePath("state-push-serial-older"), td)
   203  	defer os.RemoveAll(td)
   204  	defer testChdir(t, td)()
   205  
   206  	expected := testStateRead(t, "replace.tfstate")
   207  
   208  	p := testProvider()
   209  	ui := new(cli.MockUi)
   210  	c := &StatePushCommand{
   211  		Meta: Meta{
   212  			testingOverrides: metaOverridesForProvider(p),
   213  			Ui:               ui,
   214  		},
   215  	}
   216  
   217  	args := []string{"replace.tfstate"}
   218  	if code := c.Run(args); code != 0 {
   219  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   220  	}
   221  
   222  	actual := testStateRead(t, "local-state.tfstate")
   223  	if !actual.Equal(expected) {
   224  		t.Fatalf("bad: %#v", actual)
   225  	}
   226  }
   227  
   228  func TestStatePush_forceRemoteState(t *testing.T) {
   229  	td := tempDir(t)
   230  	copy.CopyDir(testFixturePath("inmem-backend"), td)
   231  	defer os.RemoveAll(td)
   232  	defer testChdir(t, td)()
   233  	defer inmem.Reset()
   234  
   235  	s := states.NewState()
   236  	statePath := testStateFile(t, s)
   237  
   238  	// init the backend
   239  	ui := new(cli.MockUi)
   240  	initCmd := &InitCommand{
   241  		Meta: Meta{Ui: ui},
   242  	}
   243  	if code := initCmd.Run([]string{}); code != 0 {
   244  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   245  	}
   246  
   247  	// create a new workspace
   248  	ui = new(cli.MockUi)
   249  	newCmd := &WorkspaceNewCommand{
   250  		Meta: Meta{Ui: ui},
   251  	}
   252  	if code := newCmd.Run([]string{"test"}); code != 0 {
   253  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
   254  	}
   255  
   256  	// put a dummy state in place, so we have something to force
   257  	b := backend.TestBackendConfig(t, inmem.New(), nil)
   258  	sMgr, err := b.StateMgr("test")
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  	if err := sMgr.WriteState(states.NewState()); err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	if err := sMgr.PersistState(); err != nil {
   266  		t.Fatal(err)
   267  	}
   268  
   269  	// push our local state to that new workspace
   270  	ui = new(cli.MockUi)
   271  	c := &StatePushCommand{
   272  		Meta: Meta{Ui: ui},
   273  	}
   274  
   275  	args := []string{"-force", statePath}
   276  	if code := c.Run(args); code != 0 {
   277  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   278  	}
   279  }