hermes-agent/tests/gateway/test_gateway_command_line_matcher.py
Charles Power 715fa9ea1c fix(gateway): harden gateway command-line matcher (review findings)
Address correctness gaps found in pre-PR review of the strict matcher:

- Profile selectors can appear on EITHER side of the `gateway` token
  (`_apply_profile_override` strips `--profile`/`-p` from anywhere in argv
  before argparse), so `hermes gateway --profile work run` and
  `python -m hermes_cli.main gateway -p work run` are valid launches the
  previous matcher wrongly rejected. Strip `--profile`/`-p`/`--profile=`/`-p=`
  from anywhere before locating the subcommand.
- A profile literally named `gateway` (`hermes -p gateway gateway run`) made
  the old token scan stop on the profile value; stripping the selector+value
  first fixes it.
- Tokenize quote-aware with `shlex` so quoted Windows paths containing spaces
  (`"C:\Program Files\Hermes\hermes-gateway.exe"`) are no longer split mid-path
  and the dedicated-entrypoint match survives.

Without these, the matcher could MISS a real running gateway -> the opposite
failure (restart/status reporting "down" when up). Adds regression tests for
all three shapes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 06:31:56 -07:00

60 lines
2.3 KiB
Python

"""Tests for the strict gateway command-line matcher.
Regression guard for the Windows ``hermes gateway restart`` silent-outage bug:
the previous loose substring match (``"... gateway" in cmdline``) false-matched
``gateway status``/``dashboard`` siblings and unrelated processes such as
``python -m tui_gateway``, which let ``restart()`` race a still-draining old
process and ``status``/``start`` report false positives.
"""
from __future__ import annotations
import pytest
from gateway.status import looks_like_gateway_command_line as matches
ACCEPT = [
"pythonw.exe -m hermes_cli.main gateway run",
r"C:\Users\me\hermes\venv\Scripts\pythonw.exe -m hermes_cli.main gateway run",
"python -m hermes_cli.main --profile work gateway run",
"python -m hermes_cli.main gateway run --replace",
"python -m hermes_cli/main.py gateway run",
"python gateway/run.py",
"hermes-gateway.exe",
"hermes gateway", # bare `hermes gateway` defaults to run
"hermes gateway run",
# profile selector AFTER the `gateway` token (argv is profile-position
# agnostic — _apply_profile_override strips --profile/-p anywhere)
"hermes gateway --profile work run",
"python -m hermes_cli.main gateway -p work run",
"hermes gateway --profile=work run",
# a profile literally NAMED "gateway"
"hermes -p gateway gateway run",
"python -m hermes_cli.main --profile gateway gateway run",
# quoted Windows paths with spaces (shlex-aware tokenization)
r'"C:\Program Files\Hermes\hermes-gateway.exe"',
r'"C:\Program Files\Hermes\gateway\run.py" run',
r'"C:\Program Files\Py\pythonw.exe" -m hermes_cli.main gateway run',
]
REJECT = [
"python -m tui_gateway", # unrelated module
"python -m hermes_cli.main gateway status", # other subcommand
"python -m hermes_cli.main gateway restart",
"python -m hermes_cli.main gateway stop",
"python -m hermes_cli.main --profile x dashboard", # non-gateway subcommand
"some random python -m mygateway thing",
"",
None,
]
@pytest.mark.parametrize("cmd", ACCEPT)
def test_accepts_real_gateway_run(cmd):
assert matches(cmd) is True
@pytest.mark.parametrize("cmd", REJECT)
def test_rejects_non_gateway_run(cmd):
assert matches(cmd) is False