kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/command/state_push_test.go (about)

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