142 lines
4.7 KiB
Python
142 lines
4.7 KiB
Python
"""Verify migrations are packaged into the wheel and discoverable post-install.
|
|
|
|
Critical (C1): without this, default-enabled persistence would silently
|
|
boot on an out-of-date schema after fresh install.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("uv") is None, reason="uv not on PATH")
|
|
def test_wheel_contains_v010_migration(tmp_path: Path) -> None:
|
|
"""`uv build --wheel` packages migrations/ as opensquilla/_migrations/."""
|
|
result = subprocess.run(
|
|
["uv", "build", "--wheel", "--out-dir", str(tmp_path)],
|
|
cwd=REPO_ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=180,
|
|
)
|
|
assert result.returncode == 0, f"uv build failed: {result.stderr}"
|
|
|
|
wheels = list(tmp_path.glob("opensquilla-*.whl"))
|
|
assert len(wheels) == 1, f"Expected 1 wheel, got {wheels}"
|
|
|
|
with zipfile.ZipFile(wheels[0]) as wheel:
|
|
names = wheel.namelist()
|
|
|
|
assert any(
|
|
n.endswith("opensquilla/_migrations/V010__meta_skill_runs.py") for n in names
|
|
), f"V010 missing from wheel; found: {[n for n in names if '_migrations' in n]}"
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("uv") is None, reason="uv not on PATH")
|
|
def test_installed_wheel_resolves_migrations(tmp_path: Path) -> None:
|
|
"""After pip-installing into a fresh venv, _resolve_migrations_dir() finds V010."""
|
|
venv_dir = tmp_path / "venv"
|
|
subprocess.run(
|
|
["uv", "venv", "--seed", str(venv_dir)],
|
|
cwd=REPO_ROOT,
|
|
check=True,
|
|
capture_output=True,
|
|
timeout=120,
|
|
)
|
|
pip = venv_dir / ("Scripts" if os.name == "nt" else "bin") / "pip"
|
|
py = venv_dir / ("Scripts" if os.name == "nt" else "bin") / "python"
|
|
|
|
wheel_dir = tmp_path / "dist"
|
|
subprocess.run(
|
|
["uv", "build", "--wheel", "--out-dir", str(wheel_dir)],
|
|
cwd=REPO_ROOT,
|
|
check=True,
|
|
capture_output=True,
|
|
timeout=180,
|
|
)
|
|
wheels = list(wheel_dir.glob("opensquilla-*.whl"))
|
|
# 120s was tight enough that Windows CI runners began timing out as
|
|
# the base dependency list grew (each transitive wheel adds I/O the
|
|
# Defender real-time scanner has to walk through). Ubuntu still
|
|
# completes in ~30s; Windows now needs ~90-150s. Bumping the budget
|
|
# rather than skipping preserves the test's intent — verify the
|
|
# built wheel installs cleanly into a fresh venv and the migration
|
|
# resolver finds V010 afterwards.
|
|
subprocess.run(
|
|
[str(pip), "install", str(wheels[0])],
|
|
check=True,
|
|
capture_output=True,
|
|
timeout=300,
|
|
)
|
|
|
|
result = subprocess.run(
|
|
[
|
|
str(py),
|
|
"-c",
|
|
(
|
|
"from opensquilla.gateway.boot import _resolve_migrations_dir;"
|
|
" d = _resolve_migrations_dir();"
|
|
" assert (d / 'V010__meta_skill_runs.py').exists(),"
|
|
" f'V010 missing in {d}';"
|
|
" print('OK', d)"
|
|
),
|
|
],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
)
|
|
assert result.returncode == 0, f"resolver failed: {result.stderr}"
|
|
assert "OK" in result.stdout
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("docker") is None, reason="docker not on PATH")
|
|
@pytest.mark.skipif(os.name == "nt", reason="docker smoke uses Linux container images")
|
|
@pytest.mark.skipif(
|
|
os.environ.get("OPENSQUILLA_SKIP_DOCKER_SMOKE") == "1",
|
|
reason="docker smoke disabled via env",
|
|
)
|
|
@pytest.mark.skipif(
|
|
os.environ.get("OPENSQUILLA_RUN_DOCKER_SMOKE") != "1",
|
|
reason="docker smoke is opt-in; it pulls external images",
|
|
)
|
|
def test_docker_image_resolves_migrations() -> None:
|
|
"""`docker build` + `docker run` resolves _migrations including V010.
|
|
|
|
Verifies (C1 v2): .dockerignore no longer excludes migrations/.
|
|
"""
|
|
tag = "opensquilla-test:meta-runs-persistence"
|
|
build = subprocess.run(
|
|
["docker", "build", "-t", tag, "."],
|
|
cwd=REPO_ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=600,
|
|
)
|
|
assert build.returncode == 0, f"docker build failed: {build.stderr[-2000:]}"
|
|
|
|
run = subprocess.run(
|
|
[
|
|
"docker", "run", "--rm", "--entrypoint", "python", tag,
|
|
"-c",
|
|
(
|
|
"from opensquilla.gateway.boot import _resolve_migrations_dir;"
|
|
" d = _resolve_migrations_dir();"
|
|
" assert (d / 'V010__meta_skill_runs.py').exists();"
|
|
" print('OK', d)"
|
|
),
|
|
],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
)
|
|
assert run.returncode == 0, f"docker run failed: {run.stderr}"
|
|
assert "OK" in run.stdout
|