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