#!/usr/bin/env bash set -eo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" FIXTURES_DIR="$SCRIPT_DIR/fixtures" LOGS_DIR="$SCRIPT_DIR/logs" RESULTS_DIR="$SCRIPT_DIR/results" VENV_DIR="$PROJECT_DIR/.venv-e2e" PIDS=() PYTHON_BIN="${PYTHON:-}" if [[ -z "$PYTHON_BIN" ]]; then for candidate in python3.13 python3.12 python3.11 python3; do if command -v "$candidate" &>/dev/null; then ver=$("$candidate" -c "import sys; print(sys.version_info[:2])") major=$(echo "$ver" | tr -d '(),' | awk '{print $1}') minor=$(echo "$ver" | tr -d '(),' | awk '{print $2}') if [[ "$major" -ge 3 && "$minor" -ge 11 ]]; then PYTHON_BIN="$candidate" break fi fi done fi if [[ -z "$PYTHON_BIN" ]]; then echo "ERROR: Python >= 3.11 required. Set PYTHON=/path/to/python3.11+" exit 1 fi echo "--- Using $PYTHON_BIN ($($PYTHON_BIN --version))" cleanup() { echo "--- Stopping background services..." for pid in "${PIDS[@]+"${PIDS[@]}"}"; do kill "$pid" 2>/dev/null || true done wait 2>/dev/null || true echo "--- Done" } trap cleanup EXIT usage() { echo "Usage: $0 [test_path] [pytest_args...]" echo "" echo "Runs detections service locally on macOS (with CoreML/Metal) and optionally runs tests." echo "" echo "Examples:" echo " $0 # start service only" echo " $0 tests/test_video.py # run all video tests" echo " $0 tests/test_video.py::test_ft_p_10_frame_sampling_ac1 # run single test" echo " $0 tests/test_video.py -k 'frame_sampling' # run by keyword" echo "" echo "Environment:" echo " PYTHON=python3.13 use specific python" echo " SKIP_BUILD=1 skip Cython compilation" echo " SERVICE_ONLY=1 start service and wait (don't run tests even if args given)" exit 1 } [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && usage # --- Virtual environment --- if [[ ! -d "$VENV_DIR" ]]; then echo "--- Creating virtual environment at $VENV_DIR" "$PYTHON_BIN" -m venv "$VENV_DIR" fi source "$VENV_DIR/bin/activate" echo "--- Installing dependencies..." pip install -q --upgrade pip setuptools wheel if [[ "$(uname -s)" == "Darwin" && -f "$PROJECT_DIR/requirements-macos.txt" ]]; then pip install -q -r "$PROJECT_DIR/requirements-macos.txt" else pip install -q -r "$PROJECT_DIR/requirements.txt" fi pip install -q -r "$SCRIPT_DIR/requirements.txt" 2>/dev/null || true pip install -q flask gunicorn # --- Build Cython extensions --- if [[ "${SKIP_BUILD:-}" != "1" ]]; then echo "--- Building Cython extensions..." (cd "$PROJECT_DIR" && python setup.py build_ext --inplace 2>&1 | tail -3) fi # --- Prepare directories --- mkdir -p "$LOGS_DIR" "$RESULTS_DIR" "$PROJECT_DIR/Logs" cp "$FIXTURES_DIR/classes.json" "$PROJECT_DIR/classes.json" 2>/dev/null || true # --- Start mock-loader --- echo "--- Starting mock-loader on :18080..." MODELS_ROOT="$FIXTURES_DIR" \ gunicorn -b 0.0.0.0:18080 -w 1 --chdir "$SCRIPT_DIR/mocks/loader" app:app --access-logfile /dev/null & PIDS+=($!) # --- Start mock-annotations --- echo "--- Starting mock-annotations on :18081..." gunicorn -b 0.0.0.0:18081 -w 1 --chdir "$SCRIPT_DIR/mocks/annotations" app:app --access-logfile /dev/null & PIDS+=($!) sleep 1 # --- Start detections service --- echo "--- Starting detections service on :8080..." ( cd "$PROJECT_DIR" LOADER_URL="http://localhost:18080" \ ANNOTATIONS_URL="http://localhost:18081" \ PYTHONPATH="$PROJECT_DIR/src" \ python -m uvicorn main:app --host 0.0.0.0 --port 8080 --workers 1 ) & PIDS+=($!) echo "--- Waiting for services to be ready..." for i in $(seq 1 30); do if python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')" 2>/dev/null; then echo "--- All services ready!" break fi sleep 2 done # --- Run tests or wait --- if [[ "${SERVICE_ONLY:-}" == "1" ]]; then echo "--- Service running at http://localhost:8080 (Ctrl+C to stop)" wait elif [[ $# -gt 0 ]]; then echo "--- Running: pytest $* -v -x -s" BASE_URL="http://localhost:8080" \ MOCK_LOADER_URL="http://localhost:18080" \ MOCK_ANNOTATIONS_URL="http://localhost:18081" \ MEDIA_DIR="$FIXTURES_DIR" \ RESULTS_DIR="$RESULTS_DIR" \ python -m pytest "$@" -v -x -s --csv="$RESULTS_DIR/report.csv" --rootdir="$SCRIPT_DIR" echo "--- Tests finished. Results in $RESULTS_DIR/" else echo "--- Service running at http://localhost:8080 (Ctrl+C to stop)" echo "--- To run tests in another terminal:" echo " source $VENV_DIR/bin/activate" echo " cd $SCRIPT_DIR && BASE_URL=http://localhost:8080 pytest tests/test_video.py -v -x -s" wait fi