github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_s3_bucket_notification_test.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/hashicorp/terraform/helper/acctest"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/terraform"
    13  
    14  	"github.com/aws/aws-sdk-go/aws"
    15  	"github.com/aws/aws-sdk-go/aws/awserr"
    16  	"github.com/aws/aws-sdk-go/service/s3"
    17  )
    18  
    19  func TestAccAWSS3Bucket_Notification(t *testing.T) {
    20  	rInt := acctest.RandInt()
    21  	resource.Test(t, resource.TestCase{
    22  		PreCheck:     func() { testAccPreCheck(t) },
    23  		Providers:    testAccProviders,
    24  		CheckDestroy: testAccCheckAWSS3BucketNotificationDestroy,
    25  		Steps: []resource.TestStep{
    26  			resource.TestStep{
    27  				Config: testAccAWSS3BucketConfigWithTopicNotification(rInt),
    28  				Check: resource.ComposeTestCheckFunc(
    29  					testAccCheckAWSS3BucketTopicNotification(
    30  						"aws_s3_bucket.bucket",
    31  						"notification-sns1",
    32  						"aws_sns_topic.topic",
    33  						[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
    34  						&s3.KeyFilter{
    35  							FilterRules: []*s3.FilterRule{
    36  								&s3.FilterRule{
    37  									Name:  aws.String("Prefix"),
    38  									Value: aws.String(fmt.Sprintf("%d/", rInt)),
    39  								},
    40  								&s3.FilterRule{
    41  									Name:  aws.String("Suffix"),
    42  									Value: aws.String(".txt"),
    43  								},
    44  							},
    45  						},
    46  					),
    47  					testAccCheckAWSS3BucketTopicNotification(
    48  						"aws_s3_bucket.bucket",
    49  						"notification-sns2",
    50  						"aws_sns_topic.topic",
    51  						[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
    52  						&s3.KeyFilter{
    53  							FilterRules: []*s3.FilterRule{
    54  								&s3.FilterRule{
    55  									Name:  aws.String("Suffix"),
    56  									Value: aws.String(".log"),
    57  								},
    58  							},
    59  						},
    60  					),
    61  				),
    62  			},
    63  			resource.TestStep{
    64  				Config: testAccAWSS3BucketConfigWithQueueNotification(rInt),
    65  				Check: resource.ComposeTestCheckFunc(
    66  					testAccCheckAWSS3BucketQueueNotification(
    67  						"aws_s3_bucket.bucket",
    68  						"notification-sqs",
    69  						"aws_sqs_queue.queue",
    70  						[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
    71  						&s3.KeyFilter{
    72  							FilterRules: []*s3.FilterRule{
    73  								&s3.FilterRule{
    74  									Name:  aws.String("Prefix"),
    75  									Value: aws.String(fmt.Sprintf("%d/", rInt)),
    76  								},
    77  								&s3.FilterRule{
    78  									Name:  aws.String("Suffix"),
    79  									Value: aws.String(".mp4"),
    80  								},
    81  							},
    82  						},
    83  					),
    84  				),
    85  			},
    86  			resource.TestStep{
    87  				Config: testAccAWSS3BucketConfigWithLambdaNotification(rInt),
    88  				Check: resource.ComposeTestCheckFunc(
    89  					testAccCheckAWSS3BucketLambdaFunctionConfiguration(
    90  						"aws_s3_bucket.bucket",
    91  						"notification-lambda",
    92  						"aws_lambda_function.func",
    93  						[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
    94  						&s3.KeyFilter{
    95  							FilterRules: []*s3.FilterRule{
    96  								&s3.FilterRule{
    97  									Name:  aws.String("Prefix"),
    98  									Value: aws.String(fmt.Sprintf("%d/", rInt)),
    99  								},
   100  								&s3.FilterRule{
   101  									Name:  aws.String("Suffix"),
   102  									Value: aws.String(".png"),
   103  								},
   104  							},
   105  						},
   106  					),
   107  				),
   108  			},
   109  		},
   110  	})
   111  }
   112  
   113  func TestAccAWSS3Bucket_NotificationWithoutFilter(t *testing.T) {
   114  	rInt := acctest.RandInt()
   115  	resource.Test(t, resource.TestCase{
   116  		PreCheck:     func() { testAccPreCheck(t) },
   117  		Providers:    testAccProviders,
   118  		CheckDestroy: testAccCheckAWSS3BucketNotificationDestroy,
   119  		Steps: []resource.TestStep{
   120  			resource.TestStep{
   121  				Config: testAccAWSS3BucketConfigWithTopicNotificationWithoutFilter(rInt),
   122  				Check: resource.ComposeTestCheckFunc(
   123  					testAccCheckAWSS3BucketTopicNotification(
   124  						"aws_s3_bucket.bucket",
   125  						"notification-sns1",
   126  						"aws_sns_topic.topic",
   127  						[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
   128  						nil,
   129  					),
   130  				),
   131  			},
   132  		},
   133  	})
   134  }
   135  
   136  func testAccCheckAWSS3BucketNotificationDestroy(s *terraform.State) error {
   137  	conn := testAccProvider.Meta().(*AWSClient).s3conn
   138  
   139  	for _, rs := range s.RootModule().Resources {
   140  		if rs.Type != "aws_s3_bucket_notification" {
   141  			continue
   142  		}
   143  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
   144  			out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
   145  				Bucket: aws.String(rs.Primary.ID),
   146  			})
   147  			if err != nil {
   148  				if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchBucket" {
   149  					return nil
   150  				}
   151  				return resource.NonRetryableError(err)
   152  			}
   153  			if len(out.TopicConfigurations) > 0 {
   154  				return resource.RetryableError(fmt.Errorf("TopicConfigurations is exists: %v", out))
   155  			}
   156  			if len(out.LambdaFunctionConfigurations) > 0 {
   157  				return resource.RetryableError(fmt.Errorf("LambdaFunctionConfigurations is exists: %v", out))
   158  			}
   159  			if len(out.QueueConfigurations) > 0 {
   160  				return resource.RetryableError(fmt.Errorf("QueueConfigurations is exists: %v", out))
   161  			}
   162  
   163  			return nil
   164  		})
   165  
   166  		if err != nil {
   167  			return err
   168  		}
   169  	}
   170  	return nil
   171  }
   172  
   173  func testAccCheckAWSS3BucketTopicNotification(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc {
   174  	return func(s *terraform.State) error {
   175  		rs, _ := s.RootModule().Resources[n]
   176  		topicArn := s.RootModule().Resources[t].Primary.ID
   177  		conn := testAccProvider.Meta().(*AWSClient).s3conn
   178  
   179  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
   180  			out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
   181  				Bucket: aws.String(rs.Primary.ID),
   182  			})
   183  
   184  			if err != nil {
   185  				return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err))
   186  			}
   187  
   188  			eventSlice := sort.StringSlice(events)
   189  			eventSlice.Sort()
   190  
   191  			outputTopics := out.TopicConfigurations
   192  			matched := false
   193  			for _, outputTopic := range outputTopics {
   194  				if *outputTopic.Id == i {
   195  					matched = true
   196  
   197  					if *outputTopic.TopicArn != topicArn {
   198  						return resource.RetryableError(fmt.Errorf("bad topic arn, expected: %s, got %#v", topicArn, *outputTopic.TopicArn))
   199  					}
   200  
   201  					if filters != nil {
   202  						if !reflect.DeepEqual(filters, outputTopic.Filter.Key) {
   203  							return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputTopic.Filter.Key))
   204  						}
   205  					} else {
   206  						if outputTopic.Filter != nil {
   207  							return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputTopic.Filter))
   208  						}
   209  					}
   210  
   211  					outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputTopic.Events))
   212  					outputEventSlice.Sort()
   213  					if !reflect.DeepEqual(eventSlice, outputEventSlice) {
   214  						return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice))
   215  					}
   216  				}
   217  			}
   218  
   219  			if !matched {
   220  				return resource.RetryableError(fmt.Errorf("No match topic configurations: %#v", out))
   221  			}
   222  
   223  			return nil
   224  		})
   225  
   226  		return err
   227  	}
   228  }
   229  
   230  func testAccCheckAWSS3BucketQueueNotification(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc {
   231  	return func(s *terraform.State) error {
   232  		rs, _ := s.RootModule().Resources[n]
   233  		queueArn := s.RootModule().Resources[t].Primary.Attributes["arn"]
   234  		conn := testAccProvider.Meta().(*AWSClient).s3conn
   235  
   236  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
   237  			out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
   238  				Bucket: aws.String(rs.Primary.ID),
   239  			})
   240  
   241  			if err != nil {
   242  				return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err))
   243  			}
   244  
   245  			eventSlice := sort.StringSlice(events)
   246  			eventSlice.Sort()
   247  
   248  			outputQueues := out.QueueConfigurations
   249  			matched := false
   250  			for _, outputQueue := range outputQueues {
   251  				if *outputQueue.Id == i {
   252  					matched = true
   253  
   254  					if *outputQueue.QueueArn != queueArn {
   255  						return resource.RetryableError(fmt.Errorf("bad queue arn, expected: %s, got %#v", queueArn, *outputQueue.QueueArn))
   256  					}
   257  
   258  					if filters != nil {
   259  						if !reflect.DeepEqual(filters, outputQueue.Filter.Key) {
   260  							return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputQueue.Filter.Key))
   261  						}
   262  					} else {
   263  						if outputQueue.Filter != nil {
   264  							return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputQueue.Filter))
   265  						}
   266  					}
   267  
   268  					outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputQueue.Events))
   269  					outputEventSlice.Sort()
   270  					if !reflect.DeepEqual(eventSlice, outputEventSlice) {
   271  						return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice))
   272  					}
   273  				}
   274  			}
   275  
   276  			if !matched {
   277  				return resource.RetryableError(fmt.Errorf("No match queue configurations: %#v", out))
   278  			}
   279  
   280  			return nil
   281  		})
   282  
   283  		return err
   284  	}
   285  }
   286  
   287  func testAccCheckAWSS3BucketLambdaFunctionConfiguration(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc {
   288  	return func(s *terraform.State) error {
   289  		rs, _ := s.RootModule().Resources[n]
   290  		funcArn := s.RootModule().Resources[t].Primary.Attributes["arn"]
   291  		conn := testAccProvider.Meta().(*AWSClient).s3conn
   292  
   293  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
   294  			out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
   295  				Bucket: aws.String(rs.Primary.ID),
   296  			})
   297  
   298  			if err != nil {
   299  				return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err))
   300  			}
   301  
   302  			eventSlice := sort.StringSlice(events)
   303  			eventSlice.Sort()
   304  
   305  			outputFunctions := out.LambdaFunctionConfigurations
   306  			matched := false
   307  			for _, outputFunc := range outputFunctions {
   308  				if *outputFunc.Id == i {
   309  					matched = true
   310  
   311  					if *outputFunc.LambdaFunctionArn != funcArn {
   312  						return resource.RetryableError(fmt.Errorf("bad lambda function arn, expected: %s, got %#v", funcArn, *outputFunc.LambdaFunctionArn))
   313  					}
   314  
   315  					if filters != nil {
   316  						if !reflect.DeepEqual(filters, outputFunc.Filter.Key) {
   317  							return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputFunc.Filter.Key))
   318  						}
   319  					} else {
   320  						if outputFunc.Filter != nil {
   321  							return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputFunc.Filter))
   322  						}
   323  					}
   324  
   325  					outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputFunc.Events))
   326  					outputEventSlice.Sort()
   327  					if !reflect.DeepEqual(eventSlice, outputEventSlice) {
   328  						return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice))
   329  					}
   330  				}
   331  			}
   332  
   333  			if !matched {
   334  				return resource.RetryableError(fmt.Errorf("No match lambda function configurations: %#v", out))
   335  			}
   336  
   337  			return nil
   338  		})
   339  
   340  		return err
   341  	}
   342  }
   343  
   344  func testAccAWSS3BucketConfigWithTopicNotification(randInt int) string {
   345  	return fmt.Sprintf(`
   346  resource "aws_sns_topic" "topic" {
   347      name = "terraform-test-topic"
   348  	policy = <<POLICY
   349  {
   350  	"Version":"2012-10-17",
   351  	"Statement":[{
   352  		"Sid": "",
   353  		"Effect": "Allow",
   354  		"Principal": {"AWS":"*"},
   355  		"Action": "SNS:Publish",
   356  		"Resource": "arn:aws:sns:*:*:terraform-test-topic",
   357  		"Condition":{
   358  			"ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"}
   359  		}
   360  	}]
   361  }
   362  POLICY
   363  }
   364  
   365  resource "aws_s3_bucket" "bucket" {
   366  	bucket = "tf-test-bucket-%d"
   367  	acl = "public-read"
   368  }
   369  
   370  resource "aws_s3_bucket_notification" "notification" {
   371  	bucket = "${aws_s3_bucket.bucket.id}"
   372  	topic {
   373  		id = "notification-sns1"
   374  		topic_arn = "${aws_sns_topic.topic.arn}"
   375  		events = [
   376  		  "s3:ObjectCreated:*",
   377  		  "s3:ObjectRemoved:Delete",
   378  		]
   379  		filter_prefix = "%d/"
   380  		filter_suffix = ".txt"
   381  	}
   382  	topic {
   383  		id = "notification-sns2"
   384  		topic_arn = "${aws_sns_topic.topic.arn}"
   385  		events = [
   386  		  "s3:ObjectCreated:*",
   387  		  "s3:ObjectRemoved:Delete",
   388  		]
   389  		filter_suffix = ".log"
   390  	}
   391  }
   392  `, randInt, randInt)
   393  }
   394  
   395  func testAccAWSS3BucketConfigWithQueueNotification(randInt int) string {
   396  	return fmt.Sprintf(`
   397  resource "aws_sqs_queue" "queue" {
   398      name = "terraform-test-queue-%d"
   399  	policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"sqs:SendMessage\",\"Resource\":\"arn:aws:sqs:*:*:terraform-test-queue-%d\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"${aws_s3_bucket.bucket.arn}\"}}}]}"
   400  }
   401  
   402  resource "aws_s3_bucket" "bucket" {
   403  	bucket = "tf-test-bucket-%d"
   404  	acl = "public-read"
   405  }
   406  
   407  resource "aws_s3_bucket_notification" "notification" {
   408  	bucket = "${aws_s3_bucket.bucket.id}"
   409  	queue {
   410  		id = "notification-sqs"
   411  		queue_arn = "${aws_sqs_queue.queue.arn}"
   412  		events = [
   413  		  "s3:ObjectCreated:*",
   414  		  "s3:ObjectRemoved:Delete",
   415  		]
   416  		filter_prefix = "%d/"
   417  		filter_suffix = ".mp4"
   418  	}
   419  }
   420  `, randInt, randInt, randInt, randInt)
   421  }
   422  
   423  func testAccAWSS3BucketConfigWithLambdaNotification(randInt int) string {
   424  	return fmt.Sprintf(`
   425  
   426  resource "aws_iam_role" "iam_for_lambda" {
   427      name = "iam_for_lambda"
   428      assume_role_policy = <<EOF
   429  {
   430    "Version": "2012-10-17",
   431    "Statement": [
   432      {
   433        "Action": "sts:AssumeRole",
   434        "Principal": {
   435          "Service": "lambda.amazonaws.com"
   436        },
   437        "Effect": "Allow",
   438        "Sid": ""
   439      }
   440    ]
   441  }
   442  EOF
   443  }
   444  
   445  resource "aws_lambda_permission" "allow_bucket" {
   446      statement_id = "AllowExecutionFromS3Bucket"
   447      action = "lambda:InvokeFunction"
   448      function_name = "${aws_lambda_function.func.arn}"
   449      principal = "s3.amazonaws.com"
   450      source_arn = "${aws_s3_bucket.bucket.arn}"
   451  }
   452  
   453  resource "aws_lambda_function" "func" {
   454      filename = "test-fixtures/lambdatest.zip"
   455      function_name = "example_lambda_name_%d"
   456      role = "${aws_iam_role.iam_for_lambda.arn}"
   457      handler = "exports.example"
   458  		runtime = "nodejs4.3"
   459  }
   460  
   461  resource "aws_s3_bucket" "bucket" {
   462  	bucket = "tf-test-bucket-%d"
   463  	acl = "public-read"
   464  }
   465  
   466  resource "aws_s3_bucket_notification" "notification" {
   467  	bucket = "${aws_s3_bucket.bucket.id}"
   468  	lambda_function {
   469  		id = "notification-lambda"
   470  		lambda_function_arn = "${aws_lambda_function.func.arn}"
   471  		events = [
   472  		  "s3:ObjectCreated:*",
   473  		  "s3:ObjectRemoved:Delete",
   474  		]
   475  		filter_prefix = "%d/"
   476  		filter_suffix = ".png"
   477  	}
   478  }
   479  `, randInt, randInt, randInt)
   480  }
   481  
   482  func testAccAWSS3BucketConfigWithTopicNotificationWithoutFilter(randInt int) string {
   483  	return fmt.Sprintf(`
   484  resource "aws_sns_topic" "topic" {
   485      name = "terraform-test-topic"
   486  	policy = <<POLICY
   487  {
   488  	"Version":"2012-10-17",
   489  	"Statement":[{
   490  		"Sid": "",
   491  		"Effect": "Allow",
   492  		"Principal": {"AWS":"*"},
   493  		"Action": "SNS:Publish",
   494  		"Resource": "arn:aws:sns:*:*:terraform-test-topic",
   495  		"Condition":{
   496  			"ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"}
   497  		}
   498  	}]
   499  }
   500  POLICY
   501  }
   502  
   503  resource "aws_s3_bucket" "bucket" {
   504  	bucket = "tf-test-bucket-%d"
   505  	acl = "public-read"
   506  }
   507  
   508  resource "aws_s3_bucket_notification" "notification" {
   509  	bucket = "${aws_s3_bucket.bucket.id}"
   510  	topic {
   511  		id = "notification-sns1"
   512  		topic_arn = "${aws_sns_topic.topic.arn}"
   513  		events = [
   514  		  "s3:ObjectCreated:*",
   515  		  "s3:ObjectRemoved:Delete",
   516  		]
   517  	}
   518  }
   519  `, randInt)
   520  }