From 5e5b6c893389fda388b891872243cc1743ccce9f Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Tue, 23 Dec 2025 17:44:41 +0100 Subject: [PATCH] fix(nix/e2e): keep Playwright install output off stdout - Build matomo-bootstrap with setuptools/wheel in Nix - Run playwright install via a dedicated pythonPlaywright env and redirect logs to stderr - Add Nix-based E2E path: nix runner service + persistent nix/home volumes + host networking - Add E2E test that runs bootstrap via `nix run` and asserts token-only stdout https://chatgpt.com/share/694ab489-7028-800f-8398-a19a99faffd0 --- flake.nix | 23 +++++++++---- tests/e2e/docker-compose.yml | 47 ++++++++++++++++++++++++++ tests/e2e/test_bootstrap_nix.py | 58 +++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 tests/e2e/test_bootstrap_nix.py diff --git a/flake.nix b/flake.nix index 4a58d72..1d7ee3a 100644 --- a/flake.nix +++ b/flake.nix @@ -23,12 +23,15 @@ pyproject = true; src = self; - # Runtime deps (Python) + nativeBuildInputs = with python.pkgs; [ + setuptools + wheel + ]; + propagatedBuildInputs = with python.pkgs; [ playwright ]; - # Optional: keep tests off in nix build by default doCheck = false; meta = with pkgs.lib; { @@ -46,16 +49,22 @@ apps = forAllSystems (system: let pkgs = import nixpkgs { inherit system; }; + python = pkgs.python312; + + pythonPlaywright = python.withPackages (ps: [ + ps.playwright + ]); + matomo = self.packages.${system}.matomo-bootstrap; playwright-install = pkgs.writeShellApplication { name = "matomo-bootstrap-playwright-install"; - runtimeInputs = [ matomo ]; + runtimeInputs = [ pythonPlaywright ]; + text = '' - # Installs the Playwright Chromium browser into the user cache. - # This is needed when the Matomo instance is not installed yet and - # the web installer must be driven via Playwright. - exec ${matomo}/bin/python -m playwright install chromium + # Install Playwright browsers. + # IMPORTANT: Do not print anything to stdout (tests expect token-only stdout). + exec ${pythonPlaywright}/bin/python -m playwright install chromium 1>&2 ''; }; in diff --git a/tests/e2e/docker-compose.yml b/tests/e2e/docker-compose.yml index df0019d..0ec7602 100644 --- a/tests/e2e/docker-compose.yml +++ b/tests/e2e/docker-compose.yml @@ -27,3 +27,50 @@ services: MATOMO_DATABASE_USERNAME: matomo MATOMO_DATABASE_PASSWORD: matomo_pw MATOMO_DATABASE_DBNAME: matomo + + nix: + image: nixos/nix:latest + container_name: e2e-nix + depends_on: + matomo: + condition: service_started + + # Run as root to avoid /nix big-lock permission issues + user: "0:0" + working_dir: /work + + volumes: + # Project root as flake + - ../../:/work:ro + + # Nix store (removed by docker compose down -v) + - e2e_nix_store:/nix + + # HOME/XDG for nix + playwright + - e2e_nix_home:/tmp/home + + environment: + NIX_CONFIG: "experimental-features = nix-command flakes" + TERM: "xterm" + + HOME: "/tmp/home" + USER: "root" + LOGNAME: "root" + XDG_CACHE_HOME: "/tmp/home/.cache" + XDG_CONFIG_HOME: "/tmp/home/.config" + XDG_DATA_HOME: "/tmp/home/.local/share" + + MATOMO_SITE_NAME: "Matomo E2E" + MATOMO_SITE_URL: "http://127.0.0.1:8080" + MATOMO_TIMEZONE: "Germany - Berlin" + + command: > + sh -lc "mkdir -p /tmp/home/.cache /tmp/home/.config /tmp/home/.local/share; + tail -f /dev/null" + + # Allow access to host-published Matomo port + network_mode: host + +volumes: + e2e_nix_store: + e2e_nix_home: diff --git a/tests/e2e/test_bootstrap_nix.py b/tests/e2e/test_bootstrap_nix.py new file mode 100644 index 0000000..1323c2c --- /dev/null +++ b/tests/e2e/test_bootstrap_nix.py @@ -0,0 +1,58 @@ +import os +import subprocess +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") + + +class TestMatomoBootstrapE2ENix(unittest.TestCase): + def test_bootstrap_creates_api_token_via_nix(self) -> None: + script = f"""set -euo pipefail + +export NIX_CONFIG='experimental-features = nix-command flakes' +export TERM='xterm' + +# 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 + +# 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' +""" + + cmd = [ + "docker", + "compose", + "-f", + "tests/e2e/docker-compose.yml", + "exec", + "-T", + "nix", + "sh", + "-lc", + script, + ] + + token = subprocess.check_output(cmd).decode().strip() + self.assertRegex(token, r"^[a-f0-9]{32,64}$") + + +if __name__ == "__main__": + unittest.main()