github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/command/state_rm_test.go (about) 1 package command 2 3 import ( 4 "os" 5 "path/filepath" 6 "strings" 7 "testing" 8 9 "github.com/mitchellh/cli" 10 11 "github.com/iaas-resource-provision/iaas-rpc/internal/addrs" 12 "github.com/iaas-resource-provision/iaas-rpc/internal/states" 13 ) 14 15 func TestStateRm(t *testing.T) { 16 state := states.BuildState(func(s *states.SyncState) { 17 s.SetResourceInstanceCurrent( 18 addrs.Resource{ 19 Mode: addrs.ManagedResourceMode, 20 Type: "test_instance", 21 Name: "foo", 22 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 23 &states.ResourceInstanceObjectSrc{ 24 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 25 Status: states.ObjectReady, 26 }, 27 addrs.AbsProviderConfig{ 28 Provider: addrs.NewDefaultProvider("test"), 29 Module: addrs.RootModule, 30 }, 31 ) 32 s.SetResourceInstanceCurrent( 33 addrs.Resource{ 34 Mode: addrs.ManagedResourceMode, 35 Type: "test_instance", 36 Name: "bar", 37 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 38 &states.ResourceInstanceObjectSrc{ 39 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 40 Status: states.ObjectReady, 41 }, 42 addrs.AbsProviderConfig{ 43 Provider: addrs.NewDefaultProvider("test"), 44 Module: addrs.RootModule, 45 }, 46 ) 47 }) 48 statePath := testStateFile(t, state) 49 50 p := testProvider() 51 ui := new(cli.MockUi) 52 view, _ := testView(t) 53 c := &StateRmCommand{ 54 StateMeta{ 55 Meta: Meta{ 56 testingOverrides: metaOverridesForProvider(p), 57 Ui: ui, 58 View: view, 59 }, 60 }, 61 } 62 63 args := []string{ 64 "-state", statePath, 65 "test_instance.foo", 66 } 67 if code := c.Run(args); code != 0 { 68 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 69 } 70 71 // Test it is correct 72 testStateOutput(t, statePath, testStateRmOutput) 73 74 // Test we have backups 75 backups := testStateBackups(t, filepath.Dir(statePath)) 76 if len(backups) != 1 { 77 t.Fatalf("bad: %#v", backups) 78 } 79 testStateOutput(t, backups[0], testStateRmOutputOriginal) 80 } 81 82 func TestStateRmNotChildModule(t *testing.T) { 83 state := states.BuildState(func(s *states.SyncState) { 84 s.SetResourceInstanceCurrent( 85 addrs.Resource{ 86 Mode: addrs.ManagedResourceMode, 87 Type: "test_instance", 88 Name: "foo", 89 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 90 &states.ResourceInstanceObjectSrc{ 91 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 92 Status: states.ObjectReady, 93 }, 94 addrs.AbsProviderConfig{ 95 Provider: addrs.NewDefaultProvider("test"), 96 Module: addrs.RootModule, 97 }, 98 ) 99 // This second instance has the same local address as the first but 100 // is in a child module. Older versions of Terraform would incorrectly 101 // remove this one too, since they failed to check the module address. 102 s.SetResourceInstanceCurrent( 103 addrs.Resource{ 104 Mode: addrs.ManagedResourceMode, 105 Type: "test_instance", 106 Name: "foo", 107 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)), 108 &states.ResourceInstanceObjectSrc{ 109 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 110 Status: states.ObjectReady, 111 }, 112 addrs.AbsProviderConfig{ 113 Provider: addrs.NewDefaultProvider("test"), 114 Module: addrs.RootModule, 115 }, 116 ) 117 }) 118 statePath := testStateFile(t, state) 119 120 p := testProvider() 121 ui := new(cli.MockUi) 122 view, _ := testView(t) 123 c := &StateRmCommand{ 124 StateMeta{ 125 Meta: Meta{ 126 testingOverrides: metaOverridesForProvider(p), 127 Ui: ui, 128 View: view, 129 }, 130 }, 131 } 132 133 args := []string{ 134 "-state", statePath, 135 "test_instance.foo", 136 } 137 if code := c.Run(args); code != 0 { 138 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 139 } 140 141 // Test it is correct 142 testStateOutput(t, statePath, ` 143 <no state> 144 module.child: 145 test_instance.foo: 146 ID = foo 147 provider = provider["registry.terraform.io/hashicorp/test"] 148 bar = value 149 foo = value 150 `) 151 152 // Test we have backups 153 backups := testStateBackups(t, filepath.Dir(statePath)) 154 if len(backups) != 1 { 155 t.Fatalf("bad: %#v", backups) 156 } 157 testStateOutput(t, backups[0], ` 158 test_instance.foo: 159 ID = bar 160 provider = provider["registry.terraform.io/hashicorp/test"] 161 bar = value 162 foo = value 163 164 module.child: 165 test_instance.foo: 166 ID = foo 167 provider = provider["registry.terraform.io/hashicorp/test"] 168 bar = value 169 foo = value 170 `) 171 } 172 173 func TestStateRmNoArgs(t *testing.T) { 174 state := states.BuildState(func(s *states.SyncState) { 175 s.SetResourceInstanceCurrent( 176 addrs.Resource{ 177 Mode: addrs.ManagedResourceMode, 178 Type: "test_instance", 179 Name: "foo", 180 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 181 &states.ResourceInstanceObjectSrc{ 182 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 183 Status: states.ObjectReady, 184 }, 185 addrs.AbsProviderConfig{ 186 Provider: addrs.NewDefaultProvider("test"), 187 Module: addrs.RootModule, 188 }, 189 ) 190 s.SetResourceInstanceCurrent( 191 addrs.Resource{ 192 Mode: addrs.ManagedResourceMode, 193 Type: "test_instance", 194 Name: "bar", 195 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 196 &states.ResourceInstanceObjectSrc{ 197 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 198 Status: states.ObjectReady, 199 }, 200 addrs.AbsProviderConfig{ 201 Provider: addrs.NewDefaultProvider("test"), 202 Module: addrs.RootModule, 203 }, 204 ) 205 }) 206 statePath := testStateFile(t, state) 207 208 p := testProvider() 209 ui := new(cli.MockUi) 210 view, _ := testView(t) 211 c := &StateRmCommand{ 212 StateMeta{ 213 Meta: Meta{ 214 testingOverrides: metaOverridesForProvider(p), 215 Ui: ui, 216 View: view, 217 }, 218 }, 219 } 220 221 args := []string{ 222 "-state", statePath, 223 } 224 if code := c.Run(args); code == 0 { 225 t.Errorf("expected non-zero exit code, got: %d", code) 226 } 227 228 if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one address") { 229 t.Errorf("not the error we were looking for:\n%s", msg) 230 } 231 232 } 233 234 func TestStateRmNonExist(t *testing.T) { 235 state := states.BuildState(func(s *states.SyncState) { 236 s.SetResourceInstanceCurrent( 237 addrs.Resource{ 238 Mode: addrs.ManagedResourceMode, 239 Type: "test_instance", 240 Name: "foo", 241 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 242 &states.ResourceInstanceObjectSrc{ 243 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 244 Status: states.ObjectReady, 245 }, 246 addrs.AbsProviderConfig{ 247 Provider: addrs.NewDefaultProvider("test"), 248 Module: addrs.RootModule, 249 }, 250 ) 251 s.SetResourceInstanceCurrent( 252 addrs.Resource{ 253 Mode: addrs.ManagedResourceMode, 254 Type: "test_instance", 255 Name: "bar", 256 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 257 &states.ResourceInstanceObjectSrc{ 258 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 259 Status: states.ObjectReady, 260 }, 261 addrs.AbsProviderConfig{ 262 Provider: addrs.NewDefaultProvider("test"), 263 Module: addrs.RootModule, 264 }, 265 ) 266 }) 267 statePath := testStateFile(t, state) 268 269 p := testProvider() 270 ui := new(cli.MockUi) 271 view, _ := testView(t) 272 c := &StateRmCommand{ 273 StateMeta{ 274 Meta: Meta{ 275 testingOverrides: metaOverridesForProvider(p), 276 Ui: ui, 277 View: view, 278 }, 279 }, 280 } 281 282 args := []string{ 283 "-state", statePath, 284 "test_instance.baz", // doesn't exist in the state constructed above 285 } 286 if code := c.Run(args); code != 1 { 287 t.Fatalf("expected exit status %d, got: %d", 1, code) 288 } 289 } 290 291 func TestStateRm_backupExplicit(t *testing.T) { 292 state := states.BuildState(func(s *states.SyncState) { 293 s.SetResourceInstanceCurrent( 294 addrs.Resource{ 295 Mode: addrs.ManagedResourceMode, 296 Type: "test_instance", 297 Name: "foo", 298 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 299 &states.ResourceInstanceObjectSrc{ 300 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 301 Status: states.ObjectReady, 302 }, 303 addrs.AbsProviderConfig{ 304 Provider: addrs.NewDefaultProvider("test"), 305 Module: addrs.RootModule, 306 }, 307 ) 308 s.SetResourceInstanceCurrent( 309 addrs.Resource{ 310 Mode: addrs.ManagedResourceMode, 311 Type: "test_instance", 312 Name: "bar", 313 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 314 &states.ResourceInstanceObjectSrc{ 315 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 316 Status: states.ObjectReady, 317 }, 318 addrs.AbsProviderConfig{ 319 Provider: addrs.NewDefaultProvider("test"), 320 Module: addrs.RootModule, 321 }, 322 ) 323 }) 324 statePath := testStateFile(t, state) 325 backupPath := statePath + ".backup.test" 326 327 p := testProvider() 328 ui := new(cli.MockUi) 329 view, _ := testView(t) 330 c := &StateRmCommand{ 331 StateMeta{ 332 Meta: Meta{ 333 testingOverrides: metaOverridesForProvider(p), 334 Ui: ui, 335 View: view, 336 }, 337 }, 338 } 339 340 args := []string{ 341 "-backup", backupPath, 342 "-state", statePath, 343 "test_instance.foo", 344 } 345 if code := c.Run(args); code != 0 { 346 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 347 } 348 349 // Test it is correct 350 testStateOutput(t, statePath, testStateRmOutput) 351 352 // Test backup 353 testStateOutput(t, backupPath, testStateRmOutputOriginal) 354 } 355 356 func TestStateRm_noState(t *testing.T) { 357 tmp, cwd := testCwd(t) 358 defer testFixCwd(t, tmp, cwd) 359 360 p := testProvider() 361 ui := new(cli.MockUi) 362 view, _ := testView(t) 363 c := &StateRmCommand{ 364 StateMeta{ 365 Meta: Meta{ 366 testingOverrides: metaOverridesForProvider(p), 367 Ui: ui, 368 View: view, 369 }, 370 }, 371 } 372 373 args := []string{"foo"} 374 if code := c.Run(args); code != 1 { 375 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 376 } 377 } 378 379 func TestStateRm_needsInit(t *testing.T) { 380 td := tempDir(t) 381 testCopyDir(t, testFixturePath("backend-change"), td) 382 defer os.RemoveAll(td) 383 defer testChdir(t, td)() 384 385 p := testProvider() 386 ui := new(cli.MockUi) 387 view, _ := testView(t) 388 c := &StateRmCommand{ 389 StateMeta{ 390 Meta: Meta{ 391 testingOverrides: metaOverridesForProvider(p), 392 Ui: ui, 393 View: view, 394 }, 395 }, 396 } 397 398 args := []string{"foo"} 399 if code := c.Run(args); code == 0 { 400 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 401 } 402 403 if !strings.Contains(ui.ErrorWriter.String(), "Backend initialization") { 404 t.Fatalf("expected initialization error, got:\n%s", ui.ErrorWriter.String()) 405 } 406 } 407 408 func TestStateRm_backendState(t *testing.T) { 409 td := tempDir(t) 410 testCopyDir(t, testFixturePath("backend-unchanged"), td) 411 defer os.RemoveAll(td) 412 defer testChdir(t, td)() 413 414 state := states.BuildState(func(s *states.SyncState) { 415 s.SetResourceInstanceCurrent( 416 addrs.Resource{ 417 Mode: addrs.ManagedResourceMode, 418 Type: "test_instance", 419 Name: "foo", 420 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 421 &states.ResourceInstanceObjectSrc{ 422 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 423 Status: states.ObjectReady, 424 }, 425 addrs.AbsProviderConfig{ 426 Provider: addrs.NewDefaultProvider("test"), 427 Module: addrs.RootModule, 428 }, 429 ) 430 s.SetResourceInstanceCurrent( 431 addrs.Resource{ 432 Mode: addrs.ManagedResourceMode, 433 Type: "test_instance", 434 Name: "bar", 435 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 436 &states.ResourceInstanceObjectSrc{ 437 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 438 Status: states.ObjectReady, 439 }, 440 addrs.AbsProviderConfig{ 441 Provider: addrs.NewDefaultProvider("test"), 442 Module: addrs.RootModule, 443 }, 444 ) 445 }) 446 447 statePath := "local-state.tfstate" 448 backupPath := "local-state.backup" 449 450 f, err := os.Create(statePath) 451 if err != nil { 452 t.Fatalf("failed to create state file %s: %s", statePath, err) 453 } 454 defer f.Close() 455 456 err = writeStateForTesting(state, f) 457 if err != nil { 458 t.Fatalf("failed to write state to file %s: %s", statePath, err) 459 } 460 461 p := testProvider() 462 ui := new(cli.MockUi) 463 view, _ := testView(t) 464 c := &StateRmCommand{ 465 StateMeta{ 466 Meta: Meta{ 467 testingOverrides: metaOverridesForProvider(p), 468 Ui: ui, 469 View: view, 470 }, 471 }, 472 } 473 474 args := []string{ 475 "-backup", backupPath, 476 "test_instance.foo", 477 } 478 if code := c.Run(args); code != 0 { 479 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 480 } 481 482 // Test it is correct 483 testStateOutput(t, statePath, testStateRmOutput) 484 485 // Test backup 486 testStateOutput(t, backupPath, testStateRmOutputOriginal) 487 } 488 489 const testStateRmOutputOriginal = ` 490 test_instance.bar: 491 ID = foo 492 provider = provider["registry.terraform.io/hashicorp/test"] 493 bar = value 494 foo = value 495 test_instance.foo: 496 ID = bar 497 provider = provider["registry.terraform.io/hashicorp/test"] 498 bar = value 499 foo = value 500 ` 501 502 const testStateRmOutput = ` 503 test_instance.bar: 504 ID = foo 505 provider = provider["registry.terraform.io/hashicorp/test"] 506 bar = value 507 foo = value 508 `