|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +# debug-surefire.sh |
| 5 | +# |
| 6 | +# Run Maven Surefire tests in "wait for debugger" mode (JDWP). |
| 7 | +# |
| 8 | +# Optional inputs: |
| 9 | +# --module <maven-module-id> Reactor project selector passed to "mvn -pl". |
| 10 | +# Convenience: if you pass just an artifactId (no ':' or '/'), |
| 11 | +# the script prefixes it with ':' (e.g., "foo" -> ":foo"). |
| 12 | +# --test-class <TestClass> Runs a single test class (Surefire -Dtest=...). |
| 13 | +# --test <TestClass#method> Runs a single test method/pattern (Surefire -Dtest=Class#method). |
| 14 | +# IMPORTANT: quote values containing '#', e.g. --test 'MyTest#myMethod' |
| 15 | +# --skip-install Skip the pre-test quick install step. |
| 16 | +# --no-offline | --online Run Maven without "-o" (useful if offline resolution fails). |
| 17 | +# |
| 18 | +# Extras: |
| 19 | +# Everything after "--" is passed through to Maven unchanged. |
| 20 | +# |
| 21 | +# Environment: |
| 22 | +# SUREFIRE_DEBUG_PORT If set (e.g. 8000), uses that port instead of 55005. |
| 23 | +# Binds to localhost for safety. |
| 24 | + |
| 25 | +usage() { |
| 26 | + cat <<'USAGE' |
| 27 | +Usage: |
| 28 | + debug-surefire.sh [--module <id>] [--test-class <class>] [--test <class#method>] [--skip-install] [--no-offline|--online] [-- <extra mvn args>] |
| 29 | +
|
| 30 | +Examples: |
| 31 | + # Debug a single test class (current module / reactor defaults) |
| 32 | + ./debug-surefire.sh --test-class MyTest |
| 33 | +
|
| 34 | + # Debug a single test method (quote the '#') |
| 35 | + ./debug-surefire.sh --test 'MyTest#shouldDoThing' |
| 36 | +
|
| 37 | + # Debug a test in one module of a multi-module build (artifactId shorthand) |
| 38 | + ./debug-surefire.sh --module my-module --test-class MyTest |
| 39 | +
|
| 40 | + # Pass through extra Maven args |
| 41 | + ./debug-surefire.sh --test-class MyTest -- -DtrimStackTrace=false -DfailIfNoTests=false |
| 42 | +
|
| 43 | + # Use a different debug port |
| 44 | + SUREFIRE_DEBUG_PORT=8000 ./debug-surefire.sh --test-class MyTest |
| 45 | +USAGE |
| 46 | +} |
| 47 | + |
| 48 | +MODULE="" |
| 49 | +TEST_CLASS="" |
| 50 | +TEST_TARGET="" |
| 51 | +SKIP_INSTALL="0" |
| 52 | +OFFLINE="1" |
| 53 | +PASSTHRU=() |
| 54 | + |
| 55 | +while [[ $# -gt 0 ]]; do |
| 56 | + case "$1" in |
| 57 | + -m|--module) |
| 58 | + MODULE="${2:-}"; shift 2 ;; |
| 59 | + -c|--class|--test-class) |
| 60 | + TEST_CLASS="${2:-}"; shift 2 ;; |
| 61 | + -t|--test|--test-target) |
| 62 | + TEST_TARGET="${2:-}"; shift 2 ;; |
| 63 | + --skip-install) |
| 64 | + SKIP_INSTALL="1"; shift ;; |
| 65 | + --no-offline|--online) |
| 66 | + OFFLINE="0"; shift ;; |
| 67 | + -h|--help) |
| 68 | + usage; exit 0 ;; |
| 69 | + --) |
| 70 | + shift |
| 71 | + PASSTHRU+=("$@") |
| 72 | + break |
| 73 | + ;; |
| 74 | + *) |
| 75 | + echo "Unknown argument: $1" >&2 |
| 76 | + echo >&2 |
| 77 | + usage >&2 |
| 78 | + exit 2 |
| 79 | + ;; |
| 80 | + esac |
| 81 | +done |
| 82 | + |
| 83 | +if [[ -n "$TEST_CLASS" && -n "$TEST_TARGET" ]]; then |
| 84 | + echo "ERROR: Use either --test-class OR --test (Class#method), not both." >&2 |
| 85 | + exit 2 |
| 86 | +fi |
| 87 | + |
| 88 | +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" |
| 89 | +cd "$ROOT" |
| 90 | + |
| 91 | +# Prefer Maven Wrapper if present. |
| 92 | +MVN="mvn" |
| 93 | +if [[ -x "./mvnw" ]]; then |
| 94 | + MVN="./mvnw" |
| 95 | +fi |
| 96 | + |
| 97 | +PORT="${SUREFIRE_DEBUG_PORT:-55005}" |
| 98 | +REPO_LOCAL="-Dmaven.repo.local=$ROOT/.m2_repo" |
| 99 | + |
| 100 | +OFFLINE_ARGS=() |
| 101 | +if [[ "$OFFLINE" == "1" ]]; then |
| 102 | + OFFLINE_ARGS+=("-o") |
| 103 | +fi |
| 104 | + |
| 105 | +# If it looks like a bare artifactId, convert to :artifactId for -pl convenience. |
| 106 | +PL="" |
| 107 | +if [[ -n "$MODULE" ]]; then |
| 108 | + PL="$MODULE" |
| 109 | + if [[ "$PL" != *":"* && "$PL" != *"/"* ]]; then |
| 110 | + PL=":$PL" |
| 111 | + fi |
| 112 | +fi |
| 113 | + |
| 114 | +if [[ "$SKIP_INSTALL" != "1" ]]; then |
| 115 | + INSTALL_CMD=("$MVN" "-T" "1C" "${OFFLINE_ARGS[@]}" "$REPO_LOCAL" "-Pquick") |
| 116 | + if [[ -n "$PL" ]]; then |
| 117 | + INSTALL_CMD+=("-pl" "$PL" "-am") |
| 118 | + fi |
| 119 | + INSTALL_CMD+=("clean" "install") |
| 120 | + echo "=== Pre-test install (fast, no tests) ===" >&2 |
| 121 | + printf ' %q' "${INSTALL_CMD[@]}"; echo >&2 |
| 122 | + "${INSTALL_CMD[@]}" |
| 123 | + echo >&2 |
| 124 | +fi |
| 125 | + |
| 126 | +# Build Maven test command. |
| 127 | +CMD=("$MVN" "${OFFLINE_ARGS[@]}" "$REPO_LOCAL") |
| 128 | + |
| 129 | +if [[ -n "$PL" ]]; then |
| 130 | + CMD+=("-pl" "$PL") |
| 131 | +fi |
| 132 | + |
| 133 | +# Enable Surefire's debug mode. |
| 134 | +CMD+=("-Dmaven.surefire.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:${PORT}") |
| 135 | + |
| 136 | + |
| 137 | +# Narrow the test scope if requested. |
| 138 | +if [[ -n "$TEST_TARGET" ]]; then |
| 139 | + CMD+=("-Dtest=$TEST_TARGET") |
| 140 | +elif [[ -n "$TEST_CLASS" ]]; then |
| 141 | + CMD+=("-Dtest=$TEST_CLASS") |
| 142 | +fi |
| 143 | + |
| 144 | +# Pass-through args (e.g., -DfailIfNoTests=false) |
| 145 | +if [[ ${#PASSTHRU[@]} -gt 0 ]]; then |
| 146 | + CMD+=("${PASSTHRU[@]}") |
| 147 | +fi |
| 148 | + |
| 149 | +CMD+=("test") |
| 150 | + |
| 151 | +{ |
| 152 | + echo "=== Maven Surefire Debug Runner ===" |
| 153 | + echo "Root: $ROOT" |
| 154 | + echo "Maven: $MVN" |
| 155 | + if [[ -n "$PL" ]]; then |
| 156 | + echo "Module selector (-pl): $PL" |
| 157 | + fi |
| 158 | + if [[ -n "$TEST_TARGET" ]]; then |
| 159 | + echo "Test selector: -Dtest=$TEST_TARGET" |
| 160 | + elif [[ -n "$TEST_CLASS" ]]; then |
| 161 | + echo "Test selector: -Dtest=$TEST_CLASS" |
| 162 | + else |
| 163 | + echo "Test selector: (all tests selected by Maven/Surefire)" |
| 164 | + fi |
| 165 | + if [[ "$OFFLINE" == "1" ]]; then |
| 166 | + echo "Offline: yes (-o)" |
| 167 | + else |
| 168 | + echo "Offline: no" |
| 169 | + fi |
| 170 | + echo "Local repo: $ROOT/.m2_repo" |
| 171 | + echo "JDWP port: $PORT (attach to localhost)" |
| 172 | + echo |
| 173 | + echo "Attach a debugger, e.g.:" |
| 174 | + echo " jdb -attach $PORT" |
| 175 | + echo |
| 176 | + echo "Running:" |
| 177 | + printf ' %q' "${CMD[@]}"; echo |
| 178 | + echo "==================================" |
| 179 | + echo |
| 180 | +} >&2 |
| 181 | + |
| 182 | +exec "${CMD[@]}" |
| 183 | + |
0 commit comments