2026-04-14 19:04:48 +00:00
|
|
|
"""
|
|
|
|
|
Shared test server constants for use in individual test files.
|
|
|
|
|
|
|
|
|
|
Instead of hardcoding ``BASE = "http://127.0.0.1:8788"`` in every test file,
|
|
|
|
|
import from here so the port and state dir are always consistent with
|
|
|
|
|
what conftest.py computed for this worktree.
|
|
|
|
|
|
|
|
|
|
Usage::
|
|
|
|
|
|
|
|
|
|
from tests._pytest_port import BASE
|
|
|
|
|
|
|
|
|
|
conftest.py publishes ``HERMES_WEBUI_TEST_PORT`` and
|
|
|
|
|
``HERMES_WEBUI_TEST_STATE_DIR`` to ``os.environ`` at module level
|
|
|
|
|
(before any test file is imported), so this module always reads the
|
|
|
|
|
correct values. The auto-derivation fallback matches conftest's logic
|
|
|
|
|
exactly, so standalone imports also work correctly.
|
|
|
|
|
"""
|
|
|
|
|
import hashlib
|
|
|
|
|
import os
|
|
|
|
|
import pathlib
|
|
|
|
|
|
|
|
|
|
def _auto_test_port(repo_root: pathlib.Path) -> int:
|
|
|
|
|
h = int(hashlib.md5(str(repo_root).encode()).hexdigest(), 16)
|
|
|
|
|
return 20000 + (h % 10000)
|
|
|
|
|
|
|
|
|
|
def _auto_state_dir_name(repo_root: pathlib.Path) -> str:
|
|
|
|
|
h = hashlib.md5(str(repo_root).encode()).hexdigest()[:8]
|
|
|
|
|
return f"webui-test-{h}"
|
|
|
|
|
|
|
|
|
|
_TESTS_DIR = pathlib.Path(__file__).parent.resolve()
|
|
|
|
|
_REPO_ROOT = _TESTS_DIR.parent.resolve()
|
|
|
|
|
|
|
|
|
|
TEST_PORT = int(os.environ.get('HERMES_WEBUI_TEST_PORT',
|
|
|
|
|
str(_auto_test_port(_REPO_ROOT))))
|
|
|
|
|
BASE = f"http://127.0.0.1:{TEST_PORT}"
|
|
|
|
|
|
2026-06-16 02:04:16 +00:00
|
|
|
# Test state dir: prefer the value conftest.py published to the environment.
|
|
|
|
|
# The standalone fallback anchors under the OS temp dir (NOT ~/.hermes) so test
|
|
|
|
|
# state is never created inside the production Hermes home — matching conftest's
|
|
|
|
|
# hard-isolation default. (See conftest.py TEST_STATE_DIR.)
|
|
|
|
|
import tempfile as _tempfile
|
|
|
|
|
_TEST_STATE_ROOT = pathlib.Path(
|
|
|
|
|
os.environ.get('HERMES_WEBUI_TEST_STATE_ROOT', _tempfile.gettempdir())
|
|
|
|
|
) / 'hermes-webui-tests'
|
2026-04-14 19:04:48 +00:00
|
|
|
TEST_STATE_DIR = pathlib.Path(os.environ.get(
|
|
|
|
|
'HERMES_WEBUI_TEST_STATE_DIR',
|
2026-06-16 02:04:16 +00:00
|
|
|
str(_TEST_STATE_ROOT / _auto_state_dir_name(_REPO_ROOT))
|
|
|
|
|
)).resolve()
|
|
|
|
|
|
|
|
|
|
# Defense-in-depth: mirror conftest.py's production-proximity guard so a
|
|
|
|
|
# standalone import (without conftest) can't resolve a state dir inside the real
|
|
|
|
|
# ~/.hermes either. Same logic: trip only if under literal ~/.hermes and the temp
|
|
|
|
|
# root isn't itself under production.
|
|
|
|
|
_PROD_HERMES_HOME = (pathlib.Path.home() / '.hermes').resolve()
|
|
|
|
|
_TEMP_ROOT = pathlib.Path(_tempfile.gettempdir()).resolve()
|
|
|
|
|
_temp_root_is_safe = not (
|
|
|
|
|
_TEMP_ROOT == _PROD_HERMES_HOME or _PROD_HERMES_HOME in _TEMP_ROOT.parents
|
|
|
|
|
)
|
|
|
|
|
_under_temp = _temp_root_is_safe and (
|
|
|
|
|
TEST_STATE_DIR == _TEMP_ROOT or _TEMP_ROOT in TEST_STATE_DIR.parents
|
|
|
|
|
)
|
|
|
|
|
_under_prod = TEST_STATE_DIR == _PROD_HERMES_HOME or _PROD_HERMES_HOME in TEST_STATE_DIR.parents
|
|
|
|
|
if _under_prod and not _under_temp:
|
|
|
|
|
raise RuntimeError(
|
|
|
|
|
f"REFUSING TO RUN: test state dir {TEST_STATE_DIR} is inside the production "
|
|
|
|
|
f"Hermes home {_PROD_HERMES_HOME}. Tests must never touch production files."
|
|
|
|
|
)
|
2026-04-21 02:25:14 +00:00
|
|
|
|
|
|
|
|
# Default model injected by conftest — tests that mutate the default model
|
|
|
|
|
# must restore to this value so later tests see a consistent baseline.
|
|
|
|
|
TEST_DEFAULT_MODEL = os.environ.get('HERMES_WEBUI_DEFAULT_MODEL', 'openai/gpt-5.4-mini')
|