Some checks failed
CI / test (push) Has been cancelled
- Add Dockerfile based on pinned Playwright image (v1.46.0-jammy) for reproducible browser runtime - Introduce docker-compose stack (MariaDB + Matomo + one-shot bootstrap) - Extend Makefile with container image and stack management targets - Add env.sample for environment-driven bootstrap configuration - Relax Playwright dependency to >=1.46.0 to keep Nix builds compatible - Add E2E test ensuring docker-compose bootstrap exits with 0 and prints token
107 lines
3.1 KiB
Python
107 lines
3.1 KiB
Python
import subprocess
|
|
import time
|
|
import unittest
|
|
|
|
|
|
COMPOSE_FILE = "tests/e2e/docker-compose.yml"
|
|
|
|
|
|
def run(cmd: list[str], check: bool = False) -> subprocess.CompletedProcess:
|
|
return subprocess.run(
|
|
cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
check=check,
|
|
)
|
|
|
|
|
|
def wait_http_any(url: str, timeout_s: int = 180) -> None:
|
|
# "any HTTP code" reachability via curl:
|
|
# curl exits 0 on 2xx, non-zero on 4xx/5xx; so we just wait for any response code != 000
|
|
deadline = time.time() + timeout_s
|
|
while time.time() < deadline:
|
|
p = run(
|
|
[
|
|
"curl",
|
|
"-sS",
|
|
"-o",
|
|
"/dev/null",
|
|
"-w",
|
|
"%{http_code}",
|
|
"--max-time",
|
|
"2",
|
|
url,
|
|
]
|
|
)
|
|
code = (p.stdout or "").strip()
|
|
if code and code != "000":
|
|
return
|
|
time.sleep(1)
|
|
raise RuntimeError(f"Matomo did not become reachable: {url}")
|
|
|
|
|
|
class TestComposeBootstrapExit0(unittest.TestCase):
|
|
def test_bootstrap_exits_zero(self) -> None:
|
|
compose = ["docker", "compose", "-f", COMPOSE_FILE]
|
|
|
|
try:
|
|
# clean slate
|
|
run(compose + ["down", "-v"])
|
|
|
|
# start db + matomo (+ nix if present)
|
|
up = run(compose + ["up", "-d"])
|
|
self.assertEqual(
|
|
up.returncode,
|
|
0,
|
|
msg=f"compose up failed\nSTDOUT:\n{up.stdout}\nSTDERR:\n{up.stderr}",
|
|
)
|
|
|
|
# wait for host-published matomo port
|
|
wait_http_any("http://127.0.0.1:8080/", timeout_s=180)
|
|
|
|
# IMPORTANT:
|
|
# Run bootstrap via Nix container already defined in tests/e2e/docker-compose.yml
|
|
# (this avoids host python/venv completely).
|
|
script = r"""set -euo pipefail
|
|
|
|
export NIX_CONFIG='experimental-features = nix-command flakes'
|
|
export TERM='xterm'
|
|
mkdir -p "$HOME" "$HOME/.cache" "$HOME/.config" "$HOME/.local/share"
|
|
|
|
# Mark repo safe (root in container)
|
|
git config --global --add safe.directory /work
|
|
|
|
# Install browsers (cached in container volumes)
|
|
nix run --no-write-lock-file -L .#matomo-bootstrap-playwright-install >/dev/null
|
|
|
|
# Run bootstrap (must exit 0; stdout should be token-only)
|
|
nix run --no-write-lock-file -L .#matomo-bootstrap -- \
|
|
--base-url 'http://127.0.0.1:8080' \
|
|
--admin-user 'administrator' \
|
|
--admin-password 'AdminSecret123!' \
|
|
--admin-email 'administrator@example.org' \
|
|
--token-description 'e2e-compose-exit0'
|
|
"""
|
|
|
|
boot = run(compose + ["exec", "-T", "nix", "sh", "-lc", script])
|
|
self.assertEqual(
|
|
boot.returncode,
|
|
0,
|
|
msg=f"bootstrap failed\nSTDOUT:\n{boot.stdout}\nSTDERR:\n{boot.stderr}",
|
|
)
|
|
|
|
token = (boot.stdout or "").strip()
|
|
self.assertRegex(
|
|
token,
|
|
r"^[a-f0-9]{32,64}$",
|
|
msg=f"expected token on stdout; got: {token!r}\nSTDERR:\n{boot.stderr}",
|
|
)
|
|
|
|
finally:
|
|
run(compose + ["down", "-v"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|