github.com/cbroglie/terraform@v0.7.0-rc3.0.20170410193827-735dfc416d46/builtin/providers/aws/resource_aws_dynamodb_table_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "testing" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/aws/awserr" 10 "github.com/aws/aws-sdk-go/service/dynamodb" 11 "github.com/hashicorp/terraform/helper/acctest" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/terraform" 14 ) 15 16 func TestAccAWSDynamoDbTable_basic(t *testing.T) { 17 var conf dynamodb.DescribeTableOutput 18 19 resource.Test(t, resource.TestCase{ 20 PreCheck: func() { testAccPreCheck(t) }, 21 Providers: testAccProviders, 22 CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, 23 Steps: []resource.TestStep{ 24 { 25 Config: testAccAWSDynamoDbConfigInitialState(), 26 Check: resource.ComposeTestCheckFunc( 27 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.basic-dynamodb-table", &conf), 28 testAccCheckInitialAWSDynamoDbTableConf("aws_dynamodb_table.basic-dynamodb-table"), 29 ), 30 }, 31 { 32 Config: testAccAWSDynamoDbConfigAddSecondaryGSI, 33 Check: resource.ComposeTestCheckFunc( 34 testAccCheckDynamoDbTableWasUpdated("aws_dynamodb_table.basic-dynamodb-table"), 35 ), 36 }, 37 }, 38 }) 39 } 40 41 func TestAccAWSDynamoDbTable_streamSpecification(t *testing.T) { 42 var conf dynamodb.DescribeTableOutput 43 44 resource.Test(t, resource.TestCase{ 45 PreCheck: func() { testAccPreCheck(t) }, 46 Providers: testAccProviders, 47 CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, 48 Steps: []resource.TestStep{ 49 { 50 Config: testAccAWSDynamoDbConfigStreamSpecification(), 51 Check: resource.ComposeTestCheckFunc( 52 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.basic-dynamodb-table", &conf), 53 testAccCheckInitialAWSDynamoDbTableConf("aws_dynamodb_table.basic-dynamodb-table"), 54 resource.TestCheckResourceAttr( 55 "aws_dynamodb_table.basic-dynamodb-table", "stream_enabled", "true"), 56 resource.TestCheckResourceAttr( 57 "aws_dynamodb_table.basic-dynamodb-table", "stream_view_type", "KEYS_ONLY"), 58 ), 59 }, 60 }, 61 }) 62 } 63 64 func TestAccAWSDynamoDbTable_tags(t *testing.T) { 65 var conf dynamodb.DescribeTableOutput 66 67 resource.Test(t, resource.TestCase{ 68 PreCheck: func() { testAccPreCheck(t) }, 69 Providers: testAccProviders, 70 CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, 71 Steps: []resource.TestStep{ 72 { 73 Config: testAccAWSDynamoDbConfigTags(), 74 Check: resource.ComposeTestCheckFunc( 75 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.basic-dynamodb-table", &conf), 76 testAccCheckInitialAWSDynamoDbTableConf("aws_dynamodb_table.basic-dynamodb-table"), 77 resource.TestCheckResourceAttr( 78 "aws_dynamodb_table.basic-dynamodb-table", "tags.%", "3"), 79 ), 80 }, 81 }, 82 }) 83 } 84 85 // https://github.com/hashicorp/terraform/issues/13243 86 func TestAccAWSDynamoDbTable_gsiUpdate(t *testing.T) { 87 var conf dynamodb.DescribeTableOutput 88 name := acctest.RandString(10) 89 90 resource.Test(t, resource.TestCase{ 91 PreCheck: func() { testAccPreCheck(t) }, 92 Providers: testAccProviders, 93 CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, 94 Steps: []resource.TestStep{ 95 { 96 Config: testAccAWSDynamoDbConfigGsiUpdate(name), 97 Check: resource.ComposeTestCheckFunc( 98 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.test", &conf), 99 ), 100 }, 101 { 102 Config: testAccAWSDynamoDbConfigGsiUpdated(name), 103 Check: resource.ComposeTestCheckFunc( 104 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.test", &conf), 105 ), 106 }, 107 }, 108 }) 109 } 110 111 func TestResourceAWSDynamoDbTableStreamViewType_validation(t *testing.T) { 112 cases := []struct { 113 Value string 114 ErrCount int 115 }{ 116 { 117 Value: "KEYS-ONLY", 118 ErrCount: 1, 119 }, 120 { 121 Value: "RANDOM-STRING", 122 ErrCount: 1, 123 }, 124 { 125 Value: "KEYS_ONLY", 126 ErrCount: 0, 127 }, 128 { 129 Value: "NEW_AND_OLD_IMAGES", 130 ErrCount: 0, 131 }, 132 { 133 Value: "NEW_IMAGE", 134 ErrCount: 0, 135 }, 136 { 137 Value: "OLD_IMAGE", 138 ErrCount: 0, 139 }, 140 } 141 142 for _, tc := range cases { 143 _, errors := validateStreamViewType(tc.Value, "aws_dynamodb_table_stream_view_type") 144 145 if len(errors) != tc.ErrCount { 146 t.Fatalf("Expected the DynamoDB stream_view_type to trigger a validation error") 147 } 148 } 149 } 150 151 func testAccCheckAWSDynamoDbTableDestroy(s *terraform.State) error { 152 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 153 154 for _, rs := range s.RootModule().Resources { 155 if rs.Type != "aws_dynamodb_table" { 156 continue 157 } 158 159 log.Printf("[DEBUG] Checking if DynamoDB table %s exists", rs.Primary.ID) 160 // Check if queue exists by checking for its attributes 161 params := &dynamodb.DescribeTableInput{ 162 TableName: aws.String(rs.Primary.ID), 163 } 164 165 _, err := conn.DescribeTable(params) 166 if err == nil { 167 return fmt.Errorf("DynamoDB table %s still exists. Failing!", rs.Primary.ID) 168 } 169 170 // Verify the error is what we want 171 if dbErr, ok := err.(awserr.Error); ok && dbErr.Code() == "ResourceNotFoundException" { 172 return nil 173 } 174 175 return err 176 } 177 178 return nil 179 } 180 181 func testAccCheckInitialAWSDynamoDbTableExists(n string, table *dynamodb.DescribeTableOutput) resource.TestCheckFunc { 182 return func(s *terraform.State) error { 183 log.Printf("[DEBUG] Trying to create initial table state!") 184 rs, ok := s.RootModule().Resources[n] 185 if !ok { 186 return fmt.Errorf("Not found: %s", n) 187 } 188 189 if rs.Primary.ID == "" { 190 return fmt.Errorf("No DynamoDB table name specified!") 191 } 192 193 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 194 195 params := &dynamodb.DescribeTableInput{ 196 TableName: aws.String(rs.Primary.ID), 197 } 198 199 resp, err := conn.DescribeTable(params) 200 201 if err != nil { 202 return fmt.Errorf("[ERROR] Problem describing table '%s': %s", rs.Primary.ID, err) 203 } 204 205 *table = *resp 206 207 return nil 208 } 209 } 210 211 func testAccCheckInitialAWSDynamoDbTableConf(n string) resource.TestCheckFunc { 212 return func(s *terraform.State) error { 213 log.Printf("[DEBUG] Trying to create initial table state!") 214 rs, ok := s.RootModule().Resources[n] 215 if !ok { 216 return fmt.Errorf("Not found: %s", n) 217 } 218 219 if rs.Primary.ID == "" { 220 return fmt.Errorf("No DynamoDB table name specified!") 221 } 222 223 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 224 225 params := &dynamodb.DescribeTableInput{ 226 TableName: aws.String(rs.Primary.ID), 227 } 228 229 resp, err := conn.DescribeTable(params) 230 231 if err != nil { 232 return fmt.Errorf("[ERROR] Problem describing table '%s': %s", rs.Primary.ID, err) 233 } 234 235 table := resp.Table 236 237 log.Printf("[DEBUG] Checking on table %s", rs.Primary.ID) 238 239 if *table.ProvisionedThroughput.WriteCapacityUnits != 20 { 240 return fmt.Errorf("Provisioned write capacity was %d, not 20!", table.ProvisionedThroughput.WriteCapacityUnits) 241 } 242 243 if *table.ProvisionedThroughput.ReadCapacityUnits != 10 { 244 return fmt.Errorf("Provisioned read capacity was %d, not 10!", table.ProvisionedThroughput.ReadCapacityUnits) 245 } 246 247 attrCount := len(table.AttributeDefinitions) 248 gsiCount := len(table.GlobalSecondaryIndexes) 249 lsiCount := len(table.LocalSecondaryIndexes) 250 251 if attrCount != 4 { 252 return fmt.Errorf("There were %d attributes, not 4 like there should have been!", attrCount) 253 } 254 255 if gsiCount != 1 { 256 return fmt.Errorf("There were %d GSIs, not 1 like there should have been!", gsiCount) 257 } 258 259 if lsiCount != 1 { 260 return fmt.Errorf("There were %d LSIs, not 1 like there should have been!", lsiCount) 261 } 262 263 attrmap := dynamoDbAttributesToMap(&table.AttributeDefinitions) 264 if attrmap["TestTableHashKey"] != "S" { 265 return fmt.Errorf("Test table hash key was of type %s instead of S!", attrmap["TestTableHashKey"]) 266 } 267 if attrmap["TestTableRangeKey"] != "S" { 268 return fmt.Errorf("Test table range key was of type %s instead of S!", attrmap["TestTableRangeKey"]) 269 } 270 if attrmap["TestLSIRangeKey"] != "N" { 271 return fmt.Errorf("Test table LSI range key was of type %s instead of N!", attrmap["TestLSIRangeKey"]) 272 } 273 if attrmap["TestGSIRangeKey"] != "S" { 274 return fmt.Errorf("Test table GSI range key was of type %s instead of S!", attrmap["TestGSIRangeKey"]) 275 } 276 277 return nil 278 } 279 } 280 281 func testAccCheckDynamoDbTableWasUpdated(n string) resource.TestCheckFunc { 282 return func(s *terraform.State) error { 283 rs, ok := s.RootModule().Resources[n] 284 if !ok { 285 return fmt.Errorf("Not found: %s", n) 286 } 287 288 if rs.Primary.ID == "" { 289 return fmt.Errorf("No DynamoDB table name specified!") 290 } 291 292 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 293 294 params := &dynamodb.DescribeTableInput{ 295 TableName: aws.String(rs.Primary.ID), 296 } 297 resp, err := conn.DescribeTable(params) 298 table := resp.Table 299 300 if err != nil { 301 return err 302 } 303 304 attrCount := len(table.AttributeDefinitions) 305 gsiCount := len(table.GlobalSecondaryIndexes) 306 lsiCount := len(table.LocalSecondaryIndexes) 307 308 if attrCount != 4 { 309 return fmt.Errorf("There were %d attributes, not 4 like there should have been!", attrCount) 310 } 311 312 if gsiCount != 1 { 313 return fmt.Errorf("There were %d GSIs, not 1 like there should have been!", gsiCount) 314 } 315 316 if lsiCount != 1 { 317 return fmt.Errorf("There were %d LSIs, not 1 like there should have been!", lsiCount) 318 } 319 320 if dynamoDbGetGSIIndex(&table.GlobalSecondaryIndexes, "ReplacementTestTableGSI") == -1 { 321 return fmt.Errorf("Could not find GSI named 'ReplacementTestTableGSI' in the table!") 322 } 323 324 if dynamoDbGetGSIIndex(&table.GlobalSecondaryIndexes, "InitialTestTableGSI") != -1 { 325 return fmt.Errorf("Should have removed 'InitialTestTableGSI' but it still exists!") 326 } 327 328 attrmap := dynamoDbAttributesToMap(&table.AttributeDefinitions) 329 if attrmap["TestTableHashKey"] != "S" { 330 return fmt.Errorf("Test table hash key was of type %s instead of S!", attrmap["TestTableHashKey"]) 331 } 332 if attrmap["TestTableRangeKey"] != "S" { 333 return fmt.Errorf("Test table range key was of type %s instead of S!", attrmap["TestTableRangeKey"]) 334 } 335 if attrmap["TestLSIRangeKey"] != "N" { 336 return fmt.Errorf("Test table LSI range key was of type %s instead of N!", attrmap["TestLSIRangeKey"]) 337 } 338 if attrmap["ReplacementGSIRangeKey"] != "N" { 339 return fmt.Errorf("Test table replacement GSI range key was of type %s instead of N!", attrmap["ReplacementGSIRangeKey"]) 340 } 341 342 return nil 343 } 344 } 345 346 func dynamoDbGetGSIIndex(gsiList *[]*dynamodb.GlobalSecondaryIndexDescription, target string) int { 347 for idx, gsiObject := range *gsiList { 348 if *gsiObject.IndexName == target { 349 return idx 350 } 351 } 352 353 return -1 354 } 355 356 func dynamoDbAttributesToMap(attributes *[]*dynamodb.AttributeDefinition) map[string]string { 357 attrmap := make(map[string]string) 358 359 for _, attrdef := range *attributes { 360 attrmap[*attrdef.AttributeName] = *attrdef.AttributeType 361 } 362 363 return attrmap 364 } 365 366 func testAccAWSDynamoDbConfigInitialState() string { 367 return fmt.Sprintf(` 368 resource "aws_dynamodb_table" "basic-dynamodb-table" { 369 name = "TerraformTestTable-%d" 370 read_capacity = 10 371 write_capacity = 20 372 hash_key = "TestTableHashKey" 373 range_key = "TestTableRangeKey" 374 375 attribute { 376 name = "TestTableHashKey" 377 type = "S" 378 } 379 380 attribute { 381 name = "TestTableRangeKey" 382 type = "S" 383 } 384 385 attribute { 386 name = "TestLSIRangeKey" 387 type = "N" 388 } 389 390 attribute { 391 name = "TestGSIRangeKey" 392 type = "S" 393 } 394 395 local_secondary_index { 396 name = "TestTableLSI" 397 range_key = "TestLSIRangeKey" 398 projection_type = "ALL" 399 } 400 401 global_secondary_index { 402 name = "InitialTestTableGSI" 403 hash_key = "TestTableHashKey" 404 range_key = "TestGSIRangeKey" 405 write_capacity = 10 406 read_capacity = 10 407 projection_type = "KEYS_ONLY" 408 } 409 } 410 `, acctest.RandInt()) 411 } 412 413 const testAccAWSDynamoDbConfigAddSecondaryGSI = ` 414 resource "aws_dynamodb_table" "basic-dynamodb-table" { 415 name = "TerraformTestTable" 416 read_capacity = 20 417 write_capacity = 20 418 hash_key = "TestTableHashKey" 419 range_key = "TestTableRangeKey" 420 421 attribute { 422 name = "TestTableHashKey" 423 type = "S" 424 } 425 426 attribute { 427 name = "TestTableRangeKey" 428 type = "S" 429 } 430 431 attribute { 432 name = "TestLSIRangeKey" 433 type = "N" 434 } 435 436 attribute { 437 name = "ReplacementGSIRangeKey" 438 type = "N" 439 } 440 441 local_secondary_index { 442 name = "TestTableLSI" 443 range_key = "TestLSIRangeKey" 444 projection_type = "ALL" 445 } 446 447 global_secondary_index { 448 name = "ReplacementTestTableGSI" 449 hash_key = "TestTableHashKey" 450 range_key = "ReplacementGSIRangeKey" 451 write_capacity = 5 452 read_capacity = 5 453 projection_type = "INCLUDE" 454 non_key_attributes = ["TestNonKeyAttribute"] 455 } 456 } 457 ` 458 459 func testAccAWSDynamoDbConfigStreamSpecification() string { 460 return fmt.Sprintf(` 461 resource "aws_dynamodb_table" "basic-dynamodb-table" { 462 name = "TerraformTestStreamTable-%d" 463 read_capacity = 10 464 write_capacity = 20 465 hash_key = "TestTableHashKey" 466 range_key = "TestTableRangeKey" 467 468 attribute { 469 name = "TestTableHashKey" 470 type = "S" 471 } 472 473 attribute { 474 name = "TestTableRangeKey" 475 type = "S" 476 } 477 478 attribute { 479 name = "TestLSIRangeKey" 480 type = "N" 481 } 482 483 attribute { 484 name = "TestGSIRangeKey" 485 type = "S" 486 } 487 488 local_secondary_index { 489 name = "TestTableLSI" 490 range_key = "TestLSIRangeKey" 491 projection_type = "ALL" 492 } 493 494 global_secondary_index { 495 name = "InitialTestTableGSI" 496 hash_key = "TestTableHashKey" 497 range_key = "TestGSIRangeKey" 498 write_capacity = 10 499 read_capacity = 10 500 projection_type = "KEYS_ONLY" 501 } 502 stream_enabled = true 503 stream_view_type = "KEYS_ONLY" 504 } 505 `, acctest.RandInt()) 506 } 507 508 func testAccAWSDynamoDbConfigTags() string { 509 return fmt.Sprintf(` 510 resource "aws_dynamodb_table" "basic-dynamodb-table" { 511 name = "TerraformTestTable-%d" 512 read_capacity = 10 513 write_capacity = 20 514 hash_key = "TestTableHashKey" 515 range_key = "TestTableRangeKey" 516 517 attribute { 518 name = "TestTableHashKey" 519 type = "S" 520 } 521 522 attribute { 523 name = "TestTableRangeKey" 524 type = "S" 525 } 526 527 attribute { 528 name = "TestLSIRangeKey" 529 type = "N" 530 } 531 532 attribute { 533 name = "TestGSIRangeKey" 534 type = "S" 535 } 536 537 local_secondary_index { 538 name = "TestTableLSI" 539 range_key = "TestLSIRangeKey" 540 projection_type = "ALL" 541 } 542 543 global_secondary_index { 544 name = "InitialTestTableGSI" 545 hash_key = "TestTableHashKey" 546 range_key = "TestGSIRangeKey" 547 write_capacity = 10 548 read_capacity = 10 549 projection_type = "KEYS_ONLY" 550 } 551 552 tags { 553 Name = "terraform-test-table-%d" 554 AccTest = "yes" 555 Testing = "absolutely" 556 } 557 } 558 `, acctest.RandInt(), acctest.RandInt()) 559 } 560 561 func testAccAWSDynamoDbConfigGsiUpdate(name string) string { 562 return fmt.Sprintf(` 563 variable "capacity" { 564 default = 10 565 } 566 567 resource "aws_dynamodb_table" "test" { 568 name = "tf-acc-test-%s" 569 read_capacity = "${var.capacity}" 570 write_capacity = "${var.capacity}" 571 hash_key = "id" 572 573 attribute { 574 name = "id" 575 type = "S" 576 } 577 578 attribute { 579 name = "att1" 580 type = "S" 581 } 582 583 attribute { 584 name = "att2" 585 type = "S" 586 } 587 588 attribute { 589 name = "att3" 590 type = "S" 591 } 592 593 global_secondary_index { 594 name = "att1-index" 595 hash_key = "att1" 596 write_capacity = "${var.capacity}" 597 read_capacity = "${var.capacity}" 598 projection_type = "ALL" 599 } 600 601 global_secondary_index { 602 name = "att2-index" 603 hash_key = "att2" 604 write_capacity = "${var.capacity}" 605 read_capacity = "${var.capacity}" 606 projection_type = "ALL" 607 } 608 609 global_secondary_index { 610 name = "att3-index" 611 hash_key = "att3" 612 write_capacity = "${var.capacity}" 613 read_capacity = "${var.capacity}" 614 projection_type = "ALL" 615 } 616 } 617 `, name) 618 } 619 620 func testAccAWSDynamoDbConfigGsiUpdated(name string) string { 621 return fmt.Sprintf(` 622 variable "capacity" { 623 default = 20 624 } 625 626 resource "aws_dynamodb_table" "test" { 627 name = "tf-acc-test-%s" 628 read_capacity = "${var.capacity}" 629 write_capacity = "${var.capacity}" 630 hash_key = "id" 631 632 attribute { 633 name = "id" 634 type = "S" 635 } 636 637 attribute { 638 name = "att1" 639 type = "S" 640 } 641 642 attribute { 643 name = "att2" 644 type = "S" 645 } 646 647 attribute { 648 name = "att3" 649 type = "S" 650 } 651 652 global_secondary_index { 653 name = "att1-index" 654 hash_key = "att1" 655 write_capacity = "${var.capacity}" 656 read_capacity = "${var.capacity}" 657 projection_type = "ALL" 658 } 659 660 global_secondary_index { 661 name = "att2-index" 662 hash_key = "att2" 663 write_capacity = "${var.capacity}" 664 read_capacity = "${var.capacity}" 665 projection_type = "ALL" 666 } 667 668 global_secondary_index { 669 name = "att3-index" 670 hash_key = "att3" 671 write_capacity = "${var.capacity}" 672 read_capacity = "${var.capacity}" 673 projection_type = "ALL" 674 } 675 } 676 `, name) 677 }