firegex/tests/standalone/conftest.py
2026-09-13 15:54:56 +02:00

81 lines
2.9 KiB
Python

"""Tests that restart the instance they are testing.
Some settings are read **once**, at process startup — the IP allowlist, the proxy header
it trusts, whether authentication is asked for at boot — so there is no way to exercise
them against a running instance. These drive `run.py stop`/`start` themselves for each
scenario, which is why they are not collected by default (`pytest.ini`'s `testpaths` does
not include this directory) and have to be asked for by name:
pytest standalone
Expect them to bounce whatever firegex you have running, and to leave an unrestricted one
behind at the end. They have to run on the same host firegex runs on, with whatever
`run.py` itself needs.
"""
import os
import subprocess
import time
import pytest
import requests
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
BASE = "http://127.0.0.1:4444/"
PASSWORD = "testpassword"
def run_py(*args, timeout=180) -> int:
return subprocess.run(["python3", "run.py", *args], cwd=REPO_ROOT,
timeout=timeout).returncode
def wait_ready(timeout: float = 90) -> bool:
"""A 403 counts as ready: it means the app answered, unlike a connection error.
`/api/status` is the endpoint being probed, and under a restrictive allowlist the
correct answer to it *is* a refusal.
"""
deadline = time.time() + timeout
while time.time() < deadline:
try:
if requests.get(BASE + "api/status", timeout=2).status_code in (200, 403):
return True
except requests.RequestException:
pass
time.sleep(1)
return False
@pytest.fixture(scope="module")
def restart():
"""Bring firegex up with a given configuration, and leave an unrestricted one behind.
The cleanup is not tidiness: every other test module in this suite assumes it can
reach the instance from loopback with a password, and a run that stopped halfway
through a restrictive scenario would break all of them.
"""
def _restart(allowed_ips=None, proxy_ip_header=None, unsafe_disable_auth=None):
run_py("stop")
args = ["start", "-P", PASSWORD]
# An empty string still has to be passed explicitly, to clear a previous value.
if allowed_ips is not None:
args += ["--allowed-ips", allowed_ips]
if proxy_ip_header is not None:
args += ["--proxy-ip-header", proxy_ip_header]
if unsafe_disable_auth is not None:
args += ["--unsafe-disable-auth" if unsafe_disable_auth
else "--no-unsafe-disable-auth"]
run_py(*args)
assert wait_ready(), "firegex did not come back up after the restart"
yield _restart
_restart(allowed_ips="", unsafe_disable_auth=False)
@pytest.fixture(scope="session", autouse=True)
def only_on_the_host_that_runs_it():
if not os.path.isfile(os.path.join(REPO_ROOT, "run.py")):
pytest.skip("these have to run from a clone, on the host firegex runs on")