github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/builtin/providers/test/resource_nested_set_test.go (about) 1 package test 2 3 import ( 4 "errors" 5 "fmt" 6 "regexp" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/terraform/addrs" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func TestResourceNestedSet_basic(t *testing.T) { 16 resource.UnitTest(t, resource.TestCase{ 17 Providers: testAccProviders, 18 CheckDestroy: testAccCheckResourceDestroy, 19 Steps: []resource.TestStep{ 20 resource.TestStep{ 21 Config: strings.TrimSpace(` 22 resource "test_resource_nested_set" "foo" { 23 single { 24 value = "bar" 25 } 26 } 27 `), 28 }, 29 }, 30 }) 31 } 32 33 func TestResourceNestedSet_basicImport(t *testing.T) { 34 resource.UnitTest(t, resource.TestCase{ 35 Providers: testAccProviders, 36 CheckDestroy: testAccCheckResourceDestroy, 37 Steps: []resource.TestStep{ 38 resource.TestStep{ 39 Config: strings.TrimSpace(` 40 resource "test_resource_nested_set" "foo" { 41 single { 42 value = "bar" 43 } 44 } 45 `), 46 }, 47 resource.TestStep{ 48 ImportState: true, 49 ResourceName: "test_resource_nested_set.foo", 50 Config: strings.TrimSpace(` 51 resource "test_resource_nested_set" "foo" { 52 single { 53 value = "bar" 54 } 55 } 56 `), 57 ImportStateCheck: func(ss []*terraform.InstanceState) error { 58 for _, s := range ss { 59 if s.Attributes["multi.#"] != "0" || 60 s.Attributes["single.#"] != "0" || 61 s.Attributes["type_list.#"] != "0" || 62 s.Attributes["with_list.#"] != "0" { 63 return fmt.Errorf("missing blocks in imported state:\n%s", s) 64 } 65 } 66 return nil 67 }, 68 }, 69 }, 70 }) 71 } 72 73 // The set should not be generated because of it's computed value 74 func TestResourceNestedSet_noSet(t *testing.T) { 75 checkFunc := func(s *terraform.State) error { 76 root := s.ModuleByPath(addrs.RootModuleInstance) 77 res := root.Resources["test_resource_nested_set.foo"] 78 for k, v := range res.Primary.Attributes { 79 if strings.HasPrefix(k, "single") && k != "single.#" { 80 return fmt.Errorf("unexpected set value: %s:%s", k, v) 81 } 82 } 83 return nil 84 } 85 resource.UnitTest(t, resource.TestCase{ 86 Providers: testAccProviders, 87 CheckDestroy: testAccCheckResourceDestroy, 88 Steps: []resource.TestStep{ 89 resource.TestStep{ 90 Config: strings.TrimSpace(` 91 resource "test_resource_nested_set" "foo" { 92 } 93 `), 94 Check: checkFunc, 95 }, 96 }, 97 }) 98 } 99 100 // the empty type_list must be passed to the provider with 1 nil element 101 func TestResourceNestedSet_emptyBlock(t *testing.T) { 102 resource.UnitTest(t, resource.TestCase{ 103 Providers: testAccProviders, 104 CheckDestroy: testAccCheckResourceDestroy, 105 Steps: []resource.TestStep{ 106 resource.TestStep{ 107 Config: strings.TrimSpace(` 108 resource "test_resource_nested_set" "foo" { 109 type_list { 110 } 111 } 112 `), 113 Check: resource.ComposeTestCheckFunc( 114 resource.TestCheckResourceAttr("test_resource_nested_set.foo", "type_list.#", "1"), 115 ), 116 }, 117 }, 118 }) 119 } 120 121 func TestResourceNestedSet_emptyNestedListBlock(t *testing.T) { 122 checkFunc := func(s *terraform.State) error { 123 root := s.ModuleByPath(addrs.RootModuleInstance) 124 res := root.Resources["test_resource_nested_set.foo"] 125 found := false 126 for k := range res.Primary.Attributes { 127 if !regexp.MustCompile(`^with_list\.\d+\.list_block\.`).MatchString(k) { 128 continue 129 } 130 found = true 131 } 132 if !found { 133 return fmt.Errorf("with_list.X.list_block not found") 134 } 135 return nil 136 } 137 resource.UnitTest(t, resource.TestCase{ 138 Providers: testAccProviders, 139 CheckDestroy: testAccCheckResourceDestroy, 140 Steps: []resource.TestStep{ 141 resource.TestStep{ 142 Config: strings.TrimSpace(` 143 resource "test_resource_nested_set" "foo" { 144 with_list { 145 required = "ok" 146 list_block { 147 } 148 } 149 } 150 `), 151 Check: checkFunc, 152 }, 153 }, 154 }) 155 } 156 func TestResourceNestedSet_emptyNestedList(t *testing.T) { 157 checkFunc := func(s *terraform.State) error { 158 root := s.ModuleByPath(addrs.RootModuleInstance) 159 res := root.Resources["test_resource_nested_set.foo"] 160 found := false 161 for k, v := range res.Primary.Attributes { 162 if regexp.MustCompile(`^with_list\.\d+\.list\.#$`).MatchString(k) { 163 found = true 164 if v != "0" { 165 return fmt.Errorf("expected empty list: %s, got %s", k, v) 166 } 167 break 168 } 169 } 170 if !found { 171 return fmt.Errorf("with_list.X.nested_list not found") 172 } 173 return nil 174 } 175 resource.UnitTest(t, resource.TestCase{ 176 Providers: testAccProviders, 177 CheckDestroy: testAccCheckResourceDestroy, 178 Steps: []resource.TestStep{ 179 resource.TestStep{ 180 Config: strings.TrimSpace(` 181 resource "test_resource_nested_set" "foo" { 182 with_list { 183 required = "ok" 184 list = [] 185 } 186 } 187 `), 188 Check: checkFunc, 189 }, 190 }, 191 }) 192 } 193 194 func TestResourceNestedSet_addRemove(t *testing.T) { 195 var id string 196 checkFunc := func(s *terraform.State) error { 197 root := s.ModuleByPath(addrs.RootModuleInstance) 198 res := root.Resources["test_resource_nested_set.foo"] 199 if res.Primary.ID == id { 200 return errors.New("expected new resource") 201 } 202 id = res.Primary.ID 203 return nil 204 } 205 resource.UnitTest(t, resource.TestCase{ 206 Providers: testAccProviders, 207 CheckDestroy: testAccCheckResourceDestroy, 208 Steps: []resource.TestStep{ 209 resource.TestStep{ 210 Config: strings.TrimSpace(` 211 resource "test_resource_nested_set" "foo" { 212 } 213 `), 214 Check: checkFunc, 215 }, 216 resource.TestStep{ 217 Config: strings.TrimSpace(` 218 resource "test_resource_nested_set" "foo" { 219 single { 220 value = "bar" 221 } 222 } 223 `), 224 Check: resource.ComposeTestCheckFunc( 225 checkFunc, 226 resource.TestCheckResourceAttr( 227 "test_resource_nested_set.foo", "single.#", "1", 228 ), 229 // the hash of single seems to change here, so we're not 230 // going to test for "value" directly 231 // FIXME: figure out why the set hash changes 232 ), 233 }, 234 resource.TestStep{ 235 Config: strings.TrimSpace(` 236 resource "test_resource_nested_set" "foo" { 237 } 238 `), 239 Check: resource.ComposeTestCheckFunc( 240 resource.TestCheckResourceAttr( 241 "test_resource_nested_set.foo", "single.#", "0", 242 ), 243 checkFunc, 244 ), 245 }, 246 resource.TestStep{ 247 Config: strings.TrimSpace(` 248 resource "test_resource_nested_set" "foo" { 249 single { 250 value = "bar" 251 } 252 } 253 `), 254 Check: checkFunc, 255 }, 256 resource.TestStep{ 257 Config: strings.TrimSpace(` 258 resource "test_resource_nested_set" "foo" { 259 single { 260 value = "bar" 261 optional = "baz" 262 } 263 } 264 `), 265 Check: checkFunc, 266 }, 267 268 resource.TestStep{ 269 Config: strings.TrimSpace(` 270 resource "test_resource_nested_set" "foo" { 271 } 272 `), 273 Check: checkFunc, 274 }, 275 }, 276 }) 277 } 278 func TestResourceNestedSet_multiAddRemove(t *testing.T) { 279 checkFunc := func(s *terraform.State) error { 280 return nil 281 } 282 resource.UnitTest(t, resource.TestCase{ 283 Providers: testAccProviders, 284 CheckDestroy: testAccCheckResourceDestroy, 285 Steps: []resource.TestStep{ 286 resource.TestStep{ 287 Config: strings.TrimSpace(` 288 resource "test_resource_nested_set" "foo" { 289 } 290 `), 291 Check: checkFunc, 292 }, 293 resource.TestStep{ 294 Config: strings.TrimSpace(` 295 resource "test_resource_nested_set" "foo" { 296 multi { 297 optional = "bar" 298 } 299 } 300 `), 301 Check: checkFunc, 302 }, 303 304 resource.TestStep{ 305 Config: strings.TrimSpace(` 306 resource "test_resource_nested_set" "foo" { 307 } 308 `), 309 Check: checkFunc, 310 }, 311 312 resource.TestStep{ 313 Config: strings.TrimSpace(` 314 resource "test_resource_nested_set" "foo" { 315 multi { 316 set { 317 required = "val" 318 } 319 } 320 } 321 `), 322 Check: checkFunc, 323 }, 324 325 resource.TestStep{ 326 Config: strings.TrimSpace(` 327 resource "test_resource_nested_set" "foo" { 328 multi { 329 set { 330 required = "new" 331 } 332 } 333 } 334 `), 335 Check: checkFunc, 336 }, 337 338 resource.TestStep{ 339 Config: strings.TrimSpace(` 340 resource "test_resource_nested_set" "foo" { 341 multi { 342 set { 343 required = "new" 344 optional_int = 3 345 } 346 } 347 } 348 `), 349 Check: checkFunc, 350 }, 351 352 resource.TestStep{ 353 Config: strings.TrimSpace(` 354 resource "test_resource_nested_set" "foo" { 355 single { 356 value = "bar" 357 optional = "baz" 358 } 359 multi { 360 set { 361 required = "new" 362 optional_int = 3 363 } 364 } 365 } 366 `), 367 Check: checkFunc, 368 }, 369 370 resource.TestStep{ 371 Config: strings.TrimSpace(` 372 resource "test_resource_nested_set" "foo" { 373 optional = true 374 single { 375 value = "bar" 376 optional = "baz" 377 } 378 multi { 379 set { 380 required = "new" 381 optional_int = 3 382 } 383 } 384 } 385 `), 386 Check: checkFunc, 387 }, 388 }, 389 }) 390 } 391 392 func TestResourceNestedSet_forceNewEmptyString(t *testing.T) { 393 var id string 394 step := 0 395 checkFunc := func(s *terraform.State) error { 396 root := s.ModuleByPath(addrs.RootModuleInstance) 397 res := root.Resources["test_resource_nested_set.foo"] 398 defer func() { 399 step++ 400 id = res.Primary.ID 401 }() 402 403 if step == 2 && res.Primary.ID == id { 404 // setting an empty string currently does not trigger ForceNew, but 405 // it should in the future. 406 return nil 407 } 408 409 if res.Primary.ID == id { 410 return errors.New("expected new resource") 411 } 412 413 return nil 414 } 415 resource.UnitTest(t, resource.TestCase{ 416 Providers: testAccProviders, 417 CheckDestroy: testAccCheckResourceDestroy, 418 Steps: []resource.TestStep{ 419 resource.TestStep{ 420 Config: strings.TrimSpace(` 421 resource "test_resource_nested_set" "foo" { 422 multi { 423 set { 424 required = "val" 425 } 426 } 427 } 428 `), 429 Check: checkFunc, 430 }, 431 432 resource.TestStep{ 433 Config: strings.TrimSpace(` 434 resource "test_resource_nested_set" "foo" { 435 multi { 436 set { 437 required = "" 438 } 439 } 440 } 441 `), 442 Check: checkFunc, 443 }, 444 445 resource.TestStep{ 446 Config: strings.TrimSpace(` 447 resource "test_resource_nested_set" "foo" { 448 force_new = "" 449 } 450 `), 451 Check: checkFunc, 452 }, 453 }, 454 }) 455 } 456 457 func TestResourceNestedSet_setWithList(t *testing.T) { 458 checkFunc := func(s *terraform.State) error { 459 return nil 460 } 461 resource.UnitTest(t, resource.TestCase{ 462 Providers: testAccProviders, 463 CheckDestroy: testAccCheckResourceDestroy, 464 Steps: []resource.TestStep{ 465 resource.TestStep{ 466 Config: strings.TrimSpace(` 467 resource "test_resource_nested_set" "foo" { 468 with_list { 469 required = "bar" 470 list = ["initial value"] 471 } 472 } 473 `), 474 Check: checkFunc, 475 }, 476 resource.TestStep{ 477 Config: strings.TrimSpace(` 478 resource "test_resource_nested_set" "foo" { 479 with_list { 480 required = "bar" 481 list = ["second value"] 482 } 483 } 484 `), 485 Check: checkFunc, 486 }, 487 }, 488 }) 489 } 490 491 // This is the same as forceNewEmptyString, but we start with the empty value, 492 // instead of changing it. 493 func TestResourceNestedSet_nestedSetEmptyString(t *testing.T) { 494 resource.UnitTest(t, resource.TestCase{ 495 Providers: testAccProviders, 496 CheckDestroy: testAccCheckResourceDestroy, 497 Steps: []resource.TestStep{ 498 resource.TestStep{ 499 Config: strings.TrimSpace(` 500 resource "test_resource_nested_set" "foo" { 501 multi { 502 set { 503 required = "" 504 } 505 } 506 } 507 `), 508 Check: resource.ComposeTestCheckFunc( 509 resource.TestCheckResourceAttr( 510 "test_resource_nested_set.foo", "multi.529860700.set.4196279896.required", "", 511 ), 512 ), 513 }, 514 }, 515 }) 516 } 517 518 func TestResourceNestedSet_emptySet(t *testing.T) { 519 resource.UnitTest(t, resource.TestCase{ 520 Providers: testAccProviders, 521 CheckDestroy: testAccCheckResourceDestroy, 522 Steps: []resource.TestStep{ 523 resource.TestStep{ 524 Config: strings.TrimSpace(` 525 resource "test_resource_nested_set" "foo" { 526 multi { 527 } 528 } 529 `), 530 Check: resource.ComposeTestCheckFunc( 531 resource.TestCheckResourceAttr( 532 "test_resource_nested_set.foo", "multi.#", "1", 533 ), 534 ), 535 }, 536 }, 537 }) 538 } 539 540 func TestResourceNestedSet_multipleUnknownSetElements(t *testing.T) { 541 checkFunc := func(s *terraform.State) error { 542 return nil 543 } 544 resource.UnitTest(t, resource.TestCase{ 545 Providers: testAccProviders, 546 CheckDestroy: testAccCheckResourceDestroy, 547 Steps: []resource.TestStep{ 548 resource.TestStep{ 549 Config: strings.TrimSpace(` 550 resource "test_resource_nested_set" "a" { 551 } 552 553 resource "test_resource_nested_set" "b" { 554 } 555 556 resource "test_resource_nested_set" "c" { 557 multi { 558 optional = test_resource_nested_set.a.id 559 } 560 multi { 561 optional = test_resource_nested_set.b.id 562 } 563 } 564 `), 565 Check: checkFunc, 566 }, 567 }, 568 }) 569 } 570 571 func TestResourceNestedSet_interpolationChanges(t *testing.T) { 572 resource.UnitTest(t, resource.TestCase{ 573 Providers: testAccProviders, 574 CheckDestroy: testAccCheckResourceDestroy, 575 Steps: []resource.TestStep{ 576 resource.TestStep{ 577 Config: strings.TrimSpace(` 578 resource "test_resource_nested_set" "foo" { 579 single { 580 value = "x" 581 } 582 } 583 resource "test_resource_nested_set" "bar" { 584 single { 585 value = test_resource_nested_set.foo.id 586 } 587 } 588 `), 589 Check: resource.ComposeTestCheckFunc( 590 resource.TestCheckResourceAttr( 591 "test_resource_nested_set.foo", "single.#", "1", 592 ), 593 resource.TestCheckResourceAttr( 594 "test_resource_nested_set.bar", "single.#", "1", 595 ), 596 ), 597 }, 598 resource.TestStep{ 599 Config: strings.TrimSpace(` 600 resource "test_resource_nested_set" "baz" { 601 single { 602 value = "x" 603 } 604 } 605 resource "test_resource_nested_set" "bar" { 606 single { 607 value = test_resource_nested_set.baz.id 608 } 609 } 610 `), 611 Check: resource.ComposeTestCheckFunc( 612 resource.TestCheckResourceAttr( 613 "test_resource_nested_set.baz", "single.#", "1", 614 ), 615 resource.TestCheckResourceAttr( 616 "test_resource_nested_set.bar", "single.#", "1", 617 ), 618 ), 619 }, 620 }, 621 }) 622 } 623 624 func TestResourceNestedSet_dynamicSetBlock(t *testing.T) { 625 resource.UnitTest(t, resource.TestCase{ 626 Providers: testAccProviders, 627 CheckDestroy: testAccCheckResourceDestroy, 628 Steps: []resource.TestStep{ 629 resource.TestStep{ 630 Config: strings.TrimSpace(` 631 resource "test_resource" "a" { 632 required = "ok" 633 required_map = { 634 a = "b" 635 } 636 } 637 638 resource "test_resource_nested_set" "foo" { 639 dynamic "with_list" { 640 iterator = thing 641 for_each = test_resource.a.computed_list 642 content { 643 required = thing.value 644 list = [thing.key] 645 } 646 } 647 } 648 `), 649 Check: resource.ComposeTestCheckFunc(), 650 }, 651 }, 652 }) 653 }