200 lines
10 KiB
Python
200 lines
10 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def test_unraid_template_documents_editable_runtime_settings() -> None:
|
|
template = (ROOT / "deploy" / "unraid" / "geointel-unraid-template.xml").read_text(encoding="utf-8")
|
|
|
|
assert "<Name>geointel</Name>" in template
|
|
assert "Belgium and Belgian North Sea workbench" in template
|
|
assert "<Repository>geointel-all-in-one:latest</Repository>" in template
|
|
assert "<WebUI>http://[IP]:[PORT:80]/</WebUI>" in template
|
|
assert "<Icon>http://192.168.10.150:1202/geointel-icon.png</Icon>" in template
|
|
assert "<ExtraParams>--add-host=host.docker.internal:host-gateway</ExtraParams>" in template
|
|
assert 'Target="80"' in template
|
|
assert 'Target="/app/storage"' in template
|
|
assert 'Target="/var/lib/postgresql/data"' in template
|
|
assert 'Target="GEOINTEL_POSTGRES_PASSWORD"' in template
|
|
assert 'Mask="true">change-me-before-shared-use</Config>' in template
|
|
|
|
|
|
def test_unraid_env_template_matches_single_container_compose_variables() -> None:
|
|
compose = (ROOT / "docker-compose.unraid.yml").read_text(encoding="utf-8")
|
|
env_template = (ROOT / "deploy" / "unraid" / "geointel.env.example").read_text(encoding="utf-8")
|
|
|
|
for key in (
|
|
"GEOINTEL_FRONTEND_PORT",
|
|
"GEOINTEL_STORAGE_PATH",
|
|
"GEOINTEL_POSTGIS_DATA_PATH",
|
|
"GEOINTEL_POSTGRES_DB",
|
|
"GEOINTEL_POSTGRES_USER",
|
|
"GEOINTEL_POSTGRES_PASSWORD",
|
|
"GEOINTEL_CORS_ORIGINS",
|
|
"GEOINTEL_MAX_UPLOAD_MB",
|
|
):
|
|
assert key in compose
|
|
assert f"{key}=" in env_template
|
|
|
|
assert "GEOINTEL_FRONTEND_PORT=1202" in env_template
|
|
assert "GEOINTEL_STORAGE_PATH=/mnt/user/appdata/geointel/storage" in env_template
|
|
assert "GEOINTEL_POSTGIS_DATA_PATH=/mnt/user/appdata/geointel/postgres-data" in env_template
|
|
assert "${GEOINTEL_POSTGIS_DATA_PATH:-geointel_postgis}:/var/lib/postgresql/data" in compose
|
|
assert "geointel_postgis:" in compose
|
|
assert "geointel:" in compose
|
|
assert "net.unraid.docker.managed: dockerman" in compose
|
|
assert 'net.unraid.docker.webui: "http://[IP]:[PORT:80]/"' in compose
|
|
assert 'net.unraid.docker.icon: "/boot/config/plugins/dockerMan/images/geointel-icon.png"' in compose
|
|
assert "db:" not in compose
|
|
assert "backend:" not in compose
|
|
assert "frontend:" not in compose
|
|
assert '"${GEOINTEL_FRONTEND_PORT:-1202}:80"' in compose
|
|
|
|
|
|
def test_unraid_template_exposes_every_operator_owned_runtime_setting() -> None:
|
|
run_script = (ROOT / "deploy" / "unraid" / "run-dockerman-container.sh").read_text(encoding="utf-8")
|
|
template = (ROOT / "deploy" / "unraid" / "geointel-unraid-template.xml").read_text(encoding="utf-8")
|
|
|
|
runtime_variables = set(
|
|
re.findall(r'^([A-Z][A-Z0-9_]+)="\$\{\1:-', run_script, flags=re.MULTILINE)
|
|
)
|
|
template_variables = set(re.findall(r'Target="([A-Z][A-Z0-9_]+)"', template))
|
|
bridged_or_internal = {
|
|
"GEOINTEL_FRONTEND_PORT",
|
|
"GEOINTEL_BACKUPS_PATH",
|
|
"GEOINTEL_CONTAINER_LOCK_FILE",
|
|
"GEOINTEL_IMAGE",
|
|
"GEOINTEL_MODELS_PATH",
|
|
"GEOINTEL_POSTGIS_DATA_PATH",
|
|
"GEOINTEL_STORAGE_PATH",
|
|
}
|
|
|
|
assert runtime_variables - template_variables == bridged_or_internal
|
|
assert 'Target="/app/models"' in template
|
|
|
|
|
|
def test_unraid_readme_explains_port_changes_and_safe_cleanup() -> None:
|
|
readme = (ROOT / "deploy" / "unraid" / "README.md").read_text(encoding="utf-8")
|
|
|
|
assert "cp deploy/unraid/geointel.env.example .env" in readme
|
|
assert "GEOINTEL_FRONTEND_PORT=1203" in readme
|
|
assert "docker build --build-arg GEOINTEL_INSTALL_AI=${GEOINTEL_INSTALL_AI:-false} -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest ." in readme
|
|
assert "bash deploy/unraid/run-dockerman-container.sh" in readme
|
|
assert "net.unraid.docker.managed=dockerman" in readme
|
|
assert "curl -fsS" in readme
|
|
assert "docker builder prune -af" in readme
|
|
assert "Avoid broad volume pruning" in readme
|
|
|
|
|
|
def test_unraid_all_in_one_runtime_starts_embedded_postgis_backend_and_nginx() -> None:
|
|
dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
|
|
start_script = (ROOT / "deploy" / "unraid" / "all-in-one-start.sh").read_text(encoding="utf-8")
|
|
dockerman_script = (ROOT / "deploy" / "unraid" / "run-dockerman-container.sh").read_text(encoding="utf-8")
|
|
nginx_config = (ROOT / "deploy" / "unraid" / "nginx-all-in-one.conf").read_text(encoding="utf-8")
|
|
dockerignore = (ROOT / ".dockerignore").read_text(encoding="utf-8")
|
|
|
|
assert "FROM postgres:16-bookworm AS runtime" in dockerfile
|
|
assert "postgresql-16-postgis-3" in dockerfile
|
|
assert "postgresql-16-postgis-3-scripts" in dockerfile
|
|
assert "ln -sf /usr/bin/python3.11 /usr/local/bin/python3" in dockerfile
|
|
assert "ln -sf /usr/bin/python3.11 /usr/bin/python3" in dockerfile
|
|
assert "/usr/bin/python3.11 -m venv /opt/geointel/venv" in dockerfile
|
|
assert "python3-pip" not in dockerfile
|
|
assert "python3-venv" in dockerfile
|
|
assert "COPY --from=frontend-build /frontend/dist/ /usr/share/nginx/html/" in dockerfile
|
|
assert "rm -f /etc/nginx/sites-enabled/default" in dockerfile
|
|
assert "GEOINTEL_POSTGRES_PASSWORD=" not in dockerfile
|
|
assert "GEOINTEL_POSTGRES_DB=" not in dockerfile
|
|
assert "GEOINTEL_POSTGRES_USER=" not in dockerfile
|
|
assert 'GEOINTEL_POSTGRES_PASSWORD="${GEOINTEL_POSTGRES_PASSWORD:-geointel}"' not in start_script
|
|
assert 'POSTGRES_PASSWORD="${GEOINTEL_POSTGRES_PASSWORD:-${POSTGRES_PASSWORD:-geointel}}"' in start_script
|
|
assert 'CMD ["/usr/local/bin/geointel-all-in-one-start"]' in dockerfile
|
|
assert "/usr/local/bin/docker-entrypoint.sh postgres &" in start_script
|
|
assert "python -m alembic upgrade head" in start_script
|
|
assert "uvicorn app.main:app --host 127.0.0.1 --port 8000 &" in start_script
|
|
assert 'exec nginx -g "daemon off;"' in start_script
|
|
assert "docker run -d" in dockerman_script
|
|
assert "--label net.unraid.docker.managed=dockerman" in dockerman_script
|
|
assert "migrate_compose_volume_if_needed" in dockerman_script
|
|
assert "docker rm -f geointel" in dockerman_script
|
|
assert "proxy_pass http://127.0.0.1:8000/api/" in nginx_config
|
|
assert "proxy_pass http://127.0.0.1:8000/health/ready" in nginx_config
|
|
assert "location = /geointel-icon.png" in nginx_config
|
|
assert "frontend/node_modules" in dockerignore
|
|
assert "storage" in dockerignore
|
|
assert "postgres-data" in dockerignore
|
|
|
|
|
|
def test_tower_deploy_uses_single_container_unraid_compose() -> None:
|
|
powershell = (ROOT / "scripts" / "deploy_tower.ps1").read_text(encoding="utf-8")
|
|
bash = (ROOT / "scripts" / "deploy_tower.sh").read_text(encoding="utf-8")
|
|
release_script = (ROOT / "deploy" / "unraid" / "deploy-release.sh").read_text(encoding="utf-8")
|
|
|
|
for script in (powershell, bash):
|
|
assert "bash deploy/unraid/deploy-release.sh" in script
|
|
|
|
assert "docker compose -f docker-compose.unraid.yml config" in release_script
|
|
assert "--build-arg GEOINTEL_INSTALL_AI=" in release_script
|
|
assert '--build-arg GEOINTEL_BUILD_SHA="$GEOINTEL_BUILD_SHA"' in release_script
|
|
assert '--build-arg GEOINTEL_BUILD_TIME="$GEOINTEL_BUILD_TIME"' in release_script
|
|
assert "-f deploy/unraid/Dockerfile.all-in-one" in release_script
|
|
assert '-t "$GEOINTEL_RELEASE_IMAGE"' in release_script
|
|
assert '-t "${GEOINTEL_IMAGE_REPOSITORY}:latest"' in release_script
|
|
assert 'GEOINTEL_IMAGE="$image" bash deploy/unraid/run-dockerman-container.sh' in release_script
|
|
assert "LIVE_SMOKE_CONTAINER=geointel bash scripts/live_migration_smoke.sh" in release_script
|
|
|
|
|
|
def test_tower_deploy_build_uses_remote_env_ai_setting_by_default() -> None:
|
|
powershell = (ROOT / "scripts" / "deploy_tower.ps1").read_text(encoding="utf-8")
|
|
bash = (ROOT / "scripts" / "deploy_tower.sh").read_text(encoding="utf-8")
|
|
release_script = (ROOT / "deploy" / "unraid" / "deploy-release.sh").read_text(encoding="utf-8")
|
|
|
|
for script in (powershell, bash):
|
|
assert "DEPLOY_GEOINTEL_INSTALL_AI" in script
|
|
assert "bash deploy/unraid/deploy-release.sh" in script
|
|
|
|
assert "if [ -f .env ]; then" in release_script
|
|
assert ". ./.env" in release_script
|
|
assert 'GEOINTEL_INSTALL_AI="${GEOINTEL_INSTALL_AI:-false}"' in release_script
|
|
assert "--build-arg GEOINTEL_INSTALL_AI=" in release_script
|
|
|
|
|
|
def test_powershell_tower_deploy_streams_remote_script_to_bash() -> None:
|
|
powershell = (ROOT / "scripts" / "deploy_tower.ps1").read_text(encoding="utf-8")
|
|
|
|
assert "[System.Text.UTF8Encoding]::new($false)" in powershell
|
|
assert "[System.IO.File]::WriteAllText($localScriptPath, $remoteScript, $utf8NoBom)" in powershell
|
|
assert "& scp @scpArgs" in powershell
|
|
assert "& ssh @sshRunArgs" in powershell
|
|
assert "bash '$remoteScriptPath'" in powershell
|
|
assert "rm -f '$remoteScriptPath'" in powershell
|
|
assert "REMOTE_PATH='$RemotePath'" in powershell
|
|
assert "DEPLOY_GEOINTEL_INSTALL_AI='$InstallAi'" in powershell
|
|
|
|
|
|
def test_live_migration_smoke_supports_dockerman_native_container() -> None:
|
|
script = (ROOT / "scripts" / "live_migration_smoke.sh").read_text(encoding="utf-8")
|
|
|
|
assert 'LIVE_SMOKE_CONTAINER="${LIVE_SMOKE_CONTAINER:-}"' in script
|
|
assert "run_container_smoke()" in script
|
|
assert 'docker exec -i "$container_name" sh' in script
|
|
|
|
|
|
def test_frontend_and_unraid_icon_assets_are_present() -> None:
|
|
deploy_icon = (ROOT / "deploy" / "unraid" / "geointel-icon.svg").read_text(encoding="utf-8")
|
|
frontend_icon = (ROOT / "frontend" / "public" / "geointel-icon.svg").read_text(encoding="utf-8")
|
|
deploy_png = ROOT / "deploy" / "unraid" / "geointel-icon.png"
|
|
frontend_png = ROOT / "frontend" / "public" / "geointel-icon.png"
|
|
index = (ROOT / "frontend" / "index.html").read_text(encoding="utf-8")
|
|
|
|
assert "<svg" in deploy_icon
|
|
assert "GeoIntel Kempen" in deploy_icon
|
|
assert deploy_icon == frontend_icon
|
|
assert deploy_png.read_bytes() == frontend_png.read_bytes()
|
|
assert deploy_png.stat().st_size > 1000
|
|
assert '<link rel="icon" type="image/svg+xml" href="/geointel-icon.svg" />' in index
|