diff --git a/tests/README.md b/tests/README.md index 83e2c10c2..eabae6c61 100644 --- a/tests/README.md +++ b/tests/README.md @@ -15,6 +15,14 @@ reference; that file is the standard the refactor works toward. ## Running focused subsets (taxonomy markers) +The shared static-server fixture defaults to loopback port 7011 and refuses an +occupied port rather than reusing another checkout's server. For focused tests +that do not load that fixed browser URL, use `ODYSSEUS_TEST_STATIC_PORT=0` to +allocate an ephemeral port. This permits direct subprocess/isolation tests on a +host already serving the application without stopping or changing that service. +Browser tests that hard-code port 7011 still need that port in their own isolated +network namespace; do not run them against an unrelated live server. + `tests/conftest.py` tags every test at collection time with two markers derived from its filename by `tests/_taxonomy.py`: an `area_*` marker (e.g. `area_security`) and a finer `sub_*` marker (e.g. `sub_owner_scope`). This adds diff --git a/tests/conftest.py b/tests/conftest.py index 3dab8dbd1..d4eb0a930 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -98,21 +98,25 @@ def pytest_collection_modifyitems(config, items): @pytest.fixture(scope="session", autouse=True) def _serve_test_static(): - """Ensure static assets are available on loopback port 7011 for browser integration tests.""" + """Serve this worktree's assets; non-browser runs can request an ephemeral port.""" import socket import threading import http.server import socketserver from pathlib import Path + port = int(os.environ.get("ODYSSEUS_TEST_STATIC_PORT", "7011")) + if not 0 <= port <= 65535: + raise ValueError("ODYSSEUS_TEST_STATIC_PORT must be between 0 and 65535") + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: - is_bound = (sock.connect_ex(("127.0.0.1", 7011)) == 0) + is_bound = (sock.connect_ex(("127.0.0.1", port)) == 0) if port else False finally: sock.close() if is_bound: - raise RuntimeError("port 7011 is already in use; browser tests require this worktree's static server") + raise RuntimeError(f"port {port} is already in use; browser tests require this worktree's static server") root_dir = Path(__file__).resolve().parent.parent @@ -133,7 +137,7 @@ def _serve_test_static(): class _Server(socketserver.TCPServer): allow_reuse_address = True - server = _Server(("127.0.0.1", 7011), _Handler) + server = _Server(("127.0.0.1", port), _Handler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() try: