diff --git a/.gitignore b/.gitignore index 4fa2920dd..f3bc35109 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .terraform -terraform.tfstate *.tfstate* +.kitchen +terraform.tfstate terraform.tfvars +Gemfile.lock diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 000000000..beb517ea9 --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,20 @@ +--- +driver: + name: "terraform" + root_module_directory: "examples/test_fixture" + +provisioner: + name: "terraform" + +platforms: + - name: "aws" + +verifier: + name: "awspec" + +suites: + - name: "default" + verifier: + name: "awspec" + patterns: + - "test/integration/default/test_vpc.rb" diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000..8e8299dcc --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.4.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..f1de0394e --- /dev/null +++ b/Gemfile @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +ruby '2.4.2' + +source 'https://rubygems.org/' do + gem 'aws-sdk', '~> 3.0.1' + gem 'awspec', '~> 1.4.0' + gem 'kitchen-terraform', '~> 3.1' + gem 'kitchen-verifier-awspec', '~> 0.1.1' + gem 'rhcl', '~> 0.1.0' +end diff --git a/README.md b/README.md index 50e2eb432..fb58fe5fe 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,20 @@ Examples * [Complete VPC](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/complete-vpc) * Few tests and edge cases examples: [#46](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/issue-46-no-private-subnets), [#44](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/issue-44-asymmetric-private-subnets) + +Tests +------- + +This module has been packaged with [awspec](https://github.com/k1LoW/awspec) tests through test kitchen. To run them: + +1. Install [rvm](https://rvm.io/rvm/install) and the ruby version specified in the [Gemfile](https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/Gemfile). +2. Install bundler and the gems from our Gemfile: +``` +gem install bundler; bundle install +``` +3. Test using `bundle exec kitchen test` from the root of the repo. + + Authors ------- diff --git a/examples/test_fixture/README.md b/examples/test_fixture/README.md new file mode 100644 index 000000000..b0b7231dd --- /dev/null +++ b/examples/test_fixture/README.md @@ -0,0 +1,21 @@ +# Test fixture of simple VPC + +Configuration in this directory creates a set of VPC resources to be tested by test kitchen. + +There is a public and private subnet created per availability zone in addition to single NAT Gateway shared between 2 availability zones. + +## Usage + +To run the tests, from the repo root execute: + +```bash +$ kitchen test +... +Finished in 4.25 seconds (files took 2.75 seconds to load) +20 examples, 0 failures + + Finished verifying (0m9.03s). +-----> Kitchen is finished. (0m9.40s) +``` + +This will destroy any existing test resources, create the resources afresh, run the tests, report back, and destroy the resources. diff --git a/examples/test_fixture/main.tf b/examples/test_fixture/main.tf new file mode 100644 index 000000000..b0eb37ea0 --- /dev/null +++ b/examples/test_fixture/main.tf @@ -0,0 +1,21 @@ +provider "aws" { + region = "${var.region}" +} + +data "aws_availability_zones" "available" {} + +module "vpc" { + source = "../.." + name = "test-example" + cidr = "10.0.0.0/16" + azs = ["${data.aws_availability_zones.available.names[0]}", "${data.aws_availability_zones.available.names[1]}"] + private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] + public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] + enable_nat_gateway = true + single_nat_gateway = true + + tags = { + Owner = "user" + Environment = "dev" + } +} diff --git a/examples/test_fixture/outputs.tf b/examples/test_fixture/outputs.tf new file mode 100644 index 000000000..4c89ae958 --- /dev/null +++ b/examples/test_fixture/outputs.tf @@ -0,0 +1,4 @@ +output "region" { + description = "Region we created the resources in." + value = "${var.region}" +} diff --git a/examples/test_fixture/variables.tf b/examples/test_fixture/variables.tf new file mode 100644 index 000000000..a3986dc92 --- /dev/null +++ b/examples/test_fixture/variables.tf @@ -0,0 +1,3 @@ +variable "region" { + default = "eu-west-1" +} diff --git a/test/integration/default/test_vpc.rb b/test/integration/default/test_vpc.rb new file mode 100755 index 000000000..7a74a4518 --- /dev/null +++ b/test/integration/default/test_vpc.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'awspec' +require 'aws-sdk' +require 'rhcl' + +# should strive to randomize the region for more robust testing +example_main = Rhcl.parse(File.open('examples/test_fixture/main.tf')) +vpc_name = example_main['module']['vpc']['name'] +user_tag = example_main['module']['vpc']['tags']['Owner'] +environment_tag = example_main['module']['vpc']['tags']['Environment'] +state_file = 'terraform.tfstate.d/kitchen-terraform-default-aws/terraform.tfstate' +tf_state = JSON.parse(File.open(state_file).read) +region = tf_state['modules'][0]['outputs']['region']['value'] +ENV['AWS_REGION'] = region + +ec2 = Aws::EC2::Client.new(region: region) +azs = ec2.describe_availability_zones +zone_names = azs.to_h[:availability_zones].first(2).map { |az| az[:zone_name] } + +describe vpc(vpc_name.to_s) do + it { should exist } + it { should be_available } + it { should have_tag('Name').value(vpc_name.to_s) } + it { should have_tag('Owner').value(user_tag.to_s) } + it { should have_tag('Environment').value(environment_tag.to_s) } + it { should have_route_table("#{vpc_name}-public") } + zone_names.each do |az| + it { should have_route_table("#{vpc_name}-private-#{az}") } + end +end + +zone_names.each do |az| + describe subnet("#{vpc_name}-public-#{az}") do + it { should exist } + it { should be_available } + it { should belong_to_vpc(vpc_name.to_s) } + it { should have_tag('Name').value("#{vpc_name}-public-#{az}") } + it { should have_tag('Owner').value(user_tag.to_s) } + it { should have_tag('Environment').value(environment_tag.to_s) } + end +end