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