|
| 1 | +# Testing |
| 2 | + |
| 3 | +Unit tests for the shell scripts that power the GitHub Actions in this repository. |
| 4 | + |
| 5 | +## Framework |
| 6 | + |
| 7 | +Tests are written using [bats-core](https://github.com/bats-core/bats-core) — the Bash Automated Testing System. |
| 8 | + |
| 9 | +## Structure |
| 10 | + |
| 11 | +Tests are organised per-action, mirroring the mono-repo structure of the actions themselves. |
| 12 | +Each action that contains testable shell scripts has a corresponding directory under `tests/unit/`. |
| 13 | + |
| 14 | +```text |
| 15 | +tests/ |
| 16 | +├── unit/ |
| 17 | +│ ├── promote-ecr-image/ |
| 18 | +│ │ ├── test_aws_unset.bats # Tests for the shared aws_unset.sh utility |
| 19 | +│ │ ├── test_options_helpers.bats # Tests for the shared options_helpers.sh utility |
| 20 | +│ │ └── test_promote_image.bats # Tests for promote_image.sh |
| 21 | +│ ├── test-python/ |
| 22 | +│ │ └── test_configure_pip.bats # Tests for configure_pip.sh |
| 23 | +│ ├── update-aws-ecs/ |
| 24 | +│ │ └── test_update_ecs.bats # Tests for update_ecs.sh |
| 25 | +│ └── update-aws-lambda/ |
| 26 | +│ └── test_update_lambda.bats # Tests for update_lambda.sh |
| 27 | +└── helpers/ |
| 28 | + └── mock_helpers.bash # Shared mock creation and assertion utilities |
| 29 | +``` |
| 30 | + |
| 31 | +## What Is Tested |
| 32 | + |
| 33 | +| Action | Script | Tests | What's covered | |
| 34 | +|--------|--------|-------|----------------| |
| 35 | +| `promote-ecr-image` | `options_helpers.sh` | 15 | `has_argument()` and `extract_argument()` parsing logic | |
| 36 | +| `promote-ecr-image` | `aws_unset.sh` | 7 | All 4 AWS credential env vars are cleared; no-op when already unset | |
| 37 | +| `promote-ecr-image` | `promote_image.sh` | 13 | Every required env var validation (exits 1 for each missing var); `--help` | |
| 38 | +| `test-python` | `configure_pip.sh` | 10 | Correct `pip config set` calls per env var; no-op when unset; `--help` | |
| 39 | +| `update-aws-ecs` | `update_ecs.sh` | 8 | `--help`, `aws ecs update-service` invocation, `--force-new-deployment`, failure path | |
| 40 | +| `update-aws-lambda` | `update_lambda.sh` | 7 | `--help`, `aws lambda update-function-code` invocation, failure path | |
| 41 | + |
| 42 | +### What Is NOT Tested Here |
| 43 | + |
| 44 | +- **Composite action YAML** — action `.yml` files use GitHub Actions expression syntax |
| 45 | + (`${{ inputs.xxx }}`) that cannot run outside of a GitHub Actions runner. |
| 46 | +- **Live AWS calls** — tests that require actual AWS credentials are integration tests |
| 47 | + and must run in a real CI environment with OIDC or stored secrets. |
| 48 | + |
| 49 | +## Mocking Strategy |
| 50 | + |
| 51 | +External commands (`aws`, `pip`, `tput`) are replaced with lightweight mock binaries |
| 52 | +that record every invocation to a log file (`$MOCK_DIR/<command>_calls.log`). |
| 53 | +Tests assert the correct arguments were passed without hitting real cloud APIs. |
| 54 | + |
| 55 | +`tests/helpers/mock_helpers.bash` provides shared utilities for creating mocks and |
| 56 | +making assertions against them. |
| 57 | + |
| 58 | +## Running Locally |
| 59 | + |
| 60 | +### Install bats |
| 61 | + |
| 62 | +```sh |
| 63 | +# via npm (recommended — matches the CI install) |
| 64 | +npm install -g bats |
| 65 | + |
| 66 | +# via Homebrew |
| 67 | +brew install bats-core |
| 68 | +``` |
| 69 | + |
| 70 | +### Run all tests for a specific action |
| 71 | + |
| 72 | +```sh |
| 73 | +bats tests/unit/update-aws-ecs/ |
| 74 | +``` |
| 75 | + |
| 76 | +### Run tests for all actions |
| 77 | + |
| 78 | +```sh |
| 79 | +for dir in tests/unit/*/; do bats --verbose-run "$dir"; done |
| 80 | +``` |
| 81 | + |
| 82 | +### Run with verbose output |
| 83 | + |
| 84 | +```sh |
| 85 | +bats --verbose-run tests/unit/promote-ecr-image/ |
| 86 | +``` |
| 87 | + |
| 88 | +## CI |
| 89 | + |
| 90 | +The `code-quality.yml` workflow runs automatically on every PR to `main`. |
| 91 | +It uses `tj-actions/changed-files` to detect which action directories have changed |
| 92 | +and runs tests only for those actions — each in its own isolated job. |
| 93 | + |
| 94 | +## Writing New Tests |
| 95 | + |
| 96 | +1. Create `tests/unit/<action-name>/test_<script_name>.bats`. |
| 97 | +2. Set `REPO_ROOT` relative to `BATS_TEST_DIRNAME` — tests are three levels deep, |
| 98 | + so use: `REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../../.." && pwd)"` |
| 99 | +3. In `setup()`, create a `MOCK_DIR`, add mocks for any external commands, and prepend |
| 100 | + `$MOCK_DIR` to `PATH` — subshells spawned by `run bash -c "..."` inherit the PATH |
| 101 | + automatically, so do not re-export `PATH` inside the subshell. |
| 102 | +4. Use `run bash -c "source '...script.sh'"` for tests that need to capture a non-zero |
| 103 | + exit code from the script under test. |
| 104 | + |
| 105 | +See existing test files for patterns. |
0 commit comments