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