github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/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/hashicorp/terraform/internal/addrs" 12 "github.com/hashicorp/terraform/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 testCwd(t) 358 359 p := testProvider() 360 ui := new(cli.MockUi) 361 view, _ := testView(t) 362 c := &StateRmCommand{ 363 StateMeta{ 364 Meta: Meta{ 365 testingOverrides: metaOverridesForProvider(p), 366 Ui: ui, 367 View: view, 368 }, 369 }, 370 } 371 372 args := []string{"foo"} 373 if code := c.Run(args); code != 1 { 374 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 375 } 376 } 377 378 func TestStateRm_needsInit(t *testing.T) { 379 td := t.TempDir() 380 testCopyDir(t, testFixturePath("backend-change"), td) 381 defer testChdir(t, td)() 382 383 p := testProvider() 384 ui := new(cli.MockUi) 385 view, _ := testView(t) 386 c := &StateRmCommand{ 387 StateMeta{ 388 Meta: Meta{ 389 testingOverrides: metaOverridesForProvider(p), 390 Ui: ui, 391 View: view, 392 }, 393 }, 394 } 395 396 args := []string{"foo"} 397 if code := c.Run(args); code == 0 { 398 t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String()) 399 } 400 401 if !strings.Contains(ui.ErrorWriter.String(), "Backend initialization") { 402 t.Fatalf("expected initialization error, got:\n%s", ui.ErrorWriter.String()) 403 } 404 } 405 406 func TestStateRm_backendState(t *testing.T) { 407 td := t.TempDir() 408 testCopyDir(t, testFixturePath("backend-unchanged"), td) 409 defer testChdir(t, td)() 410 411 state := states.BuildState(func(s *states.SyncState) { 412 s.SetResourceInstanceCurrent( 413 addrs.Resource{ 414 Mode: addrs.ManagedResourceMode, 415 Type: "test_instance", 416 Name: "foo", 417 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 418 &states.ResourceInstanceObjectSrc{ 419 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 420 Status: states.ObjectReady, 421 }, 422 addrs.AbsProviderConfig{ 423 Provider: addrs.NewDefaultProvider("test"), 424 Module: addrs.RootModule, 425 }, 426 ) 427 s.SetResourceInstanceCurrent( 428 addrs.Resource{ 429 Mode: addrs.ManagedResourceMode, 430 Type: "test_instance", 431 Name: "bar", 432 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 433 &states.ResourceInstanceObjectSrc{ 434 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 435 Status: states.ObjectReady, 436 }, 437 addrs.AbsProviderConfig{ 438 Provider: addrs.NewDefaultProvider("test"), 439 Module: addrs.RootModule, 440 }, 441 ) 442 }) 443 444 statePath := "local-state.tfstate" 445 backupPath := "local-state.backup" 446 447 f, err := os.Create(statePath) 448 if err != nil { 449 t.Fatalf("failed to create state file %s: %s", statePath, err) 450 } 451 defer f.Close() 452 453 err = writeStateForTesting(state, f) 454 if err != nil { 455 t.Fatalf("failed to write state to file %s: %s", statePath, err) 456 } 457 458 p := testProvider() 459 ui := new(cli.MockUi) 460 view, _ := testView(t) 461 c := &StateRmCommand{ 462 StateMeta{ 463 Meta: Meta{ 464 testingOverrides: metaOverridesForProvider(p), 465 Ui: ui, 466 View: view, 467 }, 468 }, 469 } 470 471 args := []string{ 472 "-backup", backupPath, 473 "test_instance.foo", 474 } 475 if code := c.Run(args); code != 0 { 476 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 477 } 478 479 // Test it is correct 480 testStateOutput(t, statePath, testStateRmOutput) 481 482 // Test backup 483 testStateOutput(t, backupPath, testStateRmOutputOriginal) 484 } 485 486 func TestStateRm_checkRequiredVersion(t *testing.T) { 487 // Create a temporary working directory that is empty 488 td := t.TempDir() 489 testCopyDir(t, testFixturePath("command-check-required-version"), td) 490 defer testChdir(t, td)() 491 492 state := states.BuildState(func(s *states.SyncState) { 493 s.SetResourceInstanceCurrent( 494 addrs.Resource{ 495 Mode: addrs.ManagedResourceMode, 496 Type: "test_instance", 497 Name: "foo", 498 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 499 &states.ResourceInstanceObjectSrc{ 500 AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), 501 Status: states.ObjectReady, 502 }, 503 addrs.AbsProviderConfig{ 504 Provider: addrs.NewDefaultProvider("test"), 505 Module: addrs.RootModule, 506 }, 507 ) 508 s.SetResourceInstanceCurrent( 509 addrs.Resource{ 510 Mode: addrs.ManagedResourceMode, 511 Type: "test_instance", 512 Name: "bar", 513 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 514 &states.ResourceInstanceObjectSrc{ 515 AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), 516 Status: states.ObjectReady, 517 }, 518 addrs.AbsProviderConfig{ 519 Provider: addrs.NewDefaultProvider("test"), 520 Module: addrs.RootModule, 521 }, 522 ) 523 }) 524 statePath := testStateFile(t, state) 525 526 p := testProvider() 527 ui := new(cli.MockUi) 528 view, _ := testView(t) 529 c := &StateRmCommand{ 530 StateMeta{ 531 Meta: Meta{ 532 testingOverrides: metaOverridesForProvider(p), 533 Ui: ui, 534 View: view, 535 }, 536 }, 537 } 538 539 args := []string{ 540 "-state", statePath, 541 "test_instance.foo", 542 } 543 if code := c.Run(args); code != 1 { 544 t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String()) 545 } 546 547 // State is unchanged 548 testStateOutput(t, statePath, testStateRmOutputOriginal) 549 550 // Required version diags are correct 551 errStr := ui.ErrorWriter.String() 552 if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) { 553 t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr) 554 } 555 if strings.Contains(errStr, `required_version = ">= 0.13.0"`) { 556 t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr) 557 } 558 } 559 560 const testStateRmOutputOriginal = ` 561 test_instance.bar: 562 ID = foo 563 provider = provider["registry.terraform.io/hashicorp/test"] 564 bar = value 565 foo = value 566 test_instance.foo: 567 ID = bar 568 provider = provider["registry.terraform.io/hashicorp/test"] 569 bar = value 570 foo = value 571 ` 572 573 const testStateRmOutput = ` 574 test_instance.bar: 575 ID = foo 576 provider = provider["registry.terraform.io/hashicorp/test"] 577 bar = value 578 foo = value 579 `