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  }