Files
buzz/scripts/run-tests.sh
T

220 lines
6.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# run-tests.sh — Run Sprout test suite
# =============================================================================
# Usage:
# ./scripts/run-tests.sh # run all tests (default)
# ./scripts/run-tests.sh unit # unit tests only (no infra needed)
# ./scripts/run-tests.sh integration # integration tests only
# ./scripts/run-tests.sh all # explicit all
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
MODE="${1:-all}"
TIMEOUT=60 # seconds to wait for services if starting them
DB_USER="${SPROUT_DB_USER:-sprout}"
DB_PASS="${SPROUT_DB_PASS:-sprout_dev}"
DB_NAME="${SPROUT_DB_NAME:-sprout}"
DOCKER_DB_HOST="${SPROUT_DOCKER_DB_HOST:-mysql}"
DOCKER_NETWORK="${SPROUT_DOCKER_NETWORK:-sprout-net}"
MYSQL_CLIENT_IMAGE="${SPROUT_DB_CLIENT_IMAGE:-mysql:8.0}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log() { echo -e "${BLUE}[run-tests]${NC} $*"; }
success(){ echo -e "${GREEN}[run-tests]${NC}$*"; }
warn() { echo -e "${YELLOW}[run-tests]${NC} ⚠️ $*"; }
error() { echo -e "${RED}[run-tests]${NC}$*" >&2; }
section(){ echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; echo -e "${CYAN} $*${NC}"; echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; }
cd "${REPO_ROOT}"
run_mysql_in_container() {
docker run --rm -i --network "${DOCKER_NETWORK}" \
-e MYSQL_PWD="${DB_PASS}" \
"${MYSQL_CLIENT_IMAGE}" \
mysql -h"${DOCKER_DB_HOST}" -u"${DB_USER}" "${DB_NAME}" "$@"
}
# ---- Load .env if present ---------------------------------------------------
if [[ -f ".env" ]]; then
log "Loading .env..."
set -o allexport
# shellcheck disable=SC1091
source .env
set +o allexport
else
# Use defaults matching docker-compose.yml
export DATABASE_URL="mysql://sprout:sprout_dev@localhost:3306/sprout"
export REDIS_URL="redis://localhost:6379"
export TYPESENSE_API_KEY="sprout_dev_key"
export TYPESENSE_URL="http://localhost:8108"
fi
# ---- Track results ----------------------------------------------------------
declare -a PASSED=()
declare -a FAILED=()
run_test_step() {
local name="$1"
shift
log "Running: ${name}"
if "$@"; then
success "${name} passed"
PASSED+=("${name}")
else
error "${name} FAILED"
FAILED+=("${name}")
fi
}
# ---- Check / start infra (for integration tests) ----------------------------
services_healthy() {
local mysql_ok redis_ok
mysql_ok=$(docker inspect --format='{{.State.Health.Status}}' sprout-mysql 2>/dev/null || echo "not_found")
redis_ok=$(docker inspect --format='{{.State.Health.Status}}' sprout-redis 2>/dev/null || echo "not_found")
[[ "${mysql_ok}" == "healthy" && "${redis_ok}" == "healthy" ]]
}
ensure_services() {
if services_healthy; then
success "Services already healthy"
return 0
fi
warn "Services not running — starting them..."
docker compose up -d
local elapsed=0
local interval=3
while ! services_healthy; do
if [[ ${elapsed} -ge ${TIMEOUT} ]]; then
error "Timed out waiting for services (${TIMEOUT}s)"
return 1
fi
sleep "${interval}"
elapsed=$((elapsed + interval))
echo -n "."
done
echo ""
success "Services healthy"
# Ensure migrations are current
ensure_migrations
}
ensure_migrations() {
log "Ensuring migrations are current..."
local migration_dir="${REPO_ROOT}/migrations"
if [[ ! -d "${migration_dir}" ]]; then
warn "No migrations directory. Skipping."
return 0
fi
if command -v sqlx &>/dev/null; then
DATABASE_URL="${DATABASE_URL}" sqlx migrate run --source "${migration_dir}" 2>/dev/null \
&& success "Migrations current" \
|| warn "sqlx migrate run failed — DB may be out of date"
else
# Fallback: apply all SQL files (idempotent if schema uses IF NOT EXISTS)
shopt -s nullglob
local sql_files=("${migration_dir}"/*.sql)
shopt -u nullglob
for sql_file in "${sql_files[@]}"; do
run_mysql_in_container < "${sql_file}" &>/dev/null || true
done
success "Migrations applied (mysql fallback)"
fi
}
# ---- Unit tests (no infra needed) -------------------------------------------
run_unit_tests() {
section "Unit Tests (no infra required)"
run_test_step "sprout-core tests" \
cargo test -p sprout-core --lib -- --nocapture
run_test_step "sprout-auth unit tests" \
cargo test -p sprout-auth --lib -- --nocapture
}
# ---- DB / integration tests (infra required) --------------------------------
run_integration_tests() {
section "Integration Tests (requires running services)"
ensure_services
run_test_step "sprout-db tests" \
cargo test -p sprout-db -- --nocapture
run_test_step "sprout-auth integration tests" \
cargo test -p sprout-auth --test '*' -- --nocapture 2>/dev/null || \
run_test_step "sprout-auth (no integration tests found)" true
run_test_step "workspace integration tests" \
cargo test --test '*' -- --nocapture 2>/dev/null || \
run_test_step "workspace integration tests (none found)" true
}
# ---- Main -------------------------------------------------------------------
START_TIME=$(date +%s)
case "${MODE}" in
unit)
run_unit_tests
;;
integration)
run_integration_tests
;;
all|*)
run_unit_tests
run_integration_tests
;;
esac
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
# ---- Summary ----------------------------------------------------------------
section "Test Summary"
echo ""
echo -e " Duration: ${ELAPSED}s"
echo ""
if [[ ${#PASSED[@]} -gt 0 ]]; then
echo -e " ${GREEN}Passed (${#PASSED[@]}):${NC}"
for t in "${PASSED[@]}"; do
echo -e " ${GREEN}${NC} ${t}"
done
fi
if [[ ${#FAILED[@]} -gt 0 ]]; then
echo ""
echo -e " ${RED}Failed (${#FAILED[@]}):${NC}"
for t in "${FAILED[@]}"; do
echo -e " ${RED}${NC} ${t}"
done
echo ""
exit 1
fi
echo ""
success "All tests passed! 🎉"
exit 0