Stabilize auth flow and profile images
This commit is contained in:
Executable
+441
@@ -0,0 +1,441 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
TMP_ROOT="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP_ROOT"' EXIT
|
||||
|
||||
PASS_COUNT=0
|
||||
|
||||
say() {
|
||||
printf '%s\n' "$*"
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf 'FAIL %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_file_contains() {
|
||||
local file="$1"
|
||||
local pattern="$2"
|
||||
if ! grep -Fq "$pattern" "$file"; then
|
||||
fail "expected '$pattern' in $file"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_exists_or_empty() {
|
||||
local file="$1"
|
||||
if [ -e "$file" ] && [ -s "$file" ]; then
|
||||
fail "expected empty or missing file: $file"
|
||||
fi
|
||||
}
|
||||
|
||||
new_fixture() {
|
||||
local name="$1"
|
||||
local dir="$TMP_ROOT/$name"
|
||||
mkdir -p "$dir/bin" "$dir/baron/config/.generated/ory/kratos" "$dir/baron/config/.generated/ory/oathkeeper" "$dir/logs" "$dir/state"
|
||||
touch "$dir/baron/Makefile"
|
||||
cat > "$dir/baron/config/.generated/ory/kratos/kratos.yml" <<'EOF'
|
||||
selfservice:
|
||||
allowed_return_urls:
|
||||
- http://localhost:5000
|
||||
- []
|
||||
EOF
|
||||
cat > "$dir/baron/config/.generated/ory/oathkeeper/entrypoint.sh" <<'EOF'
|
||||
#!/usr/bin/env sh
|
||||
exit 0
|
||||
EOF
|
||||
cat > "$dir/bin/docker" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
log_file="${TEST_CMD_LOG:?}"
|
||||
printf 'docker %s\n' "$*" >> "$log_file"
|
||||
|
||||
case "$*" in
|
||||
"compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml up -d")
|
||||
if [ "${TEST_DOCKER_UP_FAIL_ONCE:-0}" = "1" ] && [ ! -f "${TEST_STATE_DIR:?}/docker-up.failed" ]; then
|
||||
touch "${TEST_STATE_DIR}/docker-up.failed"
|
||||
echo "name conflict"
|
||||
exit 1
|
||||
fi
|
||||
if [ "${TEST_DOCKER_UP_HEALTH_FAILURE:-0}" = "1" ] && [ ! -f "${TEST_STATE_DIR:?}/docker-up.health-failed" ]; then
|
||||
touch "${TEST_STATE_DIR}/docker-up.health-failed"
|
||||
echo "dependency failed to start: container baron_backend is unhealthy"
|
||||
exit 1
|
||||
fi
|
||||
echo "compose up ok"
|
||||
;;
|
||||
"compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml down")
|
||||
echo "compose down ok"
|
||||
;;
|
||||
"compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml logs --no-color")
|
||||
echo "fake compose logs"
|
||||
;;
|
||||
"ps --format {{.Names}} {{.Status}}")
|
||||
printf 'baron_backend Up (healthy)\nory_kratos Up\n'
|
||||
;;
|
||||
"ps -a --format {{.Names}}")
|
||||
printf 'old_baron_backend\nold_ory_kratos\n'
|
||||
;;
|
||||
"ps --format {{.Names}}")
|
||||
printf 'baron_backend\nbaron_gateway\n'
|
||||
;;
|
||||
"rm -f old_baron_backend old_ory_kratos")
|
||||
echo "removed stale containers"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
cat > "$dir/bin/make" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'make %s\n' "$*" >> "${TEST_CMD_LOG:?}"
|
||||
EOF
|
||||
cat > "$dir/bin/adb" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'adb %s\n' "$*" >> "${TEST_CMD_LOG:?}"
|
||||
EOF
|
||||
cat > "$dir/bin/pkill" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'pkill %s\n' "$*" >> "${TEST_CMD_LOG:?}"
|
||||
EOF
|
||||
cat > "$dir/bin/chmod" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'chmod %s\n' "$*" >> "${TEST_CMD_LOG:?}"
|
||||
EOF
|
||||
cat > "$dir/bin/chown" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf 'chown %s\n' "$*" >> "${TEST_CMD_LOG:?}"
|
||||
EOF
|
||||
cat > "$dir/check.sh" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
state_dir="${TEST_STATE_DIR:?}"
|
||||
attempt_file="$state_dir/check-attempts"
|
||||
count=0
|
||||
if [ -f "$attempt_file" ]; then
|
||||
count="$(cat "$attempt_file")"
|
||||
fi
|
||||
count=$((count + 1))
|
||||
printf '%s' "$count" > "$attempt_file"
|
||||
|
||||
mode="${CHECK_MODE:-pass}"
|
||||
case "$mode" in
|
||||
pass)
|
||||
echo "RESULT ready-ish: 0 failure(s), 0 warning(s)"
|
||||
;;
|
||||
warn_then_pass)
|
||||
if [ "$count" -eq 1 ]; then
|
||||
echo "RESULT ready-ish: 0 failure(s), 1 warning(s)"
|
||||
else
|
||||
echo "RESULT ready-ish: 0 failure(s), 0 warning(s)"
|
||||
fi
|
||||
;;
|
||||
fail)
|
||||
echo "RESULT blocked: 1 failure(s), 0 warning(s)"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "unknown CHECK_MODE=$mode" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
cat > "$dir/api-smoke.sh" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
state_dir="${TEST_STATE_DIR:?}"
|
||||
attempt_file="$state_dir/api-attempts"
|
||||
count=0
|
||||
if [ -f "$attempt_file" ]; then
|
||||
count="$(cat "$attempt_file")"
|
||||
fi
|
||||
count=$((count + 1))
|
||||
printf '%s' "$count" > "$attempt_file"
|
||||
|
||||
mode="${API_MODE:-pass}"
|
||||
case "$mode" in
|
||||
pass)
|
||||
echo "PASS api smoke"
|
||||
;;
|
||||
login_failed)
|
||||
if [ "${TDC114_SKIP_AUTH_SMOKE:-false}" = "true" ]; then
|
||||
echo "SKIP authenticated smoke: TDC114_SKIP_AUTH_SMOKE=true"
|
||||
exit 0
|
||||
fi
|
||||
echo 'FAIL phone-login success: HTTP 401' >&2
|
||||
echo 'Response body:' >&2
|
||||
echo '{"error":"Login failed","code":"login_failed"}' >&2
|
||||
exit 1
|
||||
;;
|
||||
fail)
|
||||
echo "FAIL api smoke" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "unknown API_MODE=$mode" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
cat > "$dir/wsl-maintenance.sh" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
mode="${1:-status}"
|
||||
case "$mode" in
|
||||
status)
|
||||
echo "${TEST_WSL_MAINTENANCE_OUTPUT:-WSL maintenance reminder: OK}"
|
||||
;;
|
||||
*)
|
||||
echo "unsupported mode: $mode" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$dir/bin/docker" "$dir/bin/make" "$dir/bin/adb" "$dir/bin/pkill" \
|
||||
"$dir/bin/chmod" "$dir/bin/chown" "$dir/check.sh" "$dir/api-smoke.sh" \
|
||||
"$dir/wsl-maintenance.sh" "$dir/baron/config/.generated/ory/oathkeeper/entrypoint.sh"
|
||||
printf '%s\n' "$dir"
|
||||
}
|
||||
|
||||
run_case() {
|
||||
local name="$1"
|
||||
shift
|
||||
say "CASE $name"
|
||||
"$@"
|
||||
PASS_COUNT=$((PASS_COUNT + 1))
|
||||
}
|
||||
|
||||
test_startup_dry_run() {
|
||||
local fixture
|
||||
fixture="$(new_fixture startup-dry-run)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_CHECK_SCRIPT="$fixture/check.sh" \
|
||||
TDC114_API_SMOKE_SCRIPT="$fixture/api-smoke.sh" \
|
||||
TDC114_WSL_MAINTENANCE_SCRIPT="$fixture/wsl-maintenance.sh" \
|
||||
TDC114_START_AUTH_SERVER=false \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
MAKE_BIN="$fixture/bin/make" \
|
||||
bash "$ROOT_DIR/scripts/startup.sh" --dry-run --wait=0 --skip-android-check
|
||||
|
||||
assert_not_exists_or_empty "$cmd_log"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "WSL maintenance reminder: OK"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "Dry-run mode: no actions were actually performed"
|
||||
}
|
||||
|
||||
test_startup_auto_retry_success() {
|
||||
local fixture
|
||||
fixture="$(new_fixture startup-auto-success)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
TEST_DOCKER_UP_FAIL_ONCE=1 \
|
||||
CHECK_MODE=warn_then_pass \
|
||||
API_MODE=pass \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_CHECK_SCRIPT="$fixture/check.sh" \
|
||||
TDC114_API_SMOKE_SCRIPT="$fixture/api-smoke.sh" \
|
||||
TDC114_WSL_MAINTENANCE_SCRIPT="$fixture/wsl-maintenance.sh" \
|
||||
TDC114_START_AUTH_SERVER=false \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
MAKE_BIN="$fixture/bin/make" \
|
||||
bash "$ROOT_DIR/scripts/startup.sh" --auto --wait=0 --skip-android-check
|
||||
|
||||
assert_file_contains "$cmd_log" "docker rm -f old_baron_backend old_ory_kratos"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "check-baron-api-env.sh reported warnings on attempt 1"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "check-baron-api-env.sh passed with zero warnings"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "api-smoke.sh passed"
|
||||
if grep -Fq " - []" "$fixture/baron/config/.generated/ory/kratos/kratos.yml"; then
|
||||
fail "expected startup to sanitize invalid empty allowed_return_urls entry"
|
||||
fi
|
||||
}
|
||||
|
||||
test_startup_auto_health_failure_tolerated() {
|
||||
local fixture
|
||||
fixture="$(new_fixture startup-auto-health-failure)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
TEST_DOCKER_UP_HEALTH_FAILURE=1 \
|
||||
CHECK_MODE=pass \
|
||||
API_MODE=pass \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_CHECK_SCRIPT="$fixture/check.sh" \
|
||||
TDC114_API_SMOKE_SCRIPT="$fixture/api-smoke.sh" \
|
||||
TDC114_WSL_MAINTENANCE_SCRIPT="$fixture/wsl-maintenance.sh" \
|
||||
TDC114_START_AUTH_SERVER=false \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
MAKE_BIN="$fixture/bin/make" \
|
||||
bash "$ROOT_DIR/scripts/startup.sh" --auto --wait=0 --skip-android-check
|
||||
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "compose up reported dependency or health issues; continuing to stabilization checks before declaring failure"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "api-smoke.sh passed"
|
||||
}
|
||||
|
||||
test_startup_login_failed_falls_back_to_base_smoke() {
|
||||
local fixture
|
||||
fixture="$(new_fixture startup-login-fallback)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
CHECK_MODE=pass \
|
||||
API_MODE=login_failed \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_CHECK_SCRIPT="$fixture/check.sh" \
|
||||
TDC114_API_SMOKE_SCRIPT="$fixture/api-smoke.sh" \
|
||||
TDC114_WSL_MAINTENANCE_SCRIPT="$fixture/wsl-maintenance.sh" \
|
||||
TDC114_START_AUTH_SERVER=false \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
MAKE_BIN="$fixture/bin/make" \
|
||||
bash "$ROOT_DIR/scripts/startup.sh" --auto --wait=0 --skip-android-check
|
||||
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "api-smoke authenticated login failed; retrying in base-smoke-only mode because TDC114_REQUIRE_AUTH_SMOKE is false"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "api-smoke base-smoke-only mode passed"
|
||||
}
|
||||
|
||||
test_startup_auto_failure() {
|
||||
local fixture
|
||||
fixture="$(new_fixture startup-auto-failure)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
set +e
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
CHECK_MODE=fail \
|
||||
API_MODE=pass \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_CHECK_SCRIPT="$fixture/check.sh" \
|
||||
TDC114_API_SMOKE_SCRIPT="$fixture/api-smoke.sh" \
|
||||
TDC114_WSL_MAINTENANCE_SCRIPT="$fixture/wsl-maintenance.sh" \
|
||||
TDC114_START_AUTH_SERVER=false \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
MAKE_BIN="$fixture/bin/make" \
|
||||
bash "$ROOT_DIR/scripts/startup.sh" --auto --wait=0 --skip-android-check
|
||||
local rc=$?
|
||||
set -e
|
||||
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
fail "startup auto failure case should exit non-zero"
|
||||
fi
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/startup.log" "Startup failed: health checks did not pass"
|
||||
}
|
||||
|
||||
test_wsl_maintenance_schedule() {
|
||||
local fixture
|
||||
fixture="$(new_fixture wsl-maintenance-schedule)"
|
||||
local state_dir="$fixture/state"
|
||||
|
||||
TDC114_WSL_MAINTENANCE_STATE_DIR="$state_dir" \
|
||||
TDC114_WSL_MAINTENANCE_ANCHOR_DATE=2026-07-16 \
|
||||
TDC114_WSL_MAINTENANCE_TODAY=2026-07-20 \
|
||||
bash "$ROOT_DIR/scripts/check-wsl-maintenance.sh" status > "$fixture/status-not-due.txt"
|
||||
|
||||
assert_file_contains "$fixture/status-not-due.txt" "WSL maintenance reminder: OK"
|
||||
assert_file_contains "$fixture/status-not-due.txt" "Next due date: 2026-07-30"
|
||||
|
||||
TDC114_WSL_MAINTENANCE_STATE_DIR="$state_dir" \
|
||||
TDC114_WSL_MAINTENANCE_ANCHOR_DATE=2026-07-16 \
|
||||
TDC114_WSL_MAINTENANCE_TODAY=2026-07-30 \
|
||||
bash "$ROOT_DIR/scripts/check-wsl-maintenance.sh" status > "$fixture/status-due.txt"
|
||||
|
||||
assert_file_contains "$fixture/status-due.txt" "WSL maintenance reminder: DUE"
|
||||
assert_file_contains "$fixture/status-due.txt" "./scripts/check-wsl-maintenance.sh record"
|
||||
|
||||
TDC114_WSL_MAINTENANCE_STATE_DIR="$state_dir" \
|
||||
TDC114_WSL_MAINTENANCE_TODAY=2026-07-30 \
|
||||
bash "$ROOT_DIR/scripts/check-wsl-maintenance.sh" record > "$fixture/record.txt"
|
||||
|
||||
assert_file_contains "$fixture/record.txt" "Recorded WSL maintenance date: 2026-07-30"
|
||||
|
||||
TDC114_WSL_MAINTENANCE_STATE_DIR="$state_dir" \
|
||||
TDC114_WSL_MAINTENANCE_ANCHOR_DATE=2026-07-16 \
|
||||
TDC114_WSL_MAINTENANCE_TODAY=2026-08-05 \
|
||||
bash "$ROOT_DIR/scripts/check-wsl-maintenance.sh" status > "$fixture/status-after-record.txt"
|
||||
|
||||
assert_file_contains "$fixture/status-after-record.txt" "WSL maintenance reminder: OK"
|
||||
assert_file_contains "$fixture/status-after-record.txt" "Base date: 2026-07-30"
|
||||
}
|
||||
|
||||
test_shutdown_dry_run() {
|
||||
local fixture
|
||||
fixture="$(new_fixture shutdown-dry-run)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_ADB_CONNECT_ADDRESS=172.21.128.1:5562 \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
ADB_BIN="$fixture/bin/adb" \
|
||||
PKILL_BIN="$fixture/bin/pkill" \
|
||||
CHMOD_BIN="$fixture/bin/chmod" \
|
||||
CHOWN_BIN="$fixture/bin/chown" \
|
||||
bash "$ROOT_DIR/scripts/shutdown.sh" --dry-run
|
||||
|
||||
assert_not_exists_or_empty "$cmd_log"
|
||||
assert_file_contains "$fixture/logs/$(date +%F)/shutdown.log" "Dry-run mode: no shutdown actions were executed"
|
||||
}
|
||||
|
||||
test_shutdown_auto_order_and_scope() {
|
||||
local fixture
|
||||
fixture="$(new_fixture shutdown-auto)"
|
||||
local cmd_log="$fixture/commands.log"
|
||||
|
||||
TEST_CMD_LOG="$cmd_log" \
|
||||
TEST_STATE_DIR="$fixture/state" \
|
||||
BARON_SSO_WORKTREE="$fixture/baron" \
|
||||
TDC114_LOG_BASE="$fixture/logs" \
|
||||
TDC114_ADB_CONNECT_ADDRESS=172.21.128.1:5562 \
|
||||
DOCKER_BIN="$fixture/bin/docker" \
|
||||
ADB_BIN="$fixture/bin/adb" \
|
||||
PKILL_BIN="$fixture/bin/pkill" \
|
||||
CHMOD_BIN="$fixture/bin/chmod" \
|
||||
CHOWN_BIN="$fixture/bin/chown" \
|
||||
bash "$ROOT_DIR/scripts/shutdown.sh" --auto
|
||||
|
||||
assert_file_contains "$cmd_log" "pkill -f $ROOT_DIR/scripts/integration_tests.sh"
|
||||
assert_file_contains "$cmd_log" "pkill -f $ROOT_DIR/scripts/flutter-docker.sh"
|
||||
assert_file_contains "$cmd_log" "adb disconnect 172.21.128.1:5562"
|
||||
assert_file_contains "$cmd_log" "docker compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml logs --no-color"
|
||||
assert_file_contains "$cmd_log" "docker compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml down"
|
||||
assert_file_contains "$cmd_log" "docker rm -f old_baron_backend old_ory_kratos"
|
||||
assert_file_contains "$cmd_log" "chmod -R u+w config/.generated/"
|
||||
assert_file_contains "$cmd_log" "chown -R"
|
||||
|
||||
local logs_line
|
||||
local down_line
|
||||
logs_line="$(grep -n "docker compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml logs --no-color" "$cmd_log" | head -n1 | cut -d: -f1)"
|
||||
down_line="$(grep -n "docker compose -f docker-compose.yaml -f compose.infra.yaml -f compose.ory.yaml down" "$cmd_log" | head -n1 | cut -d: -f1)"
|
||||
if [ -z "$logs_line" ] || [ -z "$down_line" ] || [ "$logs_line" -ge "$down_line" ]; then
|
||||
fail "expected compose logs collection before compose down"
|
||||
fi
|
||||
}
|
||||
|
||||
run_case "startup dry-run" test_startup_dry_run
|
||||
run_case "startup auto retry success" test_startup_auto_retry_success
|
||||
run_case "startup auto health failure tolerated" test_startup_auto_health_failure_tolerated
|
||||
run_case "startup login failure falls back" test_startup_login_failed_falls_back_to_base_smoke
|
||||
run_case "startup auto failure" test_startup_auto_failure
|
||||
run_case "wsl maintenance schedule" test_wsl_maintenance_schedule
|
||||
run_case "shutdown dry-run" test_shutdown_dry_run
|
||||
run_case "shutdown auto order and scope" test_shutdown_auto_order_and_scope
|
||||
|
||||
say "PASS $PASS_COUNT case(s)"
|
||||
Reference in New Issue
Block a user