diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 1f588a9..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ - -repos: -- repo: git://github.com/antonbabenko/pre-commit-terraform - rev: v1.7.3 - hooks: - - id: terraform_fmt -- repo: git://github.com/pre-commit/pre-commit-hooks - rev: v1.4.0 - hooks: - - id: check-merge-conflict \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 73ba818..484bb2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,18 @@ -dist: trusty -sudo: false +language: go -before_install: - - curl -fSL "https://releases.hashicorp.com/terraform/0.12.6/terraform_0.12.6_linux_amd64.zip" -o terraform.zip - - sudo unzip terraform.zip -d /opt/terraform - - sudo ln -s /opt/terraform/terraform /usr/bin/terraform - - rm -f terraform.zip - - curl -fSL https://github.com/wata727/tflint/releases/download/v0.7.0/tflint_linux_amd64.zip -o tflint.zip - - sudo unzip tflint.zip -d /opt/tflint - - sudo ln -s /opt/tflint/tflint /usr/bin/tflint - - rm -f tflint.zip +go: + - 1.12.x + +env: + - GO111MODULE=on notifications: email: false +install: + - curl -sL https://taskfile.dev/install.sh | sh + - curl -sL https://releases.hashicorp.com/terraform/0.12.7/terraform_0.12.7_linux_amd64.zip -o terraform.zip + - sudo unzip terraform.zip -d /usr/bin && rm -f terraform.zip + script: - - make + - ./bin/task test diff --git a/Makefile b/Makefile deleted file mode 100644 index 964e0fa..0000000 --- a/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -OS=darwin -DIR=$(shell pwd) - -default: test - -test: - @echo "== Test ==" - @if ! terraform fmt -recursive -write=false -check=true >> /dev/null; then \ - echo "✗ terraform fmt (Some files need to be formatted, run 'terraform fmt' to fix.)"; \ - exit 1; \ - else \ - echo "√ terraform fmt"; \ - fi - - @for d in $$(find . -type f -name '*.tf' -path "./modules/*" -not -path "**/.terraform/*" -exec dirname {} \; | sort -u); do \ - cd $$d; \ - terraform init -backend=false >> /dev/null; \ - terraform validate -check-variables=false; \ - if [ $$? -eq 1 ]; then \ - echo "✗ terraform validate failed: $$d"; \ - exit 1; \ - fi; \ - cd $(DIR); \ - done - @echo "√ terraform validate modules (not including variables)"; \ - - @for d in $$(find . -type f -name '*.tf' -path "./examples/*" -not -path "**/.terraform/*" -exec dirname {} \; | sort -u); do \ - cd $$d; \ - terraform init -backend=false >> /dev/null; \ - terraform validate; \ - if [ $$? -eq 1 ]; then \ - echo "✗ terraform validate failed: $$d"; \ - exit 1; \ - fi; \ - cd $(DIR); \ - done - @echo "√ terraform validate examples"; \ - -.PHONY: default test diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..31c099f --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,55 @@ +version: '2' + +env: + AWS_DEFAULT_REGION: eu-west-1 + GO111MODULE: on + +tasks: + default: + cmds: + - task: test + + test: + desc: Run tests for all terraform directories. + silent: true + env: + DIRECTORIES: + sh: find . -type f -name '*.tf' -not -path "**/.terraform/*" -exec dirname {} \; | sort -u + cmds: + - | + BOLD=$(tput bold) + NORM=$(tput sgr0) + + CWD=$PWD + + for d in $DIRECTORIES; do + cd $d + echo "${BOLD}$PWD:${NORM}" + + if ! terraform fmt -check=true -write=true -list=false -recursive=false; then + echo " ✗ terraform fmt" && exit $? + else + echo " √ terraform fmt" + fi + + if ! terraform init -backend=false -input=false -get=true -get-plugins=true -no-color > /dev/null; then + echo " ✗ terraform init" && exit $? + else + echo " √ terraform init" + fi + + if ! terraform validate > /dev/null; then + echo " ✗ terraform validate" && exit $? + else + echo " √ terraform validate" + fi + + cd $CWD + done + + e2e: + desc: Run the end 2 end test suite. + silent: true + cmds: + - go test -v ./... -timeout=1h + \ No newline at end of file diff --git a/examples/basic/README.md b/examples/basic/README.md new file mode 100644 index 0000000..1ff054e --- /dev/null +++ b/examples/basic/README.md @@ -0,0 +1,3 @@ +## examples/basic + +An example which shows _basic_ usage of the module. diff --git a/examples/default/example.tf b/examples/basic/main.tf similarity index 83% rename from examples/default/example.tf rename to examples/basic/main.tf index f4d799e..5a3499f 100644 --- a/examples/default/example.tf +++ b/examples/basic/main.tf @@ -1,13 +1,13 @@ # ---------------------------------------- # Create a ecs service using fargate # ---------------------------------------- - -provider "aws" { - region = "eu-west-1" +terraform { + required_version = ">= 0.12" } -resource "aws_ecs_cluster" "cluster" { - name = "example-ecs-cluster" +provider "aws" { + version = ">= 2.17" + region = var.region } data "aws_vpc" "main" { @@ -18,19 +18,20 @@ data "aws_subnet_ids" "main" { vpc_id = data.aws_vpc.main.id } + module "fargate_alb" { source = "telia-oss/loadbalancer/aws" version = "3.0.0" - name_prefix = "example-ecs-cluster" + name_prefix = var.name_prefix type = "application" - internal = "false" + internal = false vpc_id = data.aws_vpc.main.id subnet_ids = data.aws_subnet_ids.main.ids tags = { - environment = "test" - terraform = "true" + environment = "dev" + terraform = "True" } } @@ -64,12 +65,17 @@ resource "aws_security_group_rule" "alb_ingress_80" { ipv6_cidr_blocks = ["::/0"] } +resource "aws_ecs_cluster" "cluster" { + name = "${var.name_prefix}-cluster" +} + module "fargate" { source = "../../" - name_prefix = "example-app" + name_prefix = var.name_prefix vpc_id = data.aws_vpc.main.id private_subnet_ids = data.aws_subnet_ids.main.ids + lb_arn = module.fargate_alb.arn cluster_id = aws_ecs_cluster.cluster.id task_container_image = "crccheck/hello-world:latest" @@ -85,10 +91,8 @@ module "fargate" { } tags = { - environment = "test" - terraform = "true" + environment = "dev" + terraform = "True" } - - lb_arn = module.fargate_alb.arn } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf new file mode 100644 index 0000000..08b6235 --- /dev/null +++ b/examples/basic/outputs.tf @@ -0,0 +1,11 @@ +output "cluster_arn" { + value = aws_ecs_cluster.cluster.arn +} + +output "service_arn" { + value = module.fargate.service_arn +} + +output "endpoint" { + value = module.fargate_alb.dns_name +} diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf new file mode 100644 index 0000000..4e5c375 --- /dev/null +++ b/examples/basic/variables.tf @@ -0,0 +1,9 @@ +variable "name_prefix" { + type = string + default = "fargate-basic-example" +} + +variable "region" { + type = string + default = "eu-west-1" +} diff --git a/examples/default/README.md b/examples/default/README.md deleted file mode 100644 index 78e0508..0000000 --- a/examples/default/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## examples/default - -Basic example which creates an Fargate ECS cluster with a default listener and hello-world service (in the default VPC). diff --git a/examples/default/versions.tf b/examples/default/versions.tf deleted file mode 100644 index ac97c6a..0000000 --- a/examples/default/versions.tf +++ /dev/null @@ -1,4 +0,0 @@ - -terraform { - required_version = ">= 0.12" -} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6c07a63 --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module github.com/telia-oss/terraform-aws-ecs-fargate/v3 + +go 1.12 + +require ( + github.com/aws/aws-sdk-go v1.23.12 + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gruntwork-io/terratest v0.18.5 + github.com/kr/pretty v0.1.0 // indirect + github.com/magiconair/properties v1.8.1 // indirect + github.com/stretchr/testify v1.4.0 + golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect + golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect + golang.org/x/sys v0.0.0-20190830080133-08d80c9d36de // indirect + golang.org/x/text v0.3.2 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2ffe7fe --- /dev/null +++ b/go.sum @@ -0,0 +1,40 @@ +github.com/aws/aws-sdk-go v1.23.12 h1:2UnxgNO6Y5J1OrkXS8XNp0UatDxD1bWHiDT62RDPggI= +github.com/aws/aws-sdk-go v1.23.12/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gruntwork-io/terratest v0.18.5 h1:qgzApIXcFOH9RhXuu3ICR7WjjiLegdvBSzjux1Y1wVM= +github.com/gruntwork-io/terratest v0.18.5/go.mod h1:NjUn6YXA5Skxt8Rs20t3isYx5Rl+EgvGB8/+RRXddqk= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM= +golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190830080133-08d80c9d36de h1:MtIqW4Vp7DcnuoJTsTOgsa2R3jBQnCU0bjwXo7DcNT8= +golang.org/x/sys v0.0.0-20190830080133-08d80c9d36de/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.tf b/main.tf index 9517717..343036f 100644 --- a/main.tf +++ b/main.tf @@ -157,7 +157,6 @@ resource "aws_ecs_task_definition" "task" { "environment": ${jsonencode(data.null_data_source.task_environment.*.outputs)} }] EOF - } resource "aws_ecs_service" "service" { diff --git a/test/module.go b/test/module.go new file mode 100644 index 0000000..9357e92 --- /dev/null +++ b/test/module.go @@ -0,0 +1,214 @@ +package module + +import ( + "errors" + "io/ioutil" + "net/http" + "strconv" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/stretchr/testify/assert" +) + +type Expectations struct { + DesiredTaskCount int + TaskCPU int + TaskMemory int + ContainerImage string + NetworkMode string + GetResponse []string + Tags map[string]string +} + +func RunTestSuite(t *testing.T, clusterARN, serviceARN, endpoint, region string, expected Expectations) { + var ( + service *ecs.Service + taskDefinition *ecs.TaskDefinition + containerDefinition *ecs.ContainerDefinition + ) + sess := NewSession(t, region) + + service = DescribeService(t, sess, clusterARN, serviceARN) + assert.Equal(t, "ACTIVE", aws.StringValue(service.Status)) + assert.Equal(t, int64(expected.DesiredTaskCount), aws.Int64Value(service.DesiredCount)) + + taskDefinition = DescribeTaskDefinition(t, sess, aws.StringValue(service.TaskDefinition)) + assert.Equal(t, strconv.Itoa(expected.TaskCPU), aws.StringValue(taskDefinition.Cpu)) + assert.Equal(t, strconv.Itoa(expected.TaskMemory), aws.StringValue(taskDefinition.Memory)) + assert.Equal(t, expected.NetworkMode, aws.StringValue(taskDefinition.NetworkMode)) + + containerDefinition = GetContainerDefinition(t, taskDefinition) + assert.Equal(t, expected.ContainerImage, aws.StringValue(containerDefinition.Image)) + + WaitForRunningTasks(t, sess, clusterARN, serviceARN, 10*time.Second, 10*time.Minute) + WaitForTargetHealth(t, sess, service, expected.DesiredTaskCount, 10*time.Second, 10*time.Minute) + + response := HTTPGetRequest(t, endpoint) + for _, line := range expected.GetResponse { + assert.Contains(t, response, line) + } +} + +func NewSession(t *testing.T, region string) *session.Session { + sess, err := session.NewSession(&aws.Config{ + Region: aws.String(region), + }) + if err != nil { + t.Fatalf("failed to create new AWS session: %s", err) + } + return sess +} + +func DescribeService(t *testing.T, sess *session.Session, clusterARN, serviceARN string) *ecs.Service { + c := ecs.New(sess) + + out, err := c.DescribeServices(&ecs.DescribeServicesInput{ + Cluster: aws.String(clusterARN), + Services: []*string{aws.String(serviceARN)}, + }) + if err != nil { + t.Fatalf("failed to describe service: %s", err) + } + if n := len(out.Services); n != 1 { + t.Fatalf("found wrong number (%d) of matches for service: %s", n, serviceARN) + } + var service *ecs.Service + for _, s := range out.Services { + if arn := aws.StringValue(s.ServiceArn); arn != serviceARN { + t.Fatalf("wrong service arn: %s", arn) + } + service = s + } + return service +} + +func GetServiceTags(service *ecs.Service) map[string]string { + tags := make(map[string]string) + for _, t := range service.Tags { + tags[aws.StringValue(t.Key)] = aws.StringValue(t.Value) + } + return tags +} + +func DescribeTaskDefinition(t *testing.T, sess *session.Session, taskDefinitionARN string) *ecs.TaskDefinition { + c := ecs.New(sess) + + out, err := c.DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{ + TaskDefinition: aws.String(taskDefinitionARN), + }) + if err != nil { + t.Fatalf("failed to describe task definition: %s", err) + } + return out.TaskDefinition +} + +func GetContainerDefinition(t *testing.T, taskDefinition *ecs.TaskDefinition) *ecs.ContainerDefinition { + if n := len(taskDefinition.ContainerDefinitions); n != 1 { + t.Fatalf("task has wrong number of container definitions: %d", n) + } + return taskDefinition.ContainerDefinitions[0] +} + +func WaitForRunningTasks(t *testing.T, sess *session.Session, clusterARN, serviceARN string, checkInterval time.Duration, timeoutLimit time.Duration) { + interval := time.NewTicker(checkInterval) + defer interval.Stop() + + timeout := time.NewTimer(timeoutLimit) + defer timeout.Stop() + +WaitLoop: + for { + select { + case <-interval.C: + service := DescribeService(t, sess, clusterARN, serviceARN) + if aws.Int64Value(service.DesiredCount) == aws.Int64Value(service.RunningCount) { + break WaitLoop + } + t.Log("waiting for running tasks...") + case <-timeout.C: + t.Fatal("timeout reached while waiting for the desired number of running tasks") + } + } +} + +func waitForTargetHealthE(t *testing.T, sess *session.Session, targetARN string, desiredHealthCount int, checkInterval time.Duration, timeoutLimit time.Duration) error { + interval := time.NewTicker(checkInterval) + defer interval.Stop() + + timeout := time.NewTimer(timeoutLimit) + defer timeout.Stop() + + c := elbv2.New(sess) + + for { + select { + case <-interval.C: + health, err := c.DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{ + TargetGroupArn: aws.String(targetARN), + }) + if err != nil { + return err + } + + healthyTargets := 0 + for _, target := range health.TargetHealthDescriptions { + switch aws.StringValue(target.TargetHealth.State) { + case elbv2.TargetHealthStateEnumUnused: + t.Logf("health checks are disabled for target group: %s", targetARN) + return nil + case elbv2.TargetHealthStateEnumHealthy: + healthyTargets++ + default: + } + } + + if healthyTargets == desiredHealthCount { + return nil + } + t.Logf("waiting for health checks (%d/%d)...", healthyTargets, desiredHealthCount) + case <-timeout.C: + return errors.New("timeout reached while waiting for the desired health count") + } + } +} + +func WaitForTargetHealth(t *testing.T, sess *session.Session, service *ecs.Service, desiredTaskCount int, checkInterval time.Duration, timeoutLimit time.Duration) { + n := len(service.LoadBalancers) + errs := make(chan error, n) + + for _, lb := range service.LoadBalancers { + go func() { + errs <- waitForTargetHealthE(t, sess, aws.StringValue(lb.TargetGroupArn), desiredTaskCount, checkInterval, timeoutLimit) + }() + } + + for i := 1; i <= n; i++ { + err := <-errs + if err != nil { + t.Error(err) + } + } +} + +func HTTPGetRequest(t *testing.T, endpoint string) string { + r, err := http.Get(endpoint) + if err != nil { + t.Fatalf("get-request error: %s", err) + } + defer r.Body.Close() + + if r.StatusCode != http.StatusOK { + t.Errorf("got non-200 response: %d", r.StatusCode) + } + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("failed to read response body: %s", err) + } + return string(body) +} diff --git a/test/module_test.go b/test/module_test.go new file mode 100644 index 0000000..e9c9897 --- /dev/null +++ b/test/module_test.go @@ -0,0 +1,70 @@ +package module_test + +import ( + "fmt" + "testing" + + ecs "github.com/telia-oss/terraform-aws-ecs-fargate/v3/test" + + "github.com/gruntwork-io/terratest/modules/random" + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func TestModule(t *testing.T) { + tests := []struct { + description string + directory string + name string + region string + expected ecs.Expectations + }{ + { + description: "basic example", + directory: "../examples/basic", + name: fmt.Sprintf("fargate-basic-test-%s", random.UniqueId()), + region: "eu-west-1", + expected: ecs.Expectations{ + DesiredTaskCount: 1, + TaskCPU: 256, + TaskMemory: 512, + ContainerImage: "crccheck/hello-world:latest", + NetworkMode: "awsvpc", + GetResponse: []string{ + `Hello World`, + `~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~`, + `\______ o _,/`, + }, + }, + }, + } + + for _, tc := range tests { + tc := tc // Source: https://gist.github.com/posener/92a55c4cd441fc5e5e85f27bca008721 + t.Run(tc.description, func(t *testing.T) { + t.Parallel() + options := &terraform.Options{ + TerraformDir: tc.directory, + + Vars: map[string]interface{}{ + "name_prefix": tc.name, + "region": tc.region, + }, + + EnvVars: map[string]string{ + "AWS_DEFAULT_REGION": tc.region, + }, + } + + defer terraform.Destroy(t, options) + terraform.InitAndApply(t, options) + + ecs.RunTestSuite(t, + terraform.Output(t, options, "cluster_arn"), + terraform.Output(t, options, "service_arn"), + fmt.Sprintf("http://%s", terraform.Output(t, options, "endpoint")), + tc.region, + tc.expected, + ) + }) + } +}