test: make tests/ mirror the source tree; drop issue numbers from filenames
`scripts/run_tests.sh tests/<dir>/` is how a change gets its regression
coverage run, so a test filed under the wrong directory is a test nobody
runs when that code changes. Two kinds of drift had accumulated.
Parallel directories for one source package, folded into the mirror:
tests/acp -> tests/acp_adapter (its __init__/conftest move with it)
tests/cli -> tests/hermes_cli (prompt_toolkit fixture merged into
hermes_cli/conftest.py)
tests/run_agent -> tests/agent (backoff fixture becomes
agent/conftest.py)
tests/relay -> tests/gateway/relay
tests/state -> tests/hermes_state
246 loose files at tests/ root, routed by the package they import/patch:
hermes_cli, hermes_state, agent, gateway, tools, plugins, tui_gateway, cron.
Installer and desktop-update script tests go to tests/scripts/{install,
desktop_update}/. 43 tests of root-level modules (batch_runner, utils,
hermes_constants, packaging) stay at the root.
Filenames drop their issue numbers (95 files: test_89315_x.py -> test_x.py);
the number stays in the module docstring where it has context.
Collisions: test_cli_skin_integration.py existed in both tests/ and tests/cli
with different subsets — merged into one (10 tests, all kept);
run_agent/test_pre_compress_memory_context.py -> agent/..._handoff.py;
tests/test_account_usage.py -> agent/test_account_usage_fetch.py;
tests/test_web_server.py -> hermes_cli/test_web_server_ws_ping.py.
Deleted: test_minisweagent_path.py (empty since PR #2804),
test_model_picker_scroll.py (tested a private copy of the logic, imported
nothing), test_process_loop_event_loop_warning.py (asserted asyncio behaviour,
imported nothing from Hermes).
Repo-root path arithmetic (Path(__file__).parents[N], dirname chains) is
bumped for the 202 files that changed depth and verified by evaluating every
such expression against the new location. classify_changes' desktop-updater
lane prefix, tests-os.yml's ignore glob and every in-tree path comment follow
the moves. tests/test_tests_tree_layout.py keeps the tree from drifting back.
This commit is contained in:
@@ -1,110 +0,0 @@
|
||||
"""Regression: installer update should discard pure npm lockfile churn.
|
||||
|
||||
Desktop/bootstrap installs update an existing managed checkout in place. Local
|
||||
build steps often rewrite tracked ``package-lock.json`` without touching the
|
||||
matching ``package.json``; treating that churn as a real local edit forces an
|
||||
autostash and can abort the repository stage before the desktop comes back up.
|
||||
|
||||
The installer should discard that generated churn before its stash/checkout
|
||||
logic, while still preserving intentional package edits where ``package.json``
|
||||
and ``package-lock.json`` changed together.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
INSTALL_SH = REPO_ROOT / "scripts" / "install.sh"
|
||||
INSTALL_PS1 = REPO_ROOT / "scripts" / "install.ps1"
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
shutil.which("git") is None or shutil.which("bash") is None,
|
||||
reason="needs git and bash",
|
||||
)
|
||||
|
||||
|
||||
def _git(cwd: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(
|
||||
["git", "-c", "user.email=t@t", "-c", "user.name=t", *args],
|
||||
cwd=cwd,
|
||||
check=check,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
def _extract_install_sh_function(name: str) -> str:
|
||||
text = INSTALL_SH.read_text()
|
||||
match = re.search(rf"{name}\(\) \{{.*?\n\}}", text, re.DOTALL)
|
||||
assert match is not None, f"{name}() not found in install.sh"
|
||||
return match.group(0)
|
||||
|
||||
|
||||
def _extract_install_sh_autostash_block() -> str:
|
||||
text = INSTALL_SH.read_text()
|
||||
match = re.search(
|
||||
r'local autostash_ref="".*?\n fi\n',
|
||||
text,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match is not None, "autostash block not found in install.sh"
|
||||
return match.group(0)
|
||||
|
||||
|
||||
@pytest.mark.live_system_guard_bypass
|
||||
def test_install_sh_discards_runtime_lockfile_churn_before_stash(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
repo = tmp_path / "hermes-agent"
|
||||
repo.mkdir()
|
||||
_git(repo, "init")
|
||||
(repo / "package.json").write_text('{"dependencies":{"a":"1"}}\n')
|
||||
(repo / "package-lock.json").write_text('{"lock":"old"}\n')
|
||||
_git(repo, "add", "package.json", "package-lock.json")
|
||||
_git(repo, "commit", "-m", "init")
|
||||
|
||||
(repo / "package-lock.json").write_text('{"lock":"runtime-churn"}\n')
|
||||
|
||||
script = (
|
||||
"set -e\n"
|
||||
'log_info() { echo "INFO: $*"; }\n'
|
||||
'INSTALL_DIR="$PWD"\n'
|
||||
f"{_extract_install_sh_function('discard_update_lockfile_churn')}\n"
|
||||
"run() {\n"
|
||||
f"{_extract_install_sh_autostash_block()}"
|
||||
"}\n"
|
||||
"run\n"
|
||||
)
|
||||
res = subprocess.run(
|
||||
["bash", "-c", script], cwd=repo, capture_output=True, text=True
|
||||
)
|
||||
|
||||
assert res.returncode == 0, res.stderr
|
||||
assert "Discarded npm lockfile churn (1 file(s))" in res.stdout
|
||||
assert _git(repo, "stash", "list").stdout.strip() == ""
|
||||
assert (repo / "package-lock.json").read_text() == '{"lock":"old"}\n'
|
||||
|
||||
|
||||
def test_install_sh_discards_lockfile_churn_before_status_probe() -> None:
|
||||
text = INSTALL_SH.read_text()
|
||||
idx_cleanup = text.index('discard_update_lockfile_churn "$INSTALL_DIR"')
|
||||
idx_status = text.index('if [ -n "$(git status --porcelain)" ]')
|
||||
idx_stash = text.index("git stash push --include-untracked")
|
||||
assert idx_cleanup < idx_status < idx_stash
|
||||
|
||||
|
||||
def test_install_ps1_discards_lockfile_churn_before_status_probe() -> None:
|
||||
text = INSTALL_PS1.read_text()
|
||||
assert "function Discard-LockfileChurn" in text
|
||||
idx_cleanup = text.index("Discard-LockfileChurn $InstallDir")
|
||||
idx_status = text.index(
|
||||
"$statusOut = git -c windows.appendAtomically=false status --porcelain"
|
||||
)
|
||||
idx_stash = text.index("stash push --include-untracked")
|
||||
assert idx_cleanup < idx_status < idx_stash
|
||||
Reference in New Issue
Block a user