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 }