diff --git a/.github/workflows/terraform-test.yml b/.github/workflows/terraform-test.yml new file mode 100644 index 0000000..f42618b --- /dev/null +++ b/.github/workflows/terraform-test.yml @@ -0,0 +1,107 @@ +on: + workflow_call: + inputs: + test-filter: + description: Limit the Terraform Test operation to the specified test files. + type: string + required: false + +jobs: + terraform-test: + name: Terraform Test + runs-on: ubuntu-latest + env: + TF_IN_AUTOMATION: true + TF_TEST_RESULTS_FILE: tftest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: latest + terraform_wrapper: false + + - name: Terraform Format + id: fmt + run: terraform fmt -check + + - name: Terraform Init + id: init + run: terraform init + + - name: Terraform Validate + id: validate + run: terraform validate + + - name: Terraform Test + id: test + # Ensure that the outcome of this step is "failure" when "terraform test" returns a non-zero exit code + shell: bash -o pipefail {0} + env: + TF_TEST_FILTER: ${{ inputs.test-filter }} + run: terraform test -filter="$TF_TEST_FILTER" -json | tee "$TF_TEST_RESULTS_FILE" + + - name: Create job summary + if: success() || failure() + shell: bash {0} + env: + TF_FMT_OUTCOME: ${{ steps.fmt.outcome }} + TF_INIT_OUTCOME: ${{ steps.init.outcome }} + TF_VALIDATE_OUTCOME: ${{ steps.validate.outcome }} + TF_TEST_OUTCOME: ${{ steps.test.outcome }} + run: | + tftest_results=$(cat "$TF_TEST_RESULTS_FILE") + readarray -t tftest_array <<< "$tftest_results" + + table_rows=("| Path | Run | Status | Error message |") + table_rows+=("| --- | --- | --- | --- |") + + for tftest_json in "${tftest_array[@]}"; do + type=$(echo "$tftest_json" | jq -r .type) + + if [[ "$type" != "test_run" ]]; then + continue + fi + + test_run=$(echo "$tftest_json" | jq .test_run) + progress=$(echo "$test_run" | jq -r .progress) + + if [[ "$progress" != "complete" ]]; then + continue + fi + + path=$(echo "$test_run" | jq -r .path) + run=$(echo "$test_run" | jq -r .run) + status=$(echo "$test_run" | jq -r .status) + status_emoji="heavy_minus_sign" # neutral/unknown by default + + if [[ "$status" == "pass" ]]; then + status_emoji="heavy_check_mark" + fi + + error_message="" + if [[ "$status" == "fail" ]]; then + status_emoji="x" + error_message=$(echo "$tftest_results" | jq -r '. | select(."@level"=="error") | .diagnostic.detail') + fi + + table_rows+=("| \`$path\` | \`$run\` | :$status_emoji:**\`$status\`** | $error_message |") + done + + table=$(printf "%s\n" "${table_rows[@]}") + + echo "#### Terraform Format and Style ๐Ÿ–Œ\`$TF_FMT_OUTCOME\` + #### Terraform Initialization โš™\`$TF_INIT_OUTCOME\` + #### Terraform Validation ๐Ÿค–\`$TF_VALIDATE_OUTCOME\` + #### Terraform Test ๐Ÿงช\`$TF_TEST_OUTCOME\` + +
Show Tests + + $table + +
+ + *Pusher: @$GITHUB_ACTOR, Action: \`$GITHUB_EVENT_NAME\`, Workflow: \`$GITHUB_WORKFLOW\`*" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..089448f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,11 @@ +name: Test +on: + pull_request: + branches: + - main +jobs: + test: + name: Unit Tests + uses: ./.github/workflows/terraform-test.yml + with: + test-filter: tests/unit.tftest.hcl diff --git a/tests/setup/main.tf b/tests/setup/main.tf new file mode 100644 index 0000000..9911efd --- /dev/null +++ b/tests/setup/main.tf @@ -0,0 +1,22 @@ +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "~> 3.6.0" + } + } +} + +resource "random_id" "name_suffix" { + byte_length = 8 +} + +resource "random_uuid" "subscription_id" {} + +locals { + name_suffix = random_id.name_suffix.hex + resource_group_name = "rg-${local.name_suffix}" + server_name = "sql-${local.name_suffix}" + account_name = "st${local.name_suffix}" + storage_blob_endpoint = "https://${local.account_name}.blob.core.windows.net/" +} diff --git a/tests/setup/outputs.tf b/tests/setup/outputs.tf new file mode 100644 index 0000000..e896d29 --- /dev/null +++ b/tests/setup/outputs.tf @@ -0,0 +1,43 @@ +output "server_name" { + value = "sql-${local.name_suffix}" +} + +output "server_id" { + value = "/subscriptions/${random_uuid.subscription_id.result}/resourceGroups/${local.resource_group_name}/providers/Microsoft.Sql/servers/${local.server_name}" +} + +output "database_name" { + value = "sqldb-${local.name_suffix}" +} + +output "azuread_administrator_login_username" { + value = local.name_suffix +} + +output "azuread_administrator_object_id" { + value = random_uuid.subscription_id.result +} + +output "resource_group_name" { + value = "rg-${local.name_suffix}" +} + +output "location" { + value = "northeurope" +} + +output "log_analytics_workspace_id" { + value = "/subscriptions/${random_uuid.subscription_id.result}/resourceGroups/${local.resource_group_name}/providers/Microsoft.OperationalInsights/workspaces/log-${local.name_suffix}" +} + +output "account_name" { + value = "st${local.name_suffix}" +} + +output "storage_account_id" { + value = "/subscriptions/${random_uuid.subscription_id.result}/resourceGroups/${local.resource_group_name}/providers/Microsoft.Storage/storageAccounts/${local.account_name}" +} + +output "storage_blob_endpoint" { + value = "https://${local.account_name}.blob.core.windows.net/" +} diff --git a/tests/unit.tftest.hcl b/tests/unit.tftest.hcl index 22d9b17..c8c9048 100644 --- a/tests/unit.tftest.hcl +++ b/tests/unit.tftest.hcl @@ -1,15 +1,33 @@ -run "basic_unit_tests" { - command = plan +mock_provider "azurerm" {} +run "setup_tests" { module { - source = "./examples/basic" + source = "./tests/setup" } } -run "complete_unit_tests" { +run "basic" { command = plan - module { - source = "./examples/complete" + variables { + server_name = run.setup_tests.server_name + azuread_administrator_login_username = run.setup_tests.azuread_administrator_login_username + azuread_administrator_object_id = run.setup_tests.azuread_administrator_object_id + log_analytics_workspace_id = run.setup_tests.log_analytics_workspace_id + storage_account_id = run.setup_tests.storage_account_id + storage_blob_endpoint = run.setup_tests.storage_blob_endpoint + } +} + +run "complete" { + command = plan + + variables { + server_name = run.setup_tests.server_name + azuread_administrator_login_username = run.setup_tests.azuread_administrator_login_username + azuread_administrator_object_id = run.setup_tests.azuread_administrator_object_id + log_analytics_workspace_id = run.setup_tests.log_analytics_workspace_id + storage_account_id = run.setup_tests.storage_account_id + storage_blob_endpoint = run.setup_tests.storage_blob_endpoint } }