2025-12-23 17:44:41 +01:00
|
|
|
import os
|
2026-02-14 04:45:00 +01:00
|
|
|
import re
|
2025-12-23 17:44:41 +01:00
|
|
|
import subprocess
|
2026-02-14 04:45:00 +01:00
|
|
|
import textwrap
|
2025-12-23 17:44:41 +01:00
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MATOMO_URL = os.environ.get("MATOMO_URL", "http://127.0.0.1:8080")
|
|
|
|
|
ADMIN_USER = os.environ.get("MATOMO_ADMIN_USER", "administrator")
|
|
|
|
|
ADMIN_PASSWORD = os.environ.get("MATOMO_ADMIN_PASSWORD", "AdminSecret123!")
|
|
|
|
|
ADMIN_EMAIL = os.environ.get("MATOMO_ADMIN_EMAIL", "administrator@example.org")
|
2026-02-14 04:45:00 +01:00
|
|
|
TOKEN_RE = re.compile(r"^[a-f0-9]{32,64}$")
|
2025-12-23 17:44:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMatomoBootstrapE2ENix(unittest.TestCase):
|
|
|
|
|
def test_bootstrap_creates_api_token_via_nix(self) -> None:
|
2026-02-14 04:45:00 +01:00
|
|
|
script = textwrap.dedent(
|
|
|
|
|
f"""\
|
|
|
|
|
set -eux
|
2025-12-23 17:44:41 +01:00
|
|
|
|
|
|
|
|
export NIX_CONFIG='experimental-features = nix-command flakes'
|
|
|
|
|
export TERM='xterm'
|
2026-02-14 04:45:00 +01:00
|
|
|
# Improve CI resilience for slow installer pages.
|
|
|
|
|
export MATOMO_INSTALLER_READY_TIMEOUT_S="${{MATOMO_INSTALLER_READY_TIMEOUT_S:-240}}"
|
|
|
|
|
export MATOMO_INSTALLER_STEP_TIMEOUT_S="${{MATOMO_INSTALLER_STEP_TIMEOUT_S:-45}}"
|
|
|
|
|
export MATOMO_INSTALLER_STEP_DEADLINE_S="${{MATOMO_INSTALLER_STEP_DEADLINE_S:-240}}"
|
2026-02-14 04:52:26 +01:00
|
|
|
export MATOMO_INSTALLER_TABLES_CREATION_TIMEOUT_S="${{MATOMO_INSTALLER_TABLES_CREATION_TIMEOUT_S:-240}}"
|
|
|
|
|
export MATOMO_INSTALLER_TABLES_ERASE_TIMEOUT_S="${{MATOMO_INSTALLER_TABLES_ERASE_TIMEOUT_S:-180}}"
|
2026-02-14 04:45:00 +01:00
|
|
|
export MATOMO_INSTALLER_DEBUG_DIR="${{MATOMO_INSTALLER_DEBUG_DIR:-/tmp/matomo-bootstrap}}"
|
2025-12-23 17:44:41 +01:00
|
|
|
|
|
|
|
|
# Make sure we have a writable HOME (compose already sets HOME=/tmp/home)
|
|
|
|
|
mkdir -p "$HOME" "$HOME/.cache" "$HOME/.config" "$HOME/.local/share"
|
|
|
|
|
|
|
|
|
|
# IMPORTANT:
|
|
|
|
|
# Nix flakes read the local repo as git+file:///work.
|
|
|
|
|
# Git refuses if the repo is not owned by the current user (root in the container).
|
|
|
|
|
# Mark it as safe explicitly.
|
|
|
|
|
git config --global --add safe.directory /work
|
|
|
|
|
|
2026-02-14 04:45:00 +01:00
|
|
|
# Preflight checks to surface "command not executable" failures (exit 126) clearly.
|
|
|
|
|
playwright_app="$(nix eval --raw .#apps.x86_64-linux.matomo-bootstrap-playwright-install.program)"
|
|
|
|
|
bootstrap_app="$(nix eval --raw .#apps.x86_64-linux.matomo-bootstrap.program)"
|
|
|
|
|
if [ -e "$playwright_app" ]; then
|
|
|
|
|
test -x "$playwright_app"
|
|
|
|
|
fi
|
|
|
|
|
if [ -e "$bootstrap_app" ]; then
|
|
|
|
|
test -x "$bootstrap_app"
|
|
|
|
|
fi
|
|
|
|
|
|
2025-12-23 17:44:41 +01:00
|
|
|
# 1) Install Playwright Chromium (cached in the container environment)
|
|
|
|
|
nix run --no-write-lock-file -L .#matomo-bootstrap-playwright-install
|
|
|
|
|
|
|
|
|
|
# 2) Run bootstrap (must print ONLY token)
|
|
|
|
|
nix run --no-write-lock-file -L .#matomo-bootstrap -- \\
|
|
|
|
|
--base-url '{MATOMO_URL}' \\
|
|
|
|
|
--admin-user '{ADMIN_USER}' \\
|
|
|
|
|
--admin-password '{ADMIN_PASSWORD}' \\
|
|
|
|
|
--admin-email '{ADMIN_EMAIL}' \\
|
|
|
|
|
--token-description 'e2e-test-token-nix'
|
|
|
|
|
"""
|
2026-02-14 04:45:00 +01:00
|
|
|
)
|
2025-12-23 17:44:41 +01:00
|
|
|
|
|
|
|
|
cmd = [
|
|
|
|
|
"docker",
|
|
|
|
|
"compose",
|
|
|
|
|
"-f",
|
|
|
|
|
"tests/e2e/docker-compose.yml",
|
|
|
|
|
"exec",
|
|
|
|
|
"-T",
|
|
|
|
|
"nix",
|
|
|
|
|
"sh",
|
|
|
|
|
"-lc",
|
|
|
|
|
script,
|
|
|
|
|
]
|
|
|
|
|
|
2026-02-14 04:45:00 +01:00
|
|
|
result = subprocess.run(
|
|
|
|
|
cmd,
|
|
|
|
|
check=False,
|
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
|
text=True,
|
|
|
|
|
)
|
|
|
|
|
if result.returncode != 0:
|
|
|
|
|
self.fail(
|
|
|
|
|
"nix bootstrap command failed\n"
|
|
|
|
|
f"exit={result.returncode}\n"
|
|
|
|
|
f"stdout:\n{result.stdout}\n"
|
|
|
|
|
f"stderr:\n{result.stderr}"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
stdout_lines = [
|
|
|
|
|
line.strip() for line in result.stdout.splitlines() if line.strip()
|
|
|
|
|
]
|
|
|
|
|
token = stdout_lines[-1] if stdout_lines else ""
|
|
|
|
|
self.assertRegex(
|
|
|
|
|
token,
|
|
|
|
|
TOKEN_RE,
|
|
|
|
|
f"Expected token on last stdout line, got stdout={result.stdout!r}",
|
|
|
|
|
)
|
2025-12-23 17:44:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
unittest.main()
|