174 lines
6.1 KiB
Bash
174 lines
6.1 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$ROOT_DIR"
|
|
|
|
TEST_COMMAND="${TEST_COMMAND:-composer test:unit}"
|
|
SOURCE_TARGET="${SOURCE_TARGET:-}"
|
|
SOURCE_HOST="${SOURCE_HOST:-${CONFIG_DB_HOST:-}}"
|
|
SOURCE_PORT="${SOURCE_PORT:-${CONFIG_DB_PORT:-3306}}"
|
|
SOURCE_DATABASE="${SOURCE_DATABASE:-${CONFIG_DB_DATABASE:-}}"
|
|
SOURCE_USER="${SOURCE_USER:-${CONFIG_DB_USER:-}}"
|
|
SOURCE_PASSWORD="${SOURCE_PASSWORD:-${CONFIG_DB_PASSWORD:-}}"
|
|
NETWORK_NAME="${NETWORK_NAME:-api-test-net}"
|
|
DB_CONTAINER_NAME="${DB_CONTAINER_NAME:-api-test-db}"
|
|
REDIS_CONTAINER_NAME="${REDIS_CONTAINER_NAME:-api-test-redis}"
|
|
PHP_IMAGE="${PHP_IMAGE:-api-php-test-runner}"
|
|
CLONE_DATABASE="${CLONE_DATABASE:-}"
|
|
CLONE_ROOT_PASSWORD="${CLONE_ROOT_PASSWORD:-test_root_password}"
|
|
SKIP_BUILD="${SKIP_BUILD:-0}"
|
|
FORCE_BUILD="${FORCE_BUILD:-0}"
|
|
SKIP_TESTS="${SKIP_TESTS:-0}"
|
|
KEEP_CONTAINERS="${KEEP_CONTAINERS:-0}"
|
|
FORCE="${FORCE:-0}"
|
|
|
|
if [[ -f ".env" ]]; then
|
|
# shellcheck disable=SC2046
|
|
export $(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' .env | sed 's/\r$//')
|
|
SOURCE_TARGET="${SOURCE_TARGET:-${CONFIG_DB_TARGET:-}}"
|
|
fi
|
|
|
|
SOURCE_TARGET="${SOURCE_TARGET:-live}"
|
|
SOURCE_TARGET="$(echo "${SOURCE_TARGET}" | tr '[:upper:]' '[:lower:]')"
|
|
if [[ "${SOURCE_TARGET}" != "live" && "${SOURCE_TARGET}" != "debug" ]]; then
|
|
SOURCE_TARGET="live"
|
|
fi
|
|
|
|
if [[ "${SOURCE_TARGET}" == "debug" ]]; then
|
|
SOURCE_HOST="${SOURCE_HOST:-${CONFIG_DB_DEBUG_HOST:-${CONFIG_DB_HOST:-}}}"
|
|
SOURCE_DATABASE="${SOURCE_DATABASE:-${CONFIG_DB_DEBUG_DATABASE:-${CONFIG_DB_DATABASE:-}}}"
|
|
SOURCE_USER="${SOURCE_USER:-${CONFIG_DB_DEBUG_USER:-${CONFIG_DB_USER:-}}}"
|
|
SOURCE_PASSWORD="${SOURCE_PASSWORD:-${CONFIG_DB_DEBUG_PASSWORD:-${CONFIG_DB_PASSWORD:-}}}"
|
|
else
|
|
SOURCE_HOST="${SOURCE_HOST:-${CONFIG_DB_HOST:-}}"
|
|
SOURCE_DATABASE="${SOURCE_DATABASE:-${CONFIG_DB_DATABASE:-}}"
|
|
SOURCE_USER="${SOURCE_USER:-${CONFIG_DB_USER:-}}"
|
|
SOURCE_PASSWORD="${SOURCE_PASSWORD:-${CONFIG_DB_PASSWORD:-}}"
|
|
fi
|
|
|
|
if [[ -z "${SOURCE_HOST}" || -z "${SOURCE_DATABASE}" || -z "${SOURCE_USER}" || -z "${SOURCE_PASSWORD}" ]]; then
|
|
echo "Missing source DB credentials for target '${SOURCE_TARGET}'. Set CONFIG_DB_TARGET and CONFIG_DB_* / CONFIG_DB_DEBUG_* in .env or env vars."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "${CLONE_DATABASE}" ]]; then
|
|
CLONE_DATABASE="${SOURCE_DATABASE}_test_clone"
|
|
fi
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
echo "Docker is required but was not found in PATH."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${FORCE}" != "1" ]]; then
|
|
echo "This will clone data from the '${SOURCE_TARGET}' database target into a local Docker MySQL container."
|
|
read -r -p "Type CLONE to continue: " confirmation
|
|
if [[ "${confirmation}" != "CLONE" ]]; then
|
|
echo "Cancelled."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
remove_container_if_exists() {
|
|
local name="$1"
|
|
if docker ps -aq --filter "name=^${name}$" | grep -q .; then
|
|
docker rm -f "${name}" >/dev/null
|
|
fi
|
|
}
|
|
|
|
if [[ "${SKIP_BUILD}" != "1" ]]; then
|
|
if docker image inspect "${PHP_IMAGE}" >/dev/null 2>&1 && [[ "${FORCE_BUILD}" != "1" ]]; then
|
|
echo "Using cached PHP test image (${PHP_IMAGE}). Set FORCE_BUILD=1 to rebuild."
|
|
else
|
|
echo "Building PHP test image (${PHP_IMAGE})..."
|
|
docker build -f services/php/Dockerfile -t "${PHP_IMAGE}" .
|
|
fi
|
|
fi
|
|
|
|
if ! docker network ls --format '{{.Name}}' | grep -qx "${NETWORK_NAME}"; then
|
|
echo "Creating docker network ${NETWORK_NAME}..."
|
|
docker network create "${NETWORK_NAME}" >/dev/null
|
|
fi
|
|
|
|
echo "Resetting test containers..."
|
|
remove_container_if_exists "${DB_CONTAINER_NAME}"
|
|
remove_container_if_exists "${REDIS_CONTAINER_NAME}"
|
|
|
|
echo "Starting cloned MySQL container (${DB_CONTAINER_NAME})..."
|
|
docker run -d \
|
|
--name "${DB_CONTAINER_NAME}" \
|
|
--network "${NETWORK_NAME}" \
|
|
-e "MYSQL_ROOT_PASSWORD=${CLONE_ROOT_PASSWORD}" \
|
|
-e "MYSQL_DATABASE=${CLONE_DATABASE}" \
|
|
mysql:8.4 >/dev/null
|
|
|
|
for i in $(seq 1 60); do
|
|
if docker exec -e "MYSQL_PWD=${CLONE_ROOT_PASSWORD}" "${DB_CONTAINER_NAME}" sh -lc "mysqladmin -u root ping --silent" >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
if [[ "$i" -eq 60 ]]; then
|
|
echo "Timed out waiting for ${DB_CONTAINER_NAME} to be ready."
|
|
exit 1
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "Cloning '${SOURCE_TARGET}' database ${SOURCE_DATABASE} from ${SOURCE_HOST} into ${DB_CONTAINER_NAME}/${CLONE_DATABASE}..."
|
|
DUMP_DIR="${ROOT_DIR}/.tmp-db-clone"
|
|
DUMP_FILE="${DUMP_DIR}/dump.sql"
|
|
mkdir -p "${DUMP_DIR}"
|
|
rm -f "${DUMP_FILE}"
|
|
|
|
docker run --rm \
|
|
-e "MYSQL_PWD=${SOURCE_PASSWORD}" \
|
|
-v "${DUMP_DIR}:/dump" \
|
|
mysql:8.4 \
|
|
sh -lc "exec mysqldump --compress --single-transaction --quick --set-gtid-purged=OFF -h '${SOURCE_HOST}' -P '${SOURCE_PORT}' -u '${SOURCE_USER}' '${SOURCE_DATABASE}' > /dump/dump.sql"
|
|
|
|
if [[ ! -f "${DUMP_FILE}" ]]; then
|
|
echo "Database dump failed."
|
|
exit 1
|
|
fi
|
|
|
|
docker run --rm \
|
|
--network "${NETWORK_NAME}" \
|
|
-e "MYSQL_PWD=${CLONE_ROOT_PASSWORD}" \
|
|
-v "${DUMP_DIR}:/dump" \
|
|
mysql:8.4 \
|
|
sh -lc "exec mysql -h '${DB_CONTAINER_NAME}' -u root '${CLONE_DATABASE}' < /dump/dump.sql"
|
|
|
|
rm -f "${DUMP_FILE}"
|
|
|
|
echo "Starting isolated Redis container (${REDIS_CONTAINER_NAME})..."
|
|
docker run -d --name "${REDIS_CONTAINER_NAME}" --network "${NETWORK_NAME}" redis:7 >/dev/null
|
|
|
|
if [[ "${SKIP_TESTS}" != "1" ]]; then
|
|
echo "Running tests in a separate PHP container against cloned DB..."
|
|
docker run --rm \
|
|
--network "${NETWORK_NAME}" \
|
|
--env-file "${ROOT_DIR}/.env" \
|
|
-e "CONFIG_DB_HOST=${DB_CONTAINER_NAME}" \
|
|
-e "CONFIG_DB_DATABASE=${CLONE_DATABASE}" \
|
|
-e "CONFIG_DB_USER=root" \
|
|
-e "CONFIG_DB_PASSWORD=${CLONE_ROOT_PASSWORD}" \
|
|
-e "REDIS_CONFIG_HOST=${REDIS_CONTAINER_NAME}" \
|
|
-e "AUTO_COMPOSER_INSTALL=false" \
|
|
-v "${ROOT_DIR}/services/nginx/app:/var/www/html" \
|
|
-v "${ROOT_DIR}/services/php/php.ini:/usr/local/etc/php/conf.d/zz-custom.ini:ro" \
|
|
"${PHP_IMAGE}" \
|
|
sh -lc "cd /var/www/html && if [ ! -f vendor/autoload.php ]; then composer install --no-interaction --prefer-dist; fi && ${TEST_COMMAND}"
|
|
fi
|
|
|
|
if [[ "${KEEP_CONTAINERS}" != "1" ]]; then
|
|
echo "Cleaning up test containers..."
|
|
remove_container_if_exists "${REDIS_CONTAINER_NAME}"
|
|
remove_container_if_exists "${DB_CONTAINER_NAME}"
|
|
else
|
|
echo "Keeping containers for inspection:"
|
|
echo " DB: ${DB_CONTAINER_NAME}"
|
|
echo " Redis: ${REDIS_CONTAINER_NAME}"
|
|
fi
|
|
|
|
echo "Done."
|