github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/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 resource.Test(t, resource.TestCase{ 18 PreCheck: func() { testAccPreCheck(t) }, 19 Providers: testAccProviders, 20 CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, 21 Steps: []resource.TestStep{ 22 resource.TestStep{ 23 Config: testAccAWSDynamoDbConfigInitialState(), 24 Check: resource.ComposeTestCheckFunc( 25 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.basic-dynamodb-table"), 26 ), 27 }, 28 resource.TestStep{ 29 Config: testAccAWSDynamoDbConfigAddSecondaryGSI, 30 Check: resource.ComposeTestCheckFunc( 31 testAccCheckDynamoDbTableWasUpdated("aws_dynamodb_table.basic-dynamodb-table"), 32 ), 33 }, 34 }, 35 }) 36 } 37 38 func TestAccAWSDynamoDbTable_streamSpecification(t *testing.T) { 39 resource.Test(t, resource.TestCase{ 40 PreCheck: func() { testAccPreCheck(t) }, 41 Providers: testAccProviders, 42 CheckDestroy: testAccCheckAWSDynamoDbTableDestroy, 43 Steps: []resource.TestStep{ 44 resource.TestStep{ 45 Config: testAccAWSDynamoDbConfigStreamSpecification(), 46 Check: resource.ComposeTestCheckFunc( 47 testAccCheckInitialAWSDynamoDbTableExists("aws_dynamodb_table.basic-dynamodb-table"), 48 resource.TestCheckResourceAttr( 49 "aws_dynamodb_table.basic-dynamodb-table", "stream_enabled", "true"), 50 resource.TestCheckResourceAttr( 51 "aws_dynamodb_table.basic-dynamodb-table", "stream_view_type", "KEYS_ONLY"), 52 ), 53 }, 54 }, 55 }) 56 } 57 58 func TestResourceAWSDynamoDbTableStreamViewType_validation(t *testing.T) { 59 cases := []struct { 60 Value string 61 ErrCount int 62 }{ 63 { 64 Value: "KEYS-ONLY", 65 ErrCount: 1, 66 }, 67 { 68 Value: "RANDOM-STRING", 69 ErrCount: 1, 70 }, 71 { 72 Value: "KEYS_ONLY", 73 ErrCount: 0, 74 }, 75 { 76 Value: "NEW_AND_OLD_IMAGES", 77 ErrCount: 0, 78 }, 79 { 80 Value: "NEW_IMAGE", 81 ErrCount: 0, 82 }, 83 { 84 Value: "OLD_IMAGE", 85 ErrCount: 0, 86 }, 87 } 88 89 for _, tc := range cases { 90 _, errors := validateStreamViewType(tc.Value, "aws_dynamodb_table_stream_view_type") 91 92 if len(errors) != tc.ErrCount { 93 t.Fatalf("Expected the DynamoDB stream_view_type to trigger a validation error") 94 } 95 } 96 } 97 98 func testAccCheckAWSDynamoDbTableDestroy(s *terraform.State) error { 99 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 100 101 for _, rs := range s.RootModule().Resources { 102 if rs.Type != "aws_dynamodb_table" { 103 continue 104 } 105 106 log.Printf("[DEBUG] Checking if DynamoDB table %s exists", rs.Primary.ID) 107 // Check if queue exists by checking for its attributes 108 params := &dynamodb.DescribeTableInput{ 109 TableName: aws.String(rs.Primary.ID), 110 } 111 112 _, err := conn.DescribeTable(params) 113 if err == nil { 114 return fmt.Errorf("DynamoDB table %s still exists. Failing!", rs.Primary.ID) 115 } 116 117 // Verify the error is what we want 118 if dbErr, ok := err.(awserr.Error); ok && dbErr.Code() == "ResourceNotFoundException" { 119 return nil 120 } 121 122 return err 123 } 124 125 return nil 126 } 127 128 func testAccCheckInitialAWSDynamoDbTableExists(n string) resource.TestCheckFunc { 129 return func(s *terraform.State) error { 130 fmt.Printf("[DEBUG] Trying to create initial table state!") 131 rs, ok := s.RootModule().Resources[n] 132 if !ok { 133 return fmt.Errorf("Not found: %s", n) 134 } 135 136 if rs.Primary.ID == "" { 137 return fmt.Errorf("No DynamoDB table name specified!") 138 } 139 140 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 141 142 params := &dynamodb.DescribeTableInput{ 143 TableName: aws.String(rs.Primary.ID), 144 } 145 146 resp, err := conn.DescribeTable(params) 147 148 if err != nil { 149 fmt.Printf("[ERROR] Problem describing table '%s': %s", rs.Primary.ID, err) 150 return err 151 } 152 153 table := resp.Table 154 155 fmt.Printf("[DEBUG] Checking on table %s", rs.Primary.ID) 156 157 if *table.ProvisionedThroughput.WriteCapacityUnits != 20 { 158 return fmt.Errorf("Provisioned write capacity was %d, not 20!", table.ProvisionedThroughput.WriteCapacityUnits) 159 } 160 161 if *table.ProvisionedThroughput.ReadCapacityUnits != 10 { 162 return fmt.Errorf("Provisioned read capacity was %d, not 10!", table.ProvisionedThroughput.ReadCapacityUnits) 163 } 164 165 attrCount := len(table.AttributeDefinitions) 166 gsiCount := len(table.GlobalSecondaryIndexes) 167 lsiCount := len(table.LocalSecondaryIndexes) 168 169 if attrCount != 4 { 170 return fmt.Errorf("There were %d attributes, not 4 like there should have been!", attrCount) 171 } 172 173 if gsiCount != 1 { 174 return fmt.Errorf("There were %d GSIs, not 1 like there should have been!", gsiCount) 175 } 176 177 if lsiCount != 1 { 178 return fmt.Errorf("There were %d LSIs, not 1 like there should have been!", lsiCount) 179 } 180 181 attrmap := dynamoDbAttributesToMap(&table.AttributeDefinitions) 182 if attrmap["TestTableHashKey"] != "S" { 183 return fmt.Errorf("Test table hash key was of type %s instead of S!", attrmap["TestTableHashKey"]) 184 } 185 if attrmap["TestTableRangeKey"] != "S" { 186 return fmt.Errorf("Test table range key was of type %s instead of S!", attrmap["TestTableRangeKey"]) 187 } 188 if attrmap["TestLSIRangeKey"] != "N" { 189 return fmt.Errorf("Test table LSI range key was of type %s instead of N!", attrmap["TestLSIRangeKey"]) 190 } 191 if attrmap["TestGSIRangeKey"] != "S" { 192 return fmt.Errorf("Test table GSI range key was of type %s instead of S!", attrmap["TestGSIRangeKey"]) 193 } 194 195 return nil 196 } 197 } 198 199 func testAccCheckDynamoDbTableWasUpdated(n string) resource.TestCheckFunc { 200 return func(s *terraform.State) error { 201 rs, ok := s.RootModule().Resources[n] 202 if !ok { 203 return fmt.Errorf("Not found: %s", n) 204 } 205 206 if rs.Primary.ID == "" { 207 return fmt.Errorf("No DynamoDB table name specified!") 208 } 209 210 conn := testAccProvider.Meta().(*AWSClient).dynamodbconn 211 212 params := &dynamodb.DescribeTableInput{ 213 TableName: aws.String(rs.Primary.ID), 214 } 215 resp, err := conn.DescribeTable(params) 216 table := resp.Table 217 218 if err != nil { 219 return err 220 } 221 222 attrCount := len(table.AttributeDefinitions) 223 gsiCount := len(table.GlobalSecondaryIndexes) 224 lsiCount := len(table.LocalSecondaryIndexes) 225 226 if attrCount != 4 { 227 return fmt.Errorf("There were %d attributes, not 4 like there should have been!", attrCount) 228 } 229 230 if gsiCount != 1 { 231 return fmt.Errorf("There were %d GSIs, not 1 like there should have been!", gsiCount) 232 } 233 234 if lsiCount != 1 { 235 return fmt.Errorf("There were %d LSIs, not 1 like there should have been!", lsiCount) 236 } 237 238 if dynamoDbGetGSIIndex(&table.GlobalSecondaryIndexes, "ReplacementTestTableGSI") == -1 { 239 return fmt.Errorf("Could not find GSI named 'ReplacementTestTableGSI' in the table!") 240 } 241 242 if dynamoDbGetGSIIndex(&table.GlobalSecondaryIndexes, "InitialTestTableGSI") != -1 { 243 return fmt.Errorf("Should have removed 'InitialTestTableGSI' but it still exists!") 244 } 245 246 attrmap := dynamoDbAttributesToMap(&table.AttributeDefinitions) 247 if attrmap["TestTableHashKey"] != "S" { 248 return fmt.Errorf("Test table hash key was of type %s instead of S!", attrmap["TestTableHashKey"]) 249 } 250 if attrmap["TestTableRangeKey"] != "S" { 251 return fmt.Errorf("Test table range key was of type %s instead of S!", attrmap["TestTableRangeKey"]) 252 } 253 if attrmap["TestLSIRangeKey"] != "N" { 254 return fmt.Errorf("Test table LSI range key was of type %s instead of N!", attrmap["TestLSIRangeKey"]) 255 } 256 if attrmap["ReplacementGSIRangeKey"] != "N" { 257 return fmt.Errorf("Test table replacement GSI range key was of type %s instead of N!", attrmap["ReplacementGSIRangeKey"]) 258 } 259 260 return nil 261 } 262 } 263 264 func dynamoDbGetGSIIndex(gsiList *[]*dynamodb.GlobalSecondaryIndexDescription, target string) int { 265 for idx, gsiObject := range *gsiList { 266 if *gsiObject.IndexName == target { 267 return idx 268 } 269 } 270 271 return -1 272 } 273 274 func dynamoDbAttributesToMap(attributes *[]*dynamodb.AttributeDefinition) map[string]string { 275 attrmap := make(map[string]string) 276 277 for _, attrdef := range *attributes { 278 attrmap[*attrdef.AttributeName] = *attrdef.AttributeType 279 } 280 281 return attrmap 282 } 283 284 func testAccAWSDynamoDbConfigInitialState() string { 285 return fmt.Sprintf(` 286 resource "aws_dynamodb_table" "basic-dynamodb-table" { 287 name = "TerraformTestTable-%d" 288 read_capacity = 10 289 write_capacity = 20 290 hash_key = "TestTableHashKey" 291 range_key = "TestTableRangeKey" 292 attribute { 293 name = "TestTableHashKey" 294 type = "S" 295 } 296 attribute { 297 name = "TestTableRangeKey" 298 type = "S" 299 } 300 attribute { 301 name = "TestLSIRangeKey" 302 type = "N" 303 } 304 attribute { 305 name = "TestGSIRangeKey" 306 type = "S" 307 } 308 local_secondary_index { 309 name = "TestTableLSI" 310 range_key = "TestLSIRangeKey" 311 projection_type = "ALL" 312 } 313 global_secondary_index { 314 name = "InitialTestTableGSI" 315 hash_key = "TestTableHashKey" 316 range_key = "TestGSIRangeKey" 317 write_capacity = 10 318 read_capacity = 10 319 projection_type = "KEYS_ONLY" 320 } 321 } 322 `, acctest.RandInt()) 323 } 324 325 const testAccAWSDynamoDbConfigAddSecondaryGSI = ` 326 resource "aws_dynamodb_table" "basic-dynamodb-table" { 327 name = "TerraformTestTable" 328 read_capacity = 20 329 write_capacity = 20 330 hash_key = "TestTableHashKey" 331 range_key = "TestTableRangeKey" 332 attribute { 333 name = "TestTableHashKey" 334 type = "S" 335 } 336 attribute { 337 name = "TestTableRangeKey" 338 type = "S" 339 } 340 attribute { 341 name = "TestLSIRangeKey" 342 type = "N" 343 } 344 attribute { 345 name = "ReplacementGSIRangeKey" 346 type = "N" 347 } 348 local_secondary_index { 349 name = "TestTableLSI" 350 range_key = "TestLSIRangeKey" 351 projection_type = "ALL" 352 } 353 global_secondary_index { 354 name = "ReplacementTestTableGSI" 355 hash_key = "TestTableHashKey" 356 range_key = "ReplacementGSIRangeKey" 357 write_capacity = 5 358 read_capacity = 5 359 projection_type = "INCLUDE" 360 non_key_attributes = ["TestNonKeyAttribute"] 361 } 362 } 363 ` 364 365 func testAccAWSDynamoDbConfigStreamSpecification() string { 366 return fmt.Sprintf(` 367 resource "aws_dynamodb_table" "basic-dynamodb-table" { 368 name = "TerraformTestStreamTable-%d" 369 read_capacity = 10 370 write_capacity = 20 371 hash_key = "TestTableHashKey" 372 range_key = "TestTableRangeKey" 373 attribute { 374 name = "TestTableHashKey" 375 type = "S" 376 } 377 attribute { 378 name = "TestTableRangeKey" 379 type = "S" 380 } 381 attribute { 382 name = "TestLSIRangeKey" 383 type = "N" 384 } 385 attribute { 386 name = "TestGSIRangeKey" 387 type = "S" 388 } 389 local_secondary_index { 390 name = "TestTableLSI" 391 range_key = "TestLSIRangeKey" 392 projection_type = "ALL" 393 } 394 global_secondary_index { 395 name = "InitialTestTableGSI" 396 hash_key = "TestTableHashKey" 397 range_key = "TestGSIRangeKey" 398 write_capacity = 10 399 read_capacity = 10 400 projection_type = "KEYS_ONLY" 401 } 402 stream_enabled = true 403 stream_view_type = "KEYS_ONLY" 404 } 405 `, acctest.RandInt()) 406 }