github.com/dougneal/terraform@v0.6.15-0.20170330092735-b6a3840768a4/backend/remote-state/s3/backend_test.go (about)

     1  package s3
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/service/dynamodb"
    11  	"github.com/aws/aws-sdk-go/service/s3"
    12  	"github.com/hashicorp/terraform/backend"
    13  )
    14  
    15  // verify that we are doing ACC tests or the S3 tests specifically
    16  func testACC(t *testing.T) {
    17  	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_S3_TEST") == ""
    18  	if skip {
    19  		t.Log("s3 backend tests require setting TF_ACC or TF_S3_TEST")
    20  		t.Skip()
    21  	}
    22  	if os.Getenv("AWS_DEFAULT_REGION") == "" {
    23  		os.Setenv("AWS_DEFAULT_REGION", "us-west-2")
    24  	}
    25  }
    26  
    27  func TestBackend_impl(t *testing.T) {
    28  	var _ backend.Backend = new(Backend)
    29  }
    30  
    31  func TestBackendConfig(t *testing.T) {
    32  	// This test just instantiates the client. Shouldn't make any actual
    33  	// requests nor incur any costs.
    34  
    35  	config := map[string]interface{}{
    36  		"region":     "us-west-1",
    37  		"bucket":     "tf-test",
    38  		"key":        "state",
    39  		"encrypt":    true,
    40  		"access_key": "ACCESS_KEY",
    41  		"secret_key": "SECRET_KEY",
    42  		"lock_table": "dynamoTable",
    43  	}
    44  
    45  	b := backend.TestBackendConfig(t, New(), config).(*Backend)
    46  
    47  	if *b.s3Client.Config.Region != "us-west-1" {
    48  		t.Fatalf("Incorrect region was populated")
    49  	}
    50  	if b.bucketName != "tf-test" {
    51  		t.Fatalf("Incorrect bucketName was populated")
    52  	}
    53  	if b.keyName != "state" {
    54  		t.Fatalf("Incorrect keyName was populated")
    55  	}
    56  
    57  	credentials, err := b.s3Client.Config.Credentials.Get()
    58  	if err != nil {
    59  		t.Fatalf("Error when requesting credentials")
    60  	}
    61  	if credentials.AccessKeyID != "ACCESS_KEY" {
    62  		t.Fatalf("Incorrect Access Key Id was populated")
    63  	}
    64  	if credentials.SecretAccessKey != "SECRET_KEY" {
    65  		t.Fatalf("Incorrect Secret Access Key was populated")
    66  	}
    67  }
    68  
    69  func TestBackend(t *testing.T) {
    70  	testACC(t)
    71  
    72  	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
    73  	keyName := "testState"
    74  
    75  	b := backend.TestBackendConfig(t, New(), map[string]interface{}{
    76  		"bucket":  bucketName,
    77  		"key":     keyName,
    78  		"encrypt": true,
    79  	}).(*Backend)
    80  
    81  	createS3Bucket(t, b.s3Client, bucketName)
    82  	defer deleteS3Bucket(t, b.s3Client, bucketName)
    83  
    84  	backend.TestBackend(t, b, nil)
    85  }
    86  
    87  func TestBackendLocked(t *testing.T) {
    88  	testACC(t)
    89  
    90  	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
    91  	keyName := "testState"
    92  
    93  	b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
    94  		"bucket":     bucketName,
    95  		"key":        keyName,
    96  		"encrypt":    true,
    97  		"lock_table": bucketName,
    98  	}).(*Backend)
    99  
   100  	b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
   101  		"bucket":     bucketName,
   102  		"key":        keyName,
   103  		"encrypt":    true,
   104  		"lock_table": bucketName,
   105  	}).(*Backend)
   106  
   107  	createS3Bucket(t, b1.s3Client, bucketName)
   108  	defer deleteS3Bucket(t, b1.s3Client, bucketName)
   109  	createDynamoDBTable(t, b1.dynClient, bucketName)
   110  	defer deleteDynamoDBTable(t, b1.dynClient, bucketName)
   111  
   112  	backend.TestBackend(t, b1, b2)
   113  }
   114  
   115  func createS3Bucket(t *testing.T, s3Client *s3.S3, bucketName string) {
   116  	createBucketReq := &s3.CreateBucketInput{
   117  		Bucket: &bucketName,
   118  	}
   119  
   120  	// Be clear about what we're doing in case the user needs to clean
   121  	// this up later.
   122  	t.Logf("creating S3 bucket %s in %s", bucketName, *s3Client.Config.Region)
   123  	_, err := s3Client.CreateBucket(createBucketReq)
   124  	if err != nil {
   125  		t.Fatal("failed to create test S3 bucket:", err)
   126  	}
   127  }
   128  
   129  func deleteS3Bucket(t *testing.T, s3Client *s3.S3, bucketName string) {
   130  	warning := "WARNING: Failed to delete the test S3 bucket. It may have been left in your AWS account and may incur storage charges. (error was %s)"
   131  
   132  	// first we have to get rid of the env objects, or we can't delete the bucket
   133  	resp, err := s3Client.ListObjects(&s3.ListObjectsInput{Bucket: &bucketName})
   134  	if err != nil {
   135  		t.Logf(warning, err)
   136  		return
   137  	}
   138  	for _, obj := range resp.Contents {
   139  		if _, err := s3Client.DeleteObject(&s3.DeleteObjectInput{Bucket: &bucketName, Key: obj.Key}); err != nil {
   140  			// this will need cleanup no matter what, so just warn and exit
   141  			t.Logf(warning, err)
   142  			return
   143  		}
   144  	}
   145  
   146  	if _, err := s3Client.DeleteBucket(&s3.DeleteBucketInput{Bucket: &bucketName}); err != nil {
   147  		t.Logf(warning, err)
   148  	}
   149  }
   150  
   151  // create the dynamoDB table, and wait until we can query it.
   152  func createDynamoDBTable(t *testing.T, dynClient *dynamodb.DynamoDB, tableName string) {
   153  	createInput := &dynamodb.CreateTableInput{
   154  		AttributeDefinitions: []*dynamodb.AttributeDefinition{
   155  			{
   156  				AttributeName: aws.String("LockID"),
   157  				AttributeType: aws.String("S"),
   158  			},
   159  		},
   160  		KeySchema: []*dynamodb.KeySchemaElement{
   161  			{
   162  				AttributeName: aws.String("LockID"),
   163  				KeyType:       aws.String("HASH"),
   164  			},
   165  		},
   166  		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
   167  			ReadCapacityUnits:  aws.Int64(5),
   168  			WriteCapacityUnits: aws.Int64(5),
   169  		},
   170  		TableName: aws.String(tableName),
   171  	}
   172  
   173  	_, err := dynClient.CreateTable(createInput)
   174  	if err != nil {
   175  		t.Fatal(err)
   176  	}
   177  
   178  	// now wait until it's ACTIVE
   179  	start := time.Now()
   180  	time.Sleep(time.Second)
   181  
   182  	describeInput := &dynamodb.DescribeTableInput{
   183  		TableName: aws.String(tableName),
   184  	}
   185  
   186  	for {
   187  		resp, err := dynClient.DescribeTable(describeInput)
   188  		if err != nil {
   189  			t.Fatal(err)
   190  		}
   191  
   192  		if *resp.Table.TableStatus == "ACTIVE" {
   193  			return
   194  		}
   195  
   196  		if time.Since(start) > time.Minute {
   197  			t.Fatalf("timed out creating DynamoDB table %s", tableName)
   198  		}
   199  
   200  		time.Sleep(3 * time.Second)
   201  	}
   202  
   203  }
   204  
   205  func deleteDynamoDBTable(t *testing.T, dynClient *dynamodb.DynamoDB, tableName string) {
   206  	params := &dynamodb.DeleteTableInput{
   207  		TableName: aws.String(tableName),
   208  	}
   209  	_, err := dynClient.DeleteTable(params)
   210  	if err != nil {
   211  		t.Logf("WARNING: Failed to delete the test DynamoDB table %q. It has been left in your AWS account and may incur charges. (error was %s)", tableName, err)
   212  	}
   213  }