github.com/ottenhoff/terraform@v0.7.0-rc1.0.20160607213102-ac2d195cc560/builtin/providers/aws/resource_aws_lambda_function_test.go (about)

     1  package aws
     2  
     3  import (
     4  	"archive/zip"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"regexp"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/aws/aws-sdk-go/aws"
    14  	"github.com/aws/aws-sdk-go/service/lambda"
    15  	"github.com/hashicorp/terraform/helper/acctest"
    16  	"github.com/hashicorp/terraform/helper/resource"
    17  	"github.com/hashicorp/terraform/terraform"
    18  )
    19  
    20  func TestAccAWSLambdaFunction_basic(t *testing.T) {
    21  	var conf lambda.GetFunctionOutput
    22  
    23  	rName := fmt.Sprintf("tf_test_%s", acctest.RandString(5))
    24  
    25  	resource.Test(t, resource.TestCase{
    26  		PreCheck:     func() { testAccPreCheck(t) },
    27  		Providers:    testAccProviders,
    28  		CheckDestroy: testAccCheckLambdaFunctionDestroy,
    29  		Steps: []resource.TestStep{
    30  			resource.TestStep{
    31  				Config: testAccAWSLambdaConfigBasic(rName),
    32  				Check: resource.ComposeTestCheckFunc(
    33  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", rName, &conf),
    34  					testAccCheckAwsLambdaFunctionName(&conf, rName),
    35  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+rName),
    36  				),
    37  			},
    38  		},
    39  	})
    40  }
    41  
    42  func TestAccAWSLambdaFunction_VPC(t *testing.T) {
    43  	var conf lambda.GetFunctionOutput
    44  	rName := fmt.Sprintf("tf_test_%s", acctest.RandString(5))
    45  
    46  	resource.Test(t, resource.TestCase{
    47  		PreCheck:     func() { testAccPreCheck(t) },
    48  		Providers:    testAccProviders,
    49  		CheckDestroy: testAccCheckLambdaFunctionDestroy,
    50  		Steps: []resource.TestStep{
    51  			resource.TestStep{
    52  				Config: testAccAWSLambdaConfigWithVPC(rName),
    53  				Check: resource.ComposeTestCheckFunc(
    54  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_test", rName, &conf),
    55  					testAccCheckAwsLambdaFunctionName(&conf, rName),
    56  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+rName),
    57  					testAccCheckAWSLambdaFunctionVersion(&conf, "$LATEST"),
    58  					resource.TestCheckResourceAttr("aws_lambda_function.lambda_function_test", "vpc_config.#", "1"),
    59  					resource.TestCheckResourceAttr("aws_lambda_function.lambda_function_test", "vpc_config.0.subnet_ids.#", "1"),
    60  					resource.TestCheckResourceAttr("aws_lambda_function.lambda_function_test", "vpc_config.0.security_group_ids.#", "1"),
    61  					resource.TestMatchResourceAttr("aws_lambda_function.lambda_function_test", "vpc_config.0.vpc_id", regexp.MustCompile("^vpc-")),
    62  				),
    63  			},
    64  		},
    65  	})
    66  }
    67  
    68  func TestAccAWSLambdaFunction_s3(t *testing.T) {
    69  	var conf lambda.GetFunctionOutput
    70  	rName := fmt.Sprintf("tf_test_%s", acctest.RandString(5))
    71  
    72  	resource.Test(t, resource.TestCase{
    73  		PreCheck:     func() { testAccPreCheck(t) },
    74  		Providers:    testAccProviders,
    75  		CheckDestroy: testAccCheckLambdaFunctionDestroy,
    76  		Steps: []resource.TestStep{
    77  			resource.TestStep{
    78  				Config: testAccAWSLambdaConfigS3(rName),
    79  				Check: resource.ComposeTestCheckFunc(
    80  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_s3test", rName, &conf),
    81  					testAccCheckAwsLambdaFunctionName(&conf, rName),
    82  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, ":"+rName),
    83  					testAccCheckAWSLambdaFunctionVersion(&conf, "$LATEST"),
    84  				),
    85  			},
    86  		},
    87  	})
    88  }
    89  
    90  func TestAccAWSLambdaFunction_localUpdate(t *testing.T) {
    91  	var conf lambda.GetFunctionOutput
    92  
    93  	path, zipFile, err := createTempFile("lambda_localUpdate")
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	defer os.Remove(path)
    98  
    99  	resource.Test(t, resource.TestCase{
   100  		PreCheck:     func() { testAccPreCheck(t) },
   101  		Providers:    testAccProviders,
   102  		CheckDestroy: testAccCheckLambdaFunctionDestroy,
   103  		Steps: []resource.TestStep{
   104  			resource.TestStep{
   105  				PreConfig: func() {
   106  					testAccCreateZipFromFiles(map[string]string{"test-fixtures/lambda_func.js": "lambda.js"}, zipFile)
   107  				},
   108  				Config: genAWSLambdaFunctionConfig_local(path),
   109  				Check: resource.ComposeTestCheckFunc(
   110  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_local", "tf_acc_lambda_name_local", &conf),
   111  					testAccCheckAwsLambdaFunctionName(&conf, "tf_acc_lambda_name_local"),
   112  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, "tf_acc_lambda_name_local"),
   113  					testAccCheckAwsLambdaSourceCodeHash(&conf, "un6qF9S9hKvXbWwJ6m2EYaVCWjcr0PCZWiTV3h4zB0I="),
   114  				),
   115  			},
   116  			resource.TestStep{
   117  				PreConfig: func() {
   118  					testAccCreateZipFromFiles(map[string]string{"test-fixtures/lambda_func_modified.js": "lambda.js"}, zipFile)
   119  				},
   120  				Config: genAWSLambdaFunctionConfig_local(path),
   121  				Check: resource.ComposeTestCheckFunc(
   122  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_local", "tf_acc_lambda_name_local", &conf),
   123  					testAccCheckAwsLambdaFunctionName(&conf, "tf_acc_lambda_name_local"),
   124  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, "tf_acc_lambda_name_local"),
   125  					testAccCheckAwsLambdaSourceCodeHash(&conf, "Y5Jf4Si63UDy1wKNfPs+U56ZL0NxsieKPt9EwRl4GQM="),
   126  				),
   127  			},
   128  		},
   129  	})
   130  }
   131  
   132  func TestAccAWSLambdaFunction_s3Update(t *testing.T) {
   133  	var conf lambda.GetFunctionOutput
   134  
   135  	path, zipFile, err := createTempFile("lambda_s3Update")
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  	defer os.Remove(path)
   140  
   141  	bucketName := fmt.Sprintf("tf-acc-lambda-s3-deployments-%d", randomInteger)
   142  	key := "lambda-func.zip"
   143  
   144  	resource.Test(t, resource.TestCase{
   145  		PreCheck:     func() { testAccPreCheck(t) },
   146  		Providers:    testAccProviders,
   147  		CheckDestroy: testAccCheckLambdaFunctionDestroy,
   148  		Steps: []resource.TestStep{
   149  			resource.TestStep{
   150  				PreConfig: func() {
   151  					// Upload 1st version
   152  					testAccCreateZipFromFiles(map[string]string{"test-fixtures/lambda_func.js": "lambda.js"}, zipFile)
   153  				},
   154  				Config: genAWSLambdaFunctionConfig_s3(bucketName, key, path),
   155  				Check: resource.ComposeTestCheckFunc(
   156  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_s3", "tf_acc_lambda_name_s3", &conf),
   157  					testAccCheckAwsLambdaFunctionName(&conf, "tf_acc_lambda_name_s3"),
   158  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, "tf_acc_lambda_name_s3"),
   159  					testAccCheckAwsLambdaSourceCodeHash(&conf, "un6qF9S9hKvXbWwJ6m2EYaVCWjcr0PCZWiTV3h4zB0I="),
   160  				),
   161  			},
   162  			resource.TestStep{
   163  				ExpectNonEmptyPlan: true,
   164  				PreConfig: func() {
   165  					// Upload 2nd version
   166  					testAccCreateZipFromFiles(map[string]string{"test-fixtures/lambda_func_modified.js": "lambda.js"}, zipFile)
   167  				},
   168  				Config: genAWSLambdaFunctionConfig_s3(bucketName, key, path),
   169  			},
   170  			// Extra step because of missing ComputedWhen
   171  			// See https://github.com/hashicorp/terraform/pull/4846 & https://github.com/hashicorp/terraform/pull/5330
   172  			resource.TestStep{
   173  				Config: genAWSLambdaFunctionConfig_s3(bucketName, key, path),
   174  				Check: resource.ComposeTestCheckFunc(
   175  					testAccCheckAwsLambdaFunctionExists("aws_lambda_function.lambda_function_s3", "tf_acc_lambda_name_s3", &conf),
   176  					testAccCheckAwsLambdaFunctionName(&conf, "tf_acc_lambda_name_s3"),
   177  					testAccCheckAwsLambdaFunctionArnHasSuffix(&conf, "tf_acc_lambda_name_s3"),
   178  					testAccCheckAwsLambdaSourceCodeHash(&conf, "Y5Jf4Si63UDy1wKNfPs+U56ZL0NxsieKPt9EwRl4GQM="),
   179  				),
   180  			},
   181  		},
   182  	})
   183  }
   184  
   185  func testAccCheckLambdaFunctionDestroy(s *terraform.State) error {
   186  	conn := testAccProvider.Meta().(*AWSClient).lambdaconn
   187  
   188  	for _, rs := range s.RootModule().Resources {
   189  		if rs.Type != "aws_lambda_function" {
   190  			continue
   191  		}
   192  
   193  		_, err := conn.GetFunction(&lambda.GetFunctionInput{
   194  			FunctionName: aws.String(rs.Primary.ID),
   195  		})
   196  
   197  		if err == nil {
   198  			return fmt.Errorf("Lambda Function still exists")
   199  		}
   200  
   201  	}
   202  
   203  	return nil
   204  
   205  }
   206  
   207  func testAccCheckAwsLambdaFunctionExists(res, funcName string, function *lambda.GetFunctionOutput) resource.TestCheckFunc {
   208  	// Wait for IAM role
   209  	return func(s *terraform.State) error {
   210  		rs, ok := s.RootModule().Resources[res]
   211  		if !ok {
   212  			return fmt.Errorf("Lambda function not found: %s", res)
   213  		}
   214  
   215  		if rs.Primary.ID == "" {
   216  			return fmt.Errorf("Lambda function ID not set")
   217  		}
   218  
   219  		conn := testAccProvider.Meta().(*AWSClient).lambdaconn
   220  
   221  		params := &lambda.GetFunctionInput{
   222  			FunctionName: aws.String(funcName),
   223  		}
   224  
   225  		getFunction, err := conn.GetFunction(params)
   226  		if err != nil {
   227  			return err
   228  		}
   229  
   230  		*function = *getFunction
   231  
   232  		return nil
   233  	}
   234  }
   235  
   236  func testAccCheckAwsLambdaFunctionName(function *lambda.GetFunctionOutput, expectedName string) resource.TestCheckFunc {
   237  	return func(s *terraform.State) error {
   238  		c := function.Configuration
   239  		if *c.FunctionName != expectedName {
   240  			return fmt.Errorf("Expected function name %s, got %s", expectedName, *c.FunctionName)
   241  		}
   242  
   243  		return nil
   244  	}
   245  }
   246  
   247  func testAccCheckAWSLambdaFunctionVersion(function *lambda.GetFunctionOutput, expectedVersion string) resource.TestCheckFunc {
   248  	return func(s *terraform.State) error {
   249  		c := function.Configuration
   250  		if *c.Version != expectedVersion {
   251  			return fmt.Errorf("Expected version %s, got %s", expectedVersion, *c.Version)
   252  		}
   253  		return nil
   254  	}
   255  }
   256  
   257  func testAccCheckAwsLambdaFunctionArnHasSuffix(function *lambda.GetFunctionOutput, arnSuffix string) resource.TestCheckFunc {
   258  	return func(s *terraform.State) error {
   259  		c := function.Configuration
   260  		if !strings.HasSuffix(*c.FunctionArn, arnSuffix) {
   261  			return fmt.Errorf("Expected function ARN %s to have suffix %s", *c.FunctionArn, arnSuffix)
   262  		}
   263  
   264  		return nil
   265  	}
   266  }
   267  
   268  func testAccCheckAwsLambdaSourceCodeHash(function *lambda.GetFunctionOutput, expectedHash string) resource.TestCheckFunc {
   269  	return func(s *terraform.State) error {
   270  		c := function.Configuration
   271  		if *c.CodeSha256 != expectedHash {
   272  			return fmt.Errorf("Expected code hash %s, got %s", expectedHash, *c.CodeSha256)
   273  		}
   274  
   275  		return nil
   276  	}
   277  }
   278  
   279  func testAccCreateZipFromFiles(files map[string]string, zipFile *os.File) error {
   280  	zipFile.Truncate(0)
   281  	zipFile.Seek(0, 0)
   282  
   283  	w := zip.NewWriter(zipFile)
   284  
   285  	for source, destination := range files {
   286  		f, err := w.Create(destination)
   287  		if err != nil {
   288  			return err
   289  		}
   290  
   291  		fileContent, err := ioutil.ReadFile(source)
   292  		if err != nil {
   293  			return err
   294  		}
   295  
   296  		_, err = f.Write(fileContent)
   297  		if err != nil {
   298  			return err
   299  		}
   300  	}
   301  
   302  	err := w.Close()
   303  	if err != nil {
   304  		return err
   305  	}
   306  
   307  	return w.Flush()
   308  }
   309  
   310  func createTempFile(prefix string) (string, *os.File, error) {
   311  	f, err := ioutil.TempFile(os.TempDir(), prefix)
   312  	if err != nil {
   313  		return "", nil, err
   314  	}
   315  
   316  	pathToFile, err := filepath.Abs(f.Name())
   317  	if err != nil {
   318  		return "", nil, err
   319  	}
   320  	return pathToFile, f, nil
   321  }
   322  
   323  const baseAccAWSLambdaConfig = `
   324  resource "aws_iam_role_policy" "iam_policy_for_lambda" {
   325      name = "iam_policy_for_lambda"
   326      role = "${aws_iam_role.iam_for_lambda.id}"
   327      policy = <<EOF
   328  {
   329    "Version": "2012-10-17",
   330    "Statement": [
   331          {
   332              "Effect": "Allow",
   333              "Action": [
   334                  "logs:CreateLogGroup",
   335                  "logs:CreateLogStream",
   336                  "logs:PutLogEvents"
   337              ],
   338              "Resource": "arn:aws:logs:*:*:*"
   339          },
   340      {
   341        "Effect": "Allow",
   342        "Action": [
   343          "ec2:CreateNetworkInterface"
   344        ],
   345        "Resource": [
   346          "*"
   347        ]
   348      }
   349    ]
   350  }
   351  EOF
   352  }
   353  
   354  resource "aws_iam_role" "iam_for_lambda" {
   355      name = "iam_for_lambda"
   356      assume_role_policy = <<EOF
   357  {
   358    "Version": "2012-10-17",
   359    "Statement": [
   360      {
   361        "Action": "sts:AssumeRole",
   362        "Principal": {
   363          "Service": "lambda.amazonaws.com"
   364        },
   365        "Effect": "Allow",
   366        "Sid": ""
   367      }
   368    ]
   369  }
   370  EOF
   371  }
   372  
   373  resource "aws_vpc" "vpc_for_lambda" {
   374      cidr_block = "10.0.0.0/16"
   375  }
   376  
   377  resource "aws_subnet" "subnet_for_lambda" {
   378      vpc_id = "${aws_vpc.vpc_for_lambda.id}"
   379      cidr_block = "10.0.1.0/24"
   380  
   381      tags {
   382          Name = "lambda"
   383      }
   384  }
   385  
   386  resource "aws_security_group" "sg_for_lambda" {
   387    name = "sg_for_lambda"
   388    description = "Allow all inbound traffic for lambda test"
   389    vpc_id = "${aws_vpc.vpc_for_lambda.id}"
   390  
   391    ingress {
   392        from_port = 0
   393        to_port = 0
   394        protocol = "-1"
   395        cidr_blocks = ["0.0.0.0/0"]
   396    }
   397  
   398    egress {
   399        from_port = 0
   400        to_port = 0
   401        protocol = "-1"
   402        cidr_blocks = ["0.0.0.0/0"]
   403    }
   404  }
   405  
   406  `
   407  
   408  func testAccAWSLambdaConfigBasic(rName string) string {
   409  	return fmt.Sprintf(baseAccAWSLambdaConfig+`
   410  resource "aws_lambda_function" "lambda_function_test" {
   411      filename = "test-fixtures/lambdatest.zip"
   412      function_name = "%s"
   413      role = "${aws_iam_role.iam_for_lambda.arn}"
   414      handler = "exports.example"
   415  }
   416  `, rName)
   417  }
   418  
   419  func testAccAWSLambdaConfigWithVPC(rName string) string {
   420  	return fmt.Sprintf(baseAccAWSLambdaConfig+`
   421  resource "aws_lambda_function" "lambda_function_test" {
   422      filename = "test-fixtures/lambdatest.zip"
   423      function_name = "%s"
   424      role = "${aws_iam_role.iam_for_lambda.arn}"
   425      handler = "exports.example"
   426  
   427      vpc_config = {
   428          subnet_ids = ["${aws_subnet.subnet_for_lambda.id}"]
   429          security_group_ids = ["${aws_security_group.sg_for_lambda.id}"]
   430      }
   431  }`, rName)
   432  }
   433  
   434  func testAccAWSLambdaConfigS3(rName string) string {
   435  	return fmt.Sprintf(`
   436  resource "aws_s3_bucket" "lambda_bucket" {
   437    bucket = "tf-test-bucket-%d"
   438  }
   439  
   440  resource "aws_s3_bucket_object" "lambda_code" {
   441    bucket = "${aws_s3_bucket.lambda_bucket.id}"
   442    key = "lambdatest.zip"
   443    source = "test-fixtures/lambdatest.zip"
   444  }
   445  
   446  resource "aws_iam_role" "iam_for_lambda" {
   447      name = "iam_for_lambda"
   448      assume_role_policy = <<EOF
   449  {
   450    "Version": "2012-10-17",
   451    "Statement": [
   452      {
   453        "Action": "sts:AssumeRole",
   454        "Principal": {
   455          "Service": "lambda.amazonaws.com"
   456        },
   457        "Effect": "Allow",
   458        "Sid": ""
   459      }
   460    ]
   461  }
   462  EOF
   463  }
   464  
   465  resource "aws_lambda_function" "lambda_function_s3test" {
   466      s3_bucket = "${aws_s3_bucket.lambda_bucket.id}"
   467      s3_key = "${aws_s3_bucket_object.lambda_code.id}"
   468      function_name = "%s"
   469      role = "${aws_iam_role.iam_for_lambda.arn}"
   470      handler = "exports.example"
   471  }
   472  `, acctest.RandInt(), rName)
   473  }
   474  
   475  const testAccAWSLambdaFunctionConfig_local_tpl = `
   476  resource "aws_iam_role" "iam_for_lambda" {
   477      name = "iam_for_lambda"
   478      assume_role_policy = <<EOF
   479  {
   480    "Version": "2012-10-17",
   481    "Statement": [
   482      {
   483        "Action": "sts:AssumeRole",
   484        "Principal": {
   485          "Service": "lambda.amazonaws.com"
   486        },
   487        "Effect": "Allow",
   488        "Sid": ""
   489      }
   490    ]
   491  }
   492  EOF
   493  }
   494  resource "aws_lambda_function" "lambda_function_local" {
   495      filename = "%s"
   496      source_code_hash = "${base64sha256(file("%s"))}"
   497      function_name = "tf_acc_lambda_name_local"
   498      role = "${aws_iam_role.iam_for_lambda.arn}"
   499      handler = "exports.example"
   500  }
   501  `
   502  
   503  func genAWSLambdaFunctionConfig_local(filePath string) string {
   504  	return fmt.Sprintf(testAccAWSLambdaFunctionConfig_local_tpl,
   505  		filePath, filePath)
   506  }
   507  
   508  const testAccAWSLambdaFunctionConfig_s3_tpl = `
   509  resource "aws_s3_bucket" "artifacts" {
   510  	bucket = "%s"
   511  	acl = "private"
   512  	force_destroy = true
   513  	versioning {
   514  		enabled = true
   515  	}
   516  }
   517  resource "aws_s3_bucket_object" "o" {
   518  	bucket = "${aws_s3_bucket.artifacts.bucket}"
   519  	key = "%s"
   520  	source = "%s"
   521  	etag = "${md5(file("%s"))}"
   522  }
   523  resource "aws_iam_role" "iam_for_lambda" {
   524      name = "iam_for_lambda"
   525      assume_role_policy = <<EOF
   526  {
   527    "Version": "2012-10-17",
   528    "Statement": [
   529      {
   530        "Action": "sts:AssumeRole",
   531        "Principal": {
   532          "Service": "lambda.amazonaws.com"
   533        },
   534        "Effect": "Allow",
   535        "Sid": ""
   536      }
   537    ]
   538  }
   539  EOF
   540  }
   541  resource "aws_lambda_function" "lambda_function_s3" {
   542  	s3_bucket = "${aws_s3_bucket_object.o.bucket}"
   543  	s3_key = "${aws_s3_bucket_object.o.key}"
   544  	s3_object_version = "${aws_s3_bucket_object.o.version_id}"
   545      function_name = "tf_acc_lambda_name_s3"
   546      role = "${aws_iam_role.iam_for_lambda.arn}"
   547      handler = "exports.example"
   548  }
   549  `
   550  
   551  func genAWSLambdaFunctionConfig_s3(bucket, key, path string) string {
   552  	return fmt.Sprintf(testAccAWSLambdaFunctionConfig_s3_tpl,
   553  		bucket, key, path, path)
   554  }