mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-01 12:02:05 +00:00
test(windows): cover no-window backend subprocess flags
This commit is contained in:
parent
cb982ad997
commit
1ffa01f35f
2 changed files with 268 additions and 0 deletions
263
tests/test_windows_subprocess_no_window_flags.py
Normal file
263
tests/test_windows_subprocess_no_window_flags.py
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
|
||||
_CREATE_NO_WINDOW = 0x08000000
|
||||
|
||||
|
||||
class _Completed:
|
||||
def __init__(self, stdout: str | bytes = "ok\n", returncode: int = 0):
|
||||
self.stdout = stdout
|
||||
self.stderr = ""
|
||||
self.returncode = returncode
|
||||
|
||||
|
||||
def test_tui_gateway_git_probe_hides_git_windows(monkeypatch):
|
||||
from tui_gateway import git_probe
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return _Completed(stdout="main\n")
|
||||
|
||||
monkeypatch.setattr(git_probe, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(git_probe, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(git_probe.subprocess, "run", fake_run)
|
||||
|
||||
assert git_probe.run_git("C:/repo", "branch", "--show-current") == "main"
|
||||
|
||||
assert captured == [
|
||||
(
|
||||
["git", "-C", "C:/repo", "branch", "--show-current"],
|
||||
{
|
||||
"capture_output": True,
|
||||
"text": True,
|
||||
"encoding": "utf-8",
|
||||
"errors": "replace",
|
||||
"timeout": git_probe._GIT_TIMEOUT,
|
||||
"check": False,
|
||||
"stdin": subprocess.DEVNULL,
|
||||
"creationflags": _CREATE_NO_WINDOW,
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_tui_gateway_fuzzy_file_listing_hides_git_windows(monkeypatch):
|
||||
from hermes_cli import _subprocess_compat
|
||||
from tui_gateway import server
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
if cmd[-1] == "--show-toplevel":
|
||||
return _Completed(stdout=b"C:/repo\n")
|
||||
return _Completed(stdout=b"src/main.py\0README.md\0")
|
||||
|
||||
monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(server.subprocess, "run", fake_run)
|
||||
server._fuzzy_cache.clear()
|
||||
|
||||
assert server._list_repo_files("C:/repo") == ["src/main.py", "README.md"]
|
||||
|
||||
assert [kwargs["creationflags"] for _, kwargs in captured] == [
|
||||
_CREATE_NO_WINDOW,
|
||||
_CREATE_NO_WINDOW,
|
||||
]
|
||||
|
||||
|
||||
def test_coding_context_git_hides_git_windows(monkeypatch):
|
||||
from agent import coding_context
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return _Completed(stdout="clean\n")
|
||||
|
||||
monkeypatch.setattr(coding_context, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(coding_context, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(coding_context.subprocess, "run", fake_run)
|
||||
|
||||
assert coding_context._git(Path("C:/repo"), "status", "--short") == "clean"
|
||||
assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW
|
||||
|
||||
|
||||
def test_context_reference_git_and_rg_hide_windows(monkeypatch):
|
||||
from agent import context_references
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
if cmd[0] == "rg":
|
||||
return _Completed(stdout="src/main.py\n")
|
||||
return _Completed(stdout="diff --git a/src/main.py b/src/main.py\n")
|
||||
|
||||
monkeypatch.setattr(context_references, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(context_references, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(context_references.subprocess, "run", fake_run)
|
||||
|
||||
ref = context_references.ContextReference(
|
||||
raw="@diff",
|
||||
kind="diff",
|
||||
target="",
|
||||
start=0,
|
||||
end=5,
|
||||
)
|
||||
warning, block = context_references._expand_git_reference(
|
||||
ref,
|
||||
Path("C:/repo"),
|
||||
["diff"],
|
||||
"git diff",
|
||||
)
|
||||
assert warning is None
|
||||
assert block is not None
|
||||
assert "git diff" in block
|
||||
assert context_references._rg_files(Path("C:/repo/src"), Path("C:/repo"), 10) == [
|
||||
Path("src/main.py")
|
||||
]
|
||||
|
||||
assert [kwargs["creationflags"] for _, kwargs in captured] == [
|
||||
_CREATE_NO_WINDOW,
|
||||
_CREATE_NO_WINDOW,
|
||||
]
|
||||
|
||||
|
||||
def test_copilot_gh_cli_probe_hides_gh_windows(monkeypatch):
|
||||
from hermes_cli import copilot_auth
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return _Completed(stdout="gho_from_cli\n")
|
||||
|
||||
monkeypatch.setattr(copilot_auth, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(copilot_auth, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(copilot_auth, "_gh_cli_candidates", lambda: ["gh"])
|
||||
monkeypatch.setattr(copilot_auth.subprocess, "run", fake_run)
|
||||
|
||||
assert copilot_auth._try_gh_cli_token() == "gho_from_cli"
|
||||
assert captured[0][0] == ["gh", "auth", "token"]
|
||||
assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW
|
||||
|
||||
|
||||
def test_gateway_pid_scan_hides_wmic_and_powershell_windows(monkeypatch):
|
||||
from hermes_cli import gateway
|
||||
from hermes_cli import _subprocess_compat
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
if cmd[0] == "wmic":
|
||||
return _Completed(stdout="", returncode=1)
|
||||
return _Completed(stdout="CommandLine=hermes gateway\nProcessId=123\n")
|
||||
|
||||
monkeypatch.setattr(gateway, "is_windows", lambda: True)
|
||||
monkeypatch.setattr(gateway.shutil, "which", lambda name: name)
|
||||
monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(gateway.subprocess, "run", fake_run)
|
||||
|
||||
assert gateway._scan_gateway_pids(set()) == [123]
|
||||
assert [kwargs["creationflags"] for _, kwargs in captured] == [
|
||||
_CREATE_NO_WINDOW,
|
||||
_CREATE_NO_WINDOW,
|
||||
]
|
||||
|
||||
|
||||
def test_stale_dashboard_windows_scan_hides_wmic(monkeypatch):
|
||||
from hermes_cli import main
|
||||
from hermes_cli import _subprocess_compat
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return _Completed(stdout="CommandLine=hermes dashboard\nProcessId=123\n")
|
||||
|
||||
monkeypatch.setattr(main.sys, "platform", "win32")
|
||||
monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(main.subprocess, "run", fake_run)
|
||||
|
||||
assert main._find_stale_dashboard_pids() == [123]
|
||||
assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW
|
||||
|
||||
|
||||
def test_gateway_force_kill_hides_taskkill_window(monkeypatch):
|
||||
from gateway import status
|
||||
from hermes_cli import _subprocess_compat
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return _Completed(stdout="")
|
||||
|
||||
monkeypatch.setattr(status, "_IS_WINDOWS", True)
|
||||
monkeypatch.setattr(_subprocess_compat, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(_subprocess_compat, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(status.subprocess, "run", fake_run)
|
||||
|
||||
status.terminate_pid(123, force=True)
|
||||
|
||||
assert captured == [
|
||||
(
|
||||
["taskkill", "/PID", "123", "/T", "/F"],
|
||||
{
|
||||
"capture_output": True,
|
||||
"text": True,
|
||||
"timeout": 10,
|
||||
"creationflags": _CREATE_NO_WINDOW,
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def test_shell_hooks_hide_hook_command_windows(monkeypatch):
|
||||
from agent import shell_hooks
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return SimpleNamespace(returncode=0, stdout="{}", stderr="")
|
||||
|
||||
monkeypatch.setattr(shell_hooks, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(shell_hooks, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(shell_hooks.subprocess, "run", fake_run)
|
||||
|
||||
result = shell_hooks._spawn(
|
||||
shell_hooks.ShellHookSpec(event="post_tool_call", command="hook-bin --flag"),
|
||||
"{}",
|
||||
)
|
||||
|
||||
assert result["returncode"] == 0
|
||||
assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW
|
||||
|
||||
|
||||
def test_inline_skill_shell_hides_bash_window(monkeypatch):
|
||||
from agent import skill_preprocessing
|
||||
|
||||
captured = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
captured.append((cmd, kwargs))
|
||||
return SimpleNamespace(returncode=0, stdout="ok\n", stderr="")
|
||||
|
||||
monkeypatch.setattr(skill_preprocessing, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(skill_preprocessing, "windows_hide_flags", lambda: _CREATE_NO_WINDOW)
|
||||
monkeypatch.setattr(skill_preprocessing.subprocess, "run", fake_run)
|
||||
|
||||
assert skill_preprocessing.run_inline_shell("echo ok", cwd=None, timeout=5) == "ok"
|
||||
assert captured[0][0] == ["bash", "-c", "echo ok"]
|
||||
assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW
|
||||
|
|
@ -11668,6 +11668,9 @@ def _list_repo_files(root: str) -> list[str]:
|
|||
return cached[1]
|
||||
|
||||
files: list[str] = []
|
||||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
|
||||
_creationflags = windows_hide_flags()
|
||||
try:
|
||||
top_result = subprocess.run(
|
||||
["git", "-C", root, "rev-parse", "--show-toplevel"],
|
||||
|
|
@ -11675,6 +11678,7 @@ def _list_repo_files(root: str) -> list[str]:
|
|||
timeout=2.0,
|
||||
check=False,
|
||||
stdin=subprocess.DEVNULL,
|
||||
creationflags=_creationflags,
|
||||
)
|
||||
if top_result.returncode == 0:
|
||||
top = top_result.stdout.decode("utf-8", "replace").strip()
|
||||
|
|
@ -11693,6 +11697,7 @@ def _list_repo_files(root: str) -> list[str]:
|
|||
timeout=2.0,
|
||||
check=False,
|
||||
stdin=subprocess.DEVNULL,
|
||||
creationflags=_creationflags,
|
||||
)
|
||||
if list_result.returncode == 0:
|
||||
for p in list_result.stdout.decode("utf-8", "replace").split("\0"):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue