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