Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module tests #48

Merged
merged 14 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
path: ["cg_space", "clamav", "database", "domain", "redis", "s3"]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: terraform validate ${{ matrix.path }}
uses: dflook/terraform-validate@v1
Expand All @@ -31,7 +31,7 @@ jobs:
path: ["cg_space", "clamav", "database", "domain", "redis", "s3"]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: terraform fmt ${{ matrix.path }}
uses: dflook/terraform-fmt-check@v1
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Terraform Test

on:
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest
name: Integration test
strategy:
fail-fast: false
max-parallel: 2
matrix:
module: ["s3", "database", "redis", "cg_space", "domain", "clamav"]
steps:
- uses: actions/checkout@v4

- name: terraform test ${{ matrix.module }}
uses: dflook/terraform-test@v1
env:
CF_USER: ${{ secrets.CF_USER }}
CF_PASSWORD: ${{ secrets.CF_PASSWORD }}
with:
path: ${{ matrix.module }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Local .terraform directories
**/.terraform/*
**/.terraform.lock.hcl

# .tfstate files
*.tfstate
Expand Down
1 change: 1 addition & 0 deletions .terraform-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.8.5
rahearn marked this conversation as resolved.
Show resolved Hide resolved
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ Creates a new cloud.gov space, such as when creating an egress space, and output

`managers`, `developers`, and `deployers` are all optional, but you probably want to set at least one of them, depending on your use case.

* `managers` are granted the [Space Manager](https://docs.cloudfoundry.org/concepts/roles.html#activeroles) role
* `developers` are granted the [Space Developer](https://docs.cloudfoundry.org/concepts/roles.html#activeroles) role
* `deployers` are granted both manager and developer roles

```
module "egress_space" {
source = "github.com/18f/terraform-cloudgov//cg_space?ref=v1.0.0"
Expand All @@ -140,3 +144,18 @@ module "egress_space" {
]
}
```

## Testing


> **Warning**
Tests provision resources in the real world when not using `mock_provider`! Take care that `CF_USER`/`CF_PASSWORD` are set to an account in a suitable non-production space. If other providers, such as the AWS provider, are used, ensure the same care is taken with their credentials in your shell before running `terraform test`.

[Terraform tests](https://developer.hashicorp.com/terraform/language/tests) are in progress of being written. To run for any module with a `tests` directory:
rahearn marked this conversation as resolved.
Show resolved Hide resolved

1. Set `CF_USER` and `CF_PASSWORD` env variables with SpaceDeployer credentials that can access the space(s) being used for tests
1. cd to module root. Example: `cd s3`
1. Run `terraform init`
1. Run `terraform test`

When updating code, try to cover every input and output variable with at least one test to verify it is connected properly.
87 changes: 87 additions & 0 deletions cg_space/tests/creation.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
mock_provider "cloudfoundry" {
override_data {
target = data.cloudfoundry_user.managers["user.manager@gsa.gov"]
values = {
id = "1e5143a4-aa47-483c-8352-557988d5cc7a"
}
}
override_data {
target = data.cloudfoundry_user.deployers["user.manager@gsa.gov"]
values = {
id = "1e5143a4-aa47-483c-8352-557988d5cc7a"
}
}
override_data {
target = data.cloudfoundry_user.developers["user.developer@gsa.gov"]
values = {
id = "2c945842-13ee-4383-84ad-34ecbcde5ce6"
}
}
}

variables {
cf_org_name = "gsa-tts-devtools-prototyping"
cf_space_name = "terraform-cloudgov-ci-tests-egress"
}

run "test_space_creation" {
assert {
condition = cloudfoundry_space.space.id == output.space_id
error_message = "Space ID output must match the new space"
}

assert {
condition = cloudfoundry_space.space.name == var.cf_space_name
error_message = "Space name should match the cf_space_name variable"
}
}

run "test_manager_only" {
variables {
managers = ["user.manager@gsa.gov"]
}

assert {
condition = cloudfoundry_space_users.space_permissions.managers == toset(["1e5143a4-aa47-483c-8352-557988d5cc7a"])
error_message = "Should be able to set Space Managers"
}

assert {
condition = length(cloudfoundry_space_users.space_permissions.developers) == 0
error_message = "Should not have set any Space Developers"
}
}

run "test_individual_permissions" {
variables {
managers = ["user.manager@gsa.gov"]
developers = ["user.developer@gsa.gov"]
}

assert {
condition = cloudfoundry_space_users.space_permissions.managers == toset(["1e5143a4-aa47-483c-8352-557988d5cc7a"])
error_message = "Should be able to set Space Managers"
}

assert {
condition = cloudfoundry_space_users.space_permissions.developers == toset(["2c945842-13ee-4383-84ad-34ecbcde5ce6"])
error_message = "Should be able to set Space Developers"
}
}

run "test_deployer_permissions" {
variables {
developers = ["user.developer@gsa.gov"]
deployers = ["user.manager@gsa.gov"]
}

assert {
condition = cloudfoundry_space_users.space_permissions.managers == toset(["1e5143a4-aa47-483c-8352-557988d5cc7a"])
error_message = "Should be able to set Space Managers via var.deployers"
}

assert {
condition = cloudfoundry_space_users.space_permissions.developers == toset(["2c945842-13ee-4383-84ad-34ecbcde5ce6", "1e5143a4-aa47-483c-8352-557988d5cc7a"])
error_message = "Should set Space Developers to var.developers + var.deployers"
}
}
121 changes: 121 additions & 0 deletions clamav/tests/creation.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
mock_provider "cloudfoundry" {}

variables {
cf_org_name = "gsa-tts-devtools-prototyping"
cf_space_name = "terraform-cloudgov-ci-tests"
app_name_or_id = "terraform_cloudgov_app"
name = "terraform-cloudgov-clamav-test"
clamav_image = "ghcr.io/gsa-tts/clamav-rest/clamav:TAG"
max_file_size = "30M"
}

run "test_app_creation" {
assert {
condition = cloudfoundry_app.clamav_api.id == output.app_id
error_message = "App ID output must match the clamav app ID"
}

assert {
condition = cloudfoundry_route.clamav_route.id == output.route_id
error_message = "Route ID output must match the ID of the route to the clamav app"
}

assert {
condition = cloudfoundry_route.clamav_route.endpoint == output.endpoint
error_message = "Endpoint output must match the clamav route endpoint"
}

assert {
condition = cloudfoundry_route.clamav_route.hostname == var.name
error_message = "ClamAV route uses the service name for hostname"
}

assert {
condition = cloudfoundry_app.clamav_api.name == var.name
error_message = "App name matches var.name"
}

assert {
condition = cloudfoundry_app.clamav_api.memory == var.clamav_memory
error_message = "App memory is passed as var.clamav_memory"
}

assert {
condition = cloudfoundry_app.clamav_api.docker_image == var.clamav_image
error_message = "Docker image is passed directly in as var.clamav_image"
}

assert {
condition = [for r in cloudfoundry_app.clamav_api.routes : r.route] == [cloudfoundry_route.clamav_route.id]
error_message = "ClamAV app has the route set on the internal domain"
}

assert {
condition = cloudfoundry_app.clamav_api.environment["MAX_FILE_SIZE"] == var.max_file_size
error_message = "Sets the max file size to var.max_file_size"
}

assert {
condition = lookup(cloudfoundry_app.clamav_api.environment, "PROXY_SERVER", null) == null
error_message = "Does not set the PROXY_SERVER environment by default"
}

assert {
condition = lookup(cloudfoundry_app.clamav_api.environment, "PROXY_PORT", null) == null
error_message = "Does not set the PROXY_PORT environment by default"
}

assert {
condition = lookup(cloudfoundry_app.clamav_api.environment, "PROXY_USERNAME", null) == null
error_message = "Does not set the PROXY_USERNAME environment by default"
}

assert {
condition = lookup(cloudfoundry_app.clamav_api.environment, "PROXY_PASSWORD", null) == null
error_message = "Does not set the PROXY_PASSWORD environment by default"
}

assert {
condition = [for policy in cloudfoundry_network_policy.clamav_routing.policy : policy.source_app] == [data.cloudfoundry_app.app.id]
error_message = "Routing policy allows traffic from the source app"
}

assert {
condition = [for policy in cloudfoundry_network_policy.clamav_routing.policy : policy.destination_app] == [cloudfoundry_app.clamav_api.id]
error_message = "Routing policy allows traffic to the clamav app"
}

assert {
condition = [for policy in cloudfoundry_network_policy.clamav_routing.policy : policy.port] == ["61443"]
error_message = "Routing policy opens up traffic on the internal https port"
}
}

run "test_with_proxy" {
variables {
proxy_server = "proxy.server"
proxy_port = "8900"
proxy_username = "username"
proxy_password = "not-a-real-password"
}

assert {
condition = cloudfoundry_app.clamav_api.environment["PROXY_SERVER"] == var.proxy_server
error_message = "Proxy variables are set properly"
}

assert {
condition = cloudfoundry_app.clamav_api.environment["PROXY_PORT"] == var.proxy_port
error_message = "Proxy variables are set properly"
}

assert {
condition = cloudfoundry_app.clamav_api.environment["PROXY_USERNAME"] == var.proxy_username
error_message = "Proxy variables are set properly"
}

assert {
condition = cloudfoundry_app.clamav_api.environment["PROXY_PASSWORD"] == var.proxy_password
error_message = "Proxy variables are set properly"
}
}
47 changes: 47 additions & 0 deletions database/tests/creation.tftest.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
mock_provider "cloudfoundry" {
mock_data "cloudfoundry_service" {
defaults = {
service_plans = {
"micro-psql" = "03c93c7b-3e1c-47c5-a6c3-1df151d280dd"
}
}
}
}

variables {
cf_org_name = "gsa-tts-devtools-prototyping"
cf_space_name = "terraform-cloudgov-ci-tests"
rds_plan_name = "micro-psql"
name = "terraform-cloudgov-rds-test"
tags = ["terraform-cloudgov", "tests"]
json_params = jsonencode({
backup_retention_period = 30
})
}

run "test_db_creation" {
assert {
condition = cloudfoundry_service_instance.rds.id == output.instance_id
error_message = "Instance ID output must match the service instance"
}

assert {
condition = cloudfoundry_service_instance.rds.service_plan == data.cloudfoundry_service.rds.service_plans[var.rds_plan_name]
error_message = "Service Plan should match the rds_plan_name variable"
}

assert {
condition = cloudfoundry_service_instance.rds.name == var.name
error_message = "Service instance name should match the name variable"
}

assert {
condition = cloudfoundry_service_instance.rds.tags == var.tags
error_message = "Service instance tags should match the tags variable"
}

assert {
condition = cloudfoundry_service_instance.rds.json_params == "{\"backup_retention_period\":30}"
error_message = "Service instance json_params should be configurable"
}
}
Loading