github.com/simonswine/terraform@v0.9.0-beta2/state/remote/s3_test.go (about)

     1  package remote
     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  )
    13  
    14  func TestS3Client_impl(t *testing.T) {
    15  	var _ Client = new(S3Client)
    16  	var _ ClientLocker = new(S3Client)
    17  }
    18  
    19  func TestS3Factory(t *testing.T) {
    20  	// This test just instantiates the client. Shouldn't make any actual
    21  	// requests nor incur any costs.
    22  
    23  	config := make(map[string]string)
    24  
    25  	// Empty config is an error
    26  	_, err := s3Factory(config)
    27  	if err == nil {
    28  		t.Fatalf("Empty config should be error")
    29  	}
    30  
    31  	config["region"] = "us-west-1"
    32  	config["bucket"] = "foo"
    33  	config["key"] = "bar"
    34  	config["encrypt"] = "1"
    35  
    36  	// For this test we'll provide the credentials as config. The
    37  	// acceptance tests implicitly test passing credentials as
    38  	// environment variables.
    39  	config["access_key"] = "bazkey"
    40  	config["secret_key"] = "bazsecret"
    41  
    42  	client, err := s3Factory(config)
    43  	if err != nil {
    44  		t.Fatalf("Error for valid config")
    45  	}
    46  
    47  	s3Client := client.(*S3Client)
    48  
    49  	if *s3Client.nativeClient.Config.Region != "us-west-1" {
    50  		t.Fatalf("Incorrect region was populated")
    51  	}
    52  	if s3Client.bucketName != "foo" {
    53  		t.Fatalf("Incorrect bucketName was populated")
    54  	}
    55  	if s3Client.keyName != "bar" {
    56  		t.Fatalf("Incorrect keyName was populated")
    57  	}
    58  
    59  	credentials, err := s3Client.nativeClient.Config.Credentials.Get()
    60  	if err != nil {
    61  		t.Fatalf("Error when requesting credentials")
    62  	}
    63  	if credentials.AccessKeyID != "bazkey" {
    64  		t.Fatalf("Incorrect Access Key Id was populated")
    65  	}
    66  	if credentials.SecretAccessKey != "bazsecret" {
    67  		t.Fatalf("Incorrect Secret Access Key was populated")
    68  	}
    69  }
    70  
    71  func TestS3Client(t *testing.T) {
    72  	// This test creates a bucket in S3 and populates it.
    73  	// It may incur costs, so it will only run if AWS credential environment
    74  	// variables are present.
    75  
    76  	accessKeyId := os.Getenv("AWS_ACCESS_KEY_ID")
    77  	if accessKeyId == "" {
    78  		t.Skipf("skipping; AWS_ACCESS_KEY_ID must be set")
    79  	}
    80  
    81  	regionName := os.Getenv("AWS_DEFAULT_REGION")
    82  	if regionName == "" {
    83  		regionName = "us-west-2"
    84  	}
    85  
    86  	bucketName := fmt.Sprintf("terraform-remote-s3-test-%x", time.Now().Unix())
    87  	keyName := "testState"
    88  	testData := []byte(`testing data`)
    89  
    90  	config := make(map[string]string)
    91  	config["region"] = regionName
    92  	config["bucket"] = bucketName
    93  	config["key"] = keyName
    94  	config["encrypt"] = "1"
    95  
    96  	client, err := s3Factory(config)
    97  	if err != nil {
    98  		t.Fatalf("Error for valid config")
    99  	}
   100  
   101  	s3Client := client.(*S3Client)
   102  	nativeClient := s3Client.nativeClient
   103  
   104  	createBucketReq := &s3.CreateBucketInput{
   105  		Bucket: &bucketName,
   106  	}
   107  
   108  	// Be clear about what we're doing in case the user needs to clean
   109  	// this up later.
   110  	t.Logf("Creating S3 bucket %s in %s", bucketName, regionName)
   111  	_, err = nativeClient.CreateBucket(createBucketReq)
   112  	if err != nil {
   113  		t.Skipf("Failed to create test S3 bucket, so skipping")
   114  	}
   115  
   116  	// Ensure we can perform a PUT request with the encryption header
   117  	err = s3Client.Put(testData)
   118  	if err != nil {
   119  		t.Logf("WARNING: Failed to send test data to S3 bucket. (error was %s)", err)
   120  	}
   121  
   122  	defer func() {
   123  		deleteBucketReq := &s3.DeleteBucketInput{
   124  			Bucket: &bucketName,
   125  		}
   126  
   127  		_, err := nativeClient.DeleteBucket(deleteBucketReq)
   128  		if err != nil {
   129  			t.Logf("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)", err)
   130  		}
   131  	}()
   132  
   133  	testClient(t, client)
   134  }
   135  
   136  func TestS3ClientLocks(t *testing.T) {
   137  	// This test creates a DynamoDB table.
   138  	// It may incur costs, so it will only run if AWS credential environment
   139  	// variables are present.
   140  
   141  	accessKeyId := os.Getenv("AWS_ACCESS_KEY_ID")
   142  	if accessKeyId == "" {
   143  		t.Skipf("skipping; AWS_ACCESS_KEY_ID must be set")
   144  	}
   145  
   146  	regionName := os.Getenv("AWS_DEFAULT_REGION")
   147  	if regionName == "" {
   148  		regionName = "us-west-2"
   149  	}
   150  
   151  	bucketName := fmt.Sprintf("terraform-remote-s3-lock-%x", time.Now().Unix())
   152  	keyName := "testState"
   153  
   154  	config := make(map[string]string)
   155  	config["region"] = regionName
   156  	config["bucket"] = bucketName
   157  	config["key"] = keyName
   158  	config["encrypt"] = "1"
   159  	config["lock_table"] = bucketName
   160  
   161  	client, err := s3Factory(config)
   162  	if err != nil {
   163  		t.Fatalf("Error for valid config")
   164  	}
   165  
   166  	s3Client := client.(*S3Client)
   167  
   168  	// set this up before we try to crate the table, in case we timeout creating it.
   169  	defer deleteDynaboDBTable(t, s3Client, bucketName)
   170  
   171  	createDynamoDBTable(t, s3Client, bucketName)
   172  
   173  	TestRemoteLocks(t, client, client)
   174  }
   175  
   176  // create the dynamoDB table, and wait until we can query it.
   177  func createDynamoDBTable(t *testing.T, c *S3Client, tableName string) {
   178  	createInput := &dynamodb.CreateTableInput{
   179  		AttributeDefinitions: []*dynamodb.AttributeDefinition{
   180  			{
   181  				AttributeName: aws.String("LockID"),
   182  				AttributeType: aws.String("S"),
   183  			},
   184  		},
   185  		KeySchema: []*dynamodb.KeySchemaElement{
   186  			{
   187  				AttributeName: aws.String("LockID"),
   188  				KeyType:       aws.String("HASH"),
   189  			},
   190  		},
   191  		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
   192  			ReadCapacityUnits:  aws.Int64(5),
   193  			WriteCapacityUnits: aws.Int64(5),
   194  		},
   195  		TableName: aws.String(tableName),
   196  	}
   197  
   198  	_, err := c.dynClient.CreateTable(createInput)
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  
   203  	// now wait until it's ACTIVE
   204  	start := time.Now()
   205  	time.Sleep(time.Second)
   206  
   207  	describeInput := &dynamodb.DescribeTableInput{
   208  		TableName: aws.String(tableName),
   209  	}
   210  
   211  	for {
   212  		resp, err := c.dynClient.DescribeTable(describeInput)
   213  		if err != nil {
   214  			t.Fatal(err)
   215  		}
   216  
   217  		if *resp.Table.TableStatus == "ACTIVE" {
   218  			return
   219  		}
   220  
   221  		if time.Since(start) > time.Minute {
   222  			t.Fatalf("timed out creating DynamoDB table %s", tableName)
   223  		}
   224  
   225  		time.Sleep(3 * time.Second)
   226  	}
   227  
   228  }
   229  
   230  func deleteDynaboDBTable(t *testing.T, c *S3Client, tableName string) {
   231  	params := &dynamodb.DeleteTableInput{
   232  		TableName: aws.String(tableName),
   233  	}
   234  	_, err := c.dynClient.DeleteTable(params)
   235  	if err != nil {
   236  		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)
   237  	}
   238  }