bash-unit-tests
Run every *.ci-test.sh file under a directory and fail the job when one or more scripts fail.
Each script runs from the job's current working directory. The job prints colored run, success, failed, and summary lines. The job also publishes a JUnit report for the GitLab Test summary widget.
Usage
include:
- component: $CI_SERVER_FQDN/xrow-public/ci-tools/bash-unit-tests@$CI_COMMIT_SHA
inputs:
path: tests
Place one or more executable or non-executable Bash test files below the configured path. The file name must end with .ci-test.sh.
tests/
container/
builds-image.ci-test.sh
helm/
renders-default-values.ci-test.sh
Each test is executed with Bash from the job's current working directory, normally the repository root in GitLab CI. Use paths relative to that directory, or derive paths from the script location when a fixture must stay beside a test file.
Example Tests
A small test should set strict Bash options, arrange its own temporary data, run one behavior, and assert the output that matters.
#!/usr/bin/env bash
set -euo pipefail
tmpdir="$(mktemp -d)"
trap 'rm -rf "${tmpdir}"' EXIT
cat > "${tmpdir}/values.yaml" <<'YAML'
replicaCount: 2
YAML
helm template example chart --values "${tmpdir}/values.yaml" > "${tmpdir}/rendered.yaml"
grep -q 'replicas: 2' "${tmpdir}/rendered.yaml"
For command-line tools, keep the assertion close to the command and print useful context before failing.
#!/usr/bin/env bash
set -euo pipefail
output="$(scripts/my-tool --format json)"
if ! jq -e '.status == "ok"' <<< "${output}" >/dev/null; then
printf 'Unexpected my-tool output:\n%s\n' "${output}" >&2
exit 1
fi
To verify an expected failure, temporarily disable errexit around the command and assert the exit code.
#!/usr/bin/env bash
set -euo pipefail
set +e
output="$(../../scripts/my-tool --invalid 2>&1)"
status=$?
set -e
test "${status}" -ne 0
grep -q 'unknown option' <<< "${output}"
Good Test Guidelines
- Test one behavior per file. Prefer several focused
*.ci-test.shfiles over one large script with many unrelated assertions. - Use
set -euo pipefailso failed commands, unset variables, and broken pipelines fail the test. - Create temporary files with
mktemp -dand clean them with atrap. - Use paths relative to the job working directory, or derive paths from the script location when fixtures must stay beside a test file.
- Assert observable behavior, such as rendered YAML, JSON fields, generated files, or exit codes.
- Print the captured output before exiting when a failure would otherwise be hard to diagnose from the job log.
- Avoid tests that depend on local machine state, timing, external services, or secrets unless those dependencies are explicit CI inputs.
- Do not hide failures with
|| true. If a command is expected to fail, capture and assert its status. - Make tests deterministic. Sort generated lists before comparing them and avoid relying on random names unless they are isolated in a temporary directory.
Local Run
Run the same test files locally before pushing:
find tests -type f -name '*.ci-test.sh' -print0 |
sort -z |
while IFS= read -r -d '' test_file; do
bash "./${test_file}"
done
Inputs
| Name | Default | Description |
|---|---|---|
stage | test | The stage for the test job. |
needs | [] | Jobs that the test job depends on. |
allow-failure | false | Whether the pipeline may continue after failed tests. |
path | . | Directory to search for *.ci-test.sh files. |
junit-report | bash-unit-tests-junit.xml | Path to the JUnit report for the GitLab Test summary widget. |
rules | exists: **/*.ci-test.sh | Rules for the test job. |
Inputs
| Name | Description | Default | Type |
| --- | --- | --- | --- |
| allow-failure | Should the pipeline continue if one or more tests fail? | false | boolean |
| junit-report | Path to the JUnit report for the GitLab Test summary widget. | bash-unit-tests-junit.xml | string |
| needs | The jobs that this job depends on. | [] | array |
| path | The directory to search for *.ci-test.sh files. | . | string |
| rules | The rules for the test job. | [{"exists":["**/*.ci-test.sh"],"when":"on_success"},{"when":"never"}] | array |
| stage | The stage for the test job. | test | string |