|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# Run test suites. |
| 4 | +# |
| 5 | +# Targets: tests | testpr | testnets |
| 6 | +# Usage: |
| 7 | +# ./run_tests.sh tests |
| 8 | +# ./run_tests.sh testpr |
| 9 | +# ./run_tests.sh testnets |
| 10 | +# |
| 11 | +# Env vars: |
| 12 | +# TESTS_DIR: directory with tests to run (default: cardano_node_tests/) |
| 13 | +# ARTIFACTS_DIR: directory to save artifacts into (default: .artifacts) |
| 14 | +# COVERAGE_DIR: directory to save CLI coverage data into (default: .cli_coverage) |
| 15 | +# REPORTS_DIR: directory to save Allure test reports into (default: .reports) |
| 16 | +# MARKEXPR: pytest mark expression to filter tests, without the `-m` flag |
| 17 | +# NO_ARTIFACTS: if set, do not save artifacts |
| 18 | +# PYTEST_ARGS: additional args to pass to pytest |
| 19 | +# CI_ARGS: additional args to pass to pytest (for CI runs) |
| 20 | +# TEST_THREADS: number of pytest workers (defaults vary per target) |
| 21 | +# DESELECT_FROM_FILE: path to file with tests to deselect |
| 22 | +# CLUSTERS_COUNT: number of local testnet clusters to launch |
| 23 | +# FORBID_RESTART: if set to 1, do not restart clusters between tests |
| 24 | +# |
| 25 | +# Notes: |
| 26 | +# - If PYTEST_ARGS is provided, we disable cleanup and the initial "skip all" pass. |
| 27 | +# - If DESELECT_FROM_FILE is provided, we disable the initial "skip all" pass. |
| 28 | +# - If NO_ARTIFACTS is unset, we save artifacts under ARTIFACTS_DIR. |
| 29 | +# - HTML/JUnit reports are generated only when PYTEST_ARGS is unset. |
| 30 | + |
| 31 | +set -Eeuo pipefail |
| 32 | + |
| 33 | +# Defaults |
| 34 | +TESTS_DIR="${TESTS_DIR:-cardano_node_tests/}" |
| 35 | +ARTIFACTS_DIR="${ARTIFACTS_DIR:-.artifacts}" |
| 36 | +COVERAGE_DIR="${COVERAGE_DIR:-.cli_coverage}" |
| 37 | +REPORTS_DIR="${REPORTS_DIR:-.reports}" |
| 38 | + |
| 39 | +# Helpers |
| 40 | +usage() { |
| 41 | + cat <<EOF |
| 42 | +Usage: "$0" [tests|testpr|testnets] |
| 43 | +
|
| 44 | +Targets: |
| 45 | + tests Run all tests (default TEST_THREADS=20), DbSyncAbortOnPanic=1 |
| 46 | + testpr Run PR-level tests (default CLUSTERS_COUNT=5, TEST_THREADS=20, MARKEXPR="smoke") |
| 47 | + testnets Run tests that can run on public testnets (CLUSTERS_COUNT=1, FORBID_RESTART=1, |
| 48 | + default TEST_THREADS=15, MARKEXPR="testnets") |
| 49 | +
|
| 50 | +All targets respect the same env vars as the original Makefile. |
| 51 | +EOF |
| 52 | +} |
| 53 | + |
| 54 | +pytest_w_echo() { |
| 55 | + echo "Running: PYTEST_ADDOPTS='${PYTEST_ADDOPTS:-}' pytest $*" |
| 56 | + pytest "$@" |
| 57 | +} |
| 58 | + |
| 59 | +ensure_dirs() { |
| 60 | + mkdir -p "$ARTIFACTS_DIR" "$COVERAGE_DIR" "$REPORTS_DIR" |
| 61 | +} |
| 62 | + |
| 63 | +# Set common env vars that affect test runs. |
| 64 | +set_common_env() { |
| 65 | + # Cleanup / skip logic |
| 66 | + CLEANUP="yes" |
| 67 | + RUN_SKIPS="yes" |
| 68 | + |
| 69 | + if [[ -n "${PYTEST_ARGS:-}" ]]; then |
| 70 | + CLEANUP="no" |
| 71 | + RUN_SKIPS="no" |
| 72 | + export PYTEST_ADDOPTS="${PYTEST_ADDOPTS:+$PYTEST_ADDOPTS }${PYTEST_ARGS}" |
| 73 | + fi |
| 74 | + |
| 75 | + if [[ -n "${DESELECT_FROM_FILE:-}" ]]; then |
| 76 | + RUN_SKIPS="no" |
| 77 | + fi |
| 78 | + |
| 79 | + if [[ -n "${CI_ARGS:-}" ]]; then |
| 80 | + export PYTEST_ADDOPTS="${PYTEST_ADDOPTS:+$PYTEST_ADDOPTS }${CI_ARGS}" |
| 81 | + fi |
| 82 | +} |
| 83 | + |
| 84 | +# Compute args that depend on current environment. |
| 85 | +compute_common_args() { |
| 86 | + # MARKEXPR handling |
| 87 | + if [[ -n "${MARKEXPR:-}" ]]; then |
| 88 | + MARKEXPR_ARR=( -m "$MARKEXPR" ) |
| 89 | + else |
| 90 | + MARKEXPR_ARR=() |
| 91 | + fi |
| 92 | + |
| 93 | + # It may not be always necessary to save artifacts, e.g. when running tests on local cluster |
| 94 | + # on local machine. |
| 95 | + if [[ -n "${NO_ARTIFACTS+x}" ]]; then |
| 96 | + ARTIFACTS_ARR=() |
| 97 | + else |
| 98 | + ARTIFACTS_ARR=( "--artifacts-base-dir=$ARTIFACTS_DIR" ) |
| 99 | + fi |
| 100 | + |
| 101 | + # Test run report args only when PYTEST_ARGS is unset. |
| 102 | + if [[ -z "${PYTEST_ARGS:-}" ]]; then |
| 103 | + TESTRUN_REPORT_ARR=( |
| 104 | + "--html=$REPORTS_DIR/testrun-report.html" |
| 105 | + "--self-contained-html" |
| 106 | + "--junitxml=$REPORTS_DIR/testrun-report.xml" |
| 107 | + ) |
| 108 | + else |
| 109 | + TESTRUN_REPORT_ARR=() |
| 110 | + fi |
| 111 | + |
| 112 | + # Deselect-from-file |
| 113 | + if [[ -n "${DESELECT_FROM_FILE:-}" ]]; then |
| 114 | + DESELECT_FROM_FILE_ARR=( "--deselect-from-file=$DESELECT_FROM_FILE" ) |
| 115 | + else |
| 116 | + DESELECT_FROM_FILE_ARR=() |
| 117 | + fi |
| 118 | +} |
| 119 | + |
| 120 | +cleanup_previous_run() { |
| 121 | + if [[ "$CLEANUP" == "yes" ]]; then |
| 122 | + # Remove previous reports and coverage artifacts. |
| 123 | + rm -f "$REPORTS_DIR"/{*-attachment.txt,*-result.json,*-container.json,testrun-report.*} || true |
| 124 | + rm -f "$COVERAGE_DIR"/cli_coverage_* || true |
| 125 | + fi |
| 126 | +} |
| 127 | + |
| 128 | +initial_skip_pass() { |
| 129 | + if [[ "$RUN_SKIPS" == "yes" ]]; then |
| 130 | + echo "Initial pass: skipping all tests to register them with Allure" |
| 131 | + pytest -s "$TESTS_DIR" "${MARKEXPR_ARR[@]}" --skipall --alluredir="$REPORTS_DIR" >/dev/null |
| 132 | + fi |
| 133 | +} |
| 134 | + |
| 135 | +run_real_tests() { |
| 136 | + pytest_w_echo \ |
| 137 | + "$TESTS_DIR" \ |
| 138 | + "${MARKEXPR_ARR[@]}" \ |
| 139 | + "${DESELECT_FROM_FILE_ARR[@]}" \ |
| 140 | + -n "${TEST_THREADS}" \ |
| 141 | + "${ARTIFACTS_ARR[@]}" \ |
| 142 | + --cli-coverage-dir="$COVERAGE_DIR" \ |
| 143 | + --alluredir="$REPORTS_DIR" \ |
| 144 | + "${TESTRUN_REPORT_ARR[@]}" \ |
| 145 | + "$@" |
| 146 | +} |
| 147 | + |
| 148 | +# Provide default MARKEXPR if none was given from env/CLI. |
| 149 | +ensure_markexpr_default() { |
| 150 | + local default_expr="$1" |
| 151 | + if [[ -z "${MARKEXPR:-}" ]]; then |
| 152 | + MARKEXPR="$default_expr" |
| 153 | + fi |
| 154 | +} |
| 155 | + |
| 156 | +# Targets |
| 157 | +target_tests() { |
| 158 | + export DbSyncAbortOnPanic="${DbSyncAbortOnPanic:-1}" |
| 159 | + TEST_THREADS="${TEST_THREADS:-20}" |
| 160 | + |
| 161 | + ensure_dirs |
| 162 | + set_common_env |
| 163 | + compute_common_args |
| 164 | + cleanup_previous_run |
| 165 | + initial_skip_pass |
| 166 | + run_real_tests "$@" |
| 167 | +} |
| 168 | + |
| 169 | +target_testpr() { |
| 170 | + export TESTPR=1 |
| 171 | + export CLUSTERS_COUNT="${CLUSTERS_COUNT:-5}" |
| 172 | + TEST_THREADS="${TEST_THREADS:-20}" |
| 173 | + ensure_markexpr_default "smoke" |
| 174 | + |
| 175 | + ensure_dirs |
| 176 | + set_common_env |
| 177 | + compute_common_args |
| 178 | + cleanup_previous_run |
| 179 | + initial_skip_pass |
| 180 | + run_real_tests "$@" |
| 181 | +} |
| 182 | + |
| 183 | +target_testnets() { |
| 184 | + export CLUSTERS_COUNT=1 |
| 185 | + export FORBID_RESTART=1 |
| 186 | + TEST_THREADS="${TEST_THREADS:-15}" |
| 187 | + ensure_markexpr_default "testnets" |
| 188 | + |
| 189 | + ensure_dirs |
| 190 | + set_common_env |
| 191 | + compute_common_args |
| 192 | + cleanup_previous_run |
| 193 | + initial_skip_pass |
| 194 | + run_real_tests "$@" |
| 195 | +} |
| 196 | + |
| 197 | +# Dispatch |
| 198 | +main() { |
| 199 | + command -v pytest >/dev/null 2>&1 || { |
| 200 | + echo "Error: pytest not found in PATH." >&2 |
| 201 | + exit 127 |
| 202 | +} |
| 203 | + |
| 204 | + local cmd="${1:-tests}" |
| 205 | + case "$cmd" in |
| 206 | + tests) shift; target_tests "$@";; |
| 207 | + testpr) shift; target_testpr "$@";; |
| 208 | + testnets) shift; target_testnets "$@";; |
| 209 | + -h|--help) usage;; |
| 210 | + *) echo "Unknown target: $cmd" >&2; usage; exit 2;; |
| 211 | + esac |
| 212 | +} |
| 213 | + |
| 214 | +main "$@" |
0 commit comments