2017-03-21 18:43:31 +01:00
package s3
import (
"fmt"
"os"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/hashicorp/terraform/backend"
)
// verify that we are doing ACC tests or the S3 tests specifically
func testACC ( t * testing . T ) {
skip := os . Getenv ( "TF_ACC" ) == "" && os . Getenv ( "TF_S3_TEST" ) == ""
if skip {
t . Log ( "s3 backend tests require setting TF_ACC or TF_S3_TEST" )
t . Skip ( )
}
if os . Getenv ( "AWS_DEFAULT_REGION" ) == "" {
os . Setenv ( "AWS_DEFAULT_REGION" , "us-west-2" )
}
}
func TestBackend_impl ( t * testing . T ) {
var _ backend . Backend = new ( Backend )
}
func TestBackendConfig ( t * testing . T ) {
// This test just instantiates the client. Shouldn't make any actual
// requests nor incur any costs.
config := map [ string ] interface { } {
"region" : "us-west-1" ,
"bucket" : "tf-test" ,
"key" : "state" ,
"encrypt" : true ,
"access_key" : "ACCESS_KEY" ,
"secret_key" : "SECRET_KEY" ,
"lock_table" : "dynamoTable" ,
}
b := backend . TestBackendConfig ( t , New ( ) , config ) . ( * Backend )
2017-03-22 20:52:55 +01:00
if * b . s3Client . Config . Region != "us-west-1" {
2017-03-21 18:43:31 +01:00
t . Fatalf ( "Incorrect region was populated" )
}
2017-03-22 20:52:55 +01:00
if b . bucketName != "tf-test" {
2017-03-21 18:43:31 +01:00
t . Fatalf ( "Incorrect bucketName was populated" )
}
2017-03-22 20:52:55 +01:00
if b . keyName != "state" {
2017-03-21 18:43:31 +01:00
t . Fatalf ( "Incorrect keyName was populated" )
}
2017-03-22 20:52:55 +01:00
credentials , err := b . s3Client . Config . Credentials . Get ( )
2017-03-21 18:43:31 +01:00
if err != nil {
t . Fatalf ( "Error when requesting credentials" )
}
if credentials . AccessKeyID != "ACCESS_KEY" {
t . Fatalf ( "Incorrect Access Key Id was populated" )
}
if credentials . SecretAccessKey != "SECRET_KEY" {
t . Fatalf ( "Incorrect Secret Access Key was populated" )
}
}
func TestBackend ( t * testing . T ) {
testACC ( t )
bucketName := fmt . Sprintf ( "terraform-remote-s3-test-%x" , time . Now ( ) . Unix ( ) )
keyName := "testState"
b := backend . TestBackendConfig ( t , New ( ) , map [ string ] interface { } {
"bucket" : bucketName ,
"key" : keyName ,
"encrypt" : true ,
} ) . ( * Backend )
2017-03-22 20:52:55 +01:00
createS3Bucket ( t , b . s3Client , bucketName )
defer deleteS3Bucket ( t , b . s3Client , bucketName )
2017-03-21 18:43:31 +01:00
backend . TestBackend ( t , b , nil )
}
func TestBackendLocked ( t * testing . T ) {
testACC ( t )
bucketName := fmt . Sprintf ( "terraform-remote-s3-test-%x" , time . Now ( ) . Unix ( ) )
keyName := "testState"
b1 := backend . TestBackendConfig ( t , New ( ) , map [ string ] interface { } {
"bucket" : bucketName ,
"key" : keyName ,
"encrypt" : true ,
"lock_table" : bucketName ,
} ) . ( * Backend )
b2 := backend . TestBackendConfig ( t , New ( ) , map [ string ] interface { } {
"bucket" : bucketName ,
"key" : keyName ,
"encrypt" : true ,
"lock_table" : bucketName ,
} ) . ( * Backend )
2017-03-22 20:52:55 +01:00
createS3Bucket ( t , b1 . s3Client , bucketName )
defer deleteS3Bucket ( t , b1 . s3Client , bucketName )
createDynamoDBTable ( t , b1 . dynClient , bucketName )
defer deleteDynamoDBTable ( t , b1 . dynClient , bucketName )
2017-03-21 18:43:31 +01:00
backend . TestBackend ( t , b1 , b2 )
}
2017-03-22 20:52:55 +01:00
func createS3Bucket ( t * testing . T , s3Client * s3 . S3 , bucketName string ) {
2017-03-21 18:43:31 +01:00
createBucketReq := & s3 . CreateBucketInput {
Bucket : & bucketName ,
}
// Be clear about what we're doing in case the user needs to clean
// this up later.
2017-03-22 20:52:55 +01:00
t . Logf ( "creating S3 bucket %s in %s" , bucketName , * s3Client . Config . Region )
_ , err := s3Client . CreateBucket ( createBucketReq )
2017-03-21 18:43:31 +01:00
if err != nil {
t . Fatal ( "failed to create test S3 bucket:" , err )
}
}
2017-03-22 20:52:55 +01:00
func deleteS3Bucket ( t * testing . T , s3Client * s3 . S3 , bucketName string ) {
2017-03-22 21:33:41 +01:00
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)"
2017-03-21 18:43:31 +01:00
2017-03-22 21:33:41 +01:00
// first we have to get rid of the env objects, or we can't delete the bucket
resp , err := s3Client . ListObjects ( & s3 . ListObjectsInput { Bucket : & bucketName } )
2017-03-21 18:43:31 +01:00
if err != nil {
2017-03-22 21:33:41 +01:00
t . Logf ( warning , err )
return
}
for _ , obj := range resp . Contents {
if _ , err := s3Client . DeleteObject ( & s3 . DeleteObjectInput { Bucket : & bucketName , Key : obj . Key } ) ; err != nil {
// this will need cleanup no matter what, so just warn and exit
t . Logf ( warning , err )
return
}
}
if _ , err := s3Client . DeleteBucket ( & s3 . DeleteBucketInput { Bucket : & bucketName } ) ; err != nil {
t . Logf ( warning , err )
2017-03-21 18:43:31 +01:00
}
}
// create the dynamoDB table, and wait until we can query it.
2017-03-22 20:52:55 +01:00
func createDynamoDBTable ( t * testing . T , dynClient * dynamodb . DynamoDB , tableName string ) {
2017-03-21 18:43:31 +01:00
createInput := & dynamodb . CreateTableInput {
AttributeDefinitions : [ ] * dynamodb . AttributeDefinition {
{
AttributeName : aws . String ( "LockID" ) ,
AttributeType : aws . String ( "S" ) ,
} ,
} ,
KeySchema : [ ] * dynamodb . KeySchemaElement {
{
AttributeName : aws . String ( "LockID" ) ,
KeyType : aws . String ( "HASH" ) ,
} ,
} ,
ProvisionedThroughput : & dynamodb . ProvisionedThroughput {
ReadCapacityUnits : aws . Int64 ( 5 ) ,
WriteCapacityUnits : aws . Int64 ( 5 ) ,
} ,
TableName : aws . String ( tableName ) ,
}
2017-03-22 20:52:55 +01:00
_ , err := dynClient . CreateTable ( createInput )
2017-03-21 18:43:31 +01:00
if err != nil {
t . Fatal ( err )
}
// now wait until it's ACTIVE
start := time . Now ( )
time . Sleep ( time . Second )
describeInput := & dynamodb . DescribeTableInput {
TableName : aws . String ( tableName ) ,
}
for {
2017-03-22 20:52:55 +01:00
resp , err := dynClient . DescribeTable ( describeInput )
2017-03-21 18:43:31 +01:00
if err != nil {
t . Fatal ( err )
}
if * resp . Table . TableStatus == "ACTIVE" {
return
}
if time . Since ( start ) > time . Minute {
t . Fatalf ( "timed out creating DynamoDB table %s" , tableName )
}
time . Sleep ( 3 * time . Second )
}
}
2017-03-22 20:52:55 +01:00
func deleteDynamoDBTable ( t * testing . T , dynClient * dynamodb . DynamoDB , tableName string ) {
2017-03-21 18:43:31 +01:00
params := & dynamodb . DeleteTableInput {
TableName : aws . String ( tableName ) ,
}
2017-03-22 20:52:55 +01:00
_ , err := dynClient . DeleteTable ( params )
2017-03-21 18:43:31 +01:00
if err != nil {
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 )
}
}