fix(tests): resolve 17 persistent CI test failures (#15084)

Make the main-branch test suite pass again. Most failures were tests
still asserting old shapes after recent refactors; two were real source
bugs.

Source fixes:
- tools/mcp_tool.py: _kill_orphaned_mcp_children() slept 2s on every
  shutdown even when no tracked PIDs existed, making test_shutdown_is_parallel
  measure ~3s for 3 parallel 1s shutdowns. Early-return when pids is empty.
- hermes_cli/tips.py: tip 105 was 157 chars; corpus max is 150.

Test fixes (mostly stale mock targets / missing fixture fields):
- test_zombie_process_cleanup, test_agent_cache: patch run_agent.cleanup_vm
  (the local name bound at import), not tools.terminal_tool.cleanup_vm.
- test_browser_camofox: patch tools.browser_camofox.load_config, not
  hermes_cli.config.load_config (the source module, not the resolved one).
- test_flush_memories_codex._chat_response_with_memory_call: add
  finish_reason, tool_call.id, tool_call.type so the chat_completions
  transport normalizer doesn't AttributeError.
- test_concurrent_interrupt: polling_tool signature now accepts
  messages= kwarg that _invoke_tool() passes through.
- test_minimax_provider: add _fallback_chain=[] to the __new__'d agent
  so switch_model() doesn't AttributeError.
- test_skills_config: SKILLS_DIR MagicMock + .rglob stopped working
  after the scanner switched to agent.skill_utils.iter_skill_index_files
  (os.walk-based). Point SKILLS_DIR at a real tmp_path and patch
  agent.skill_utils.get_external_skills_dirs.
- test_browser_cdp_tool: browser_cdp toolset was intentionally split into
  'browser-cdp' (commit 96b0f3700) so its stricter check_fn doesn't gate
  the whole browser toolset; test now expects 'browser-cdp'.
- test_registry: add tools.browser_dialog_tool to the expected
  builtin-discovery set (PR #14540 added it).
- test_file_tools TestPatchHints: patch_tool surfaces hints as a '_hint'
  key on the JSON payload, not inline '[Hint: ...' text.
- test_write_deny test_hermes_env: resolve .env via get_hermes_home() so
  the path matches the profile-aware denylist under hermetic HERMES_HOME.
- test_checkpoint_manager test_falls_back_to_parent: guard the walk-up
  so a stray /tmp/pyproject.toml on the host doesn't pick up /tmp as the
  project root.
- test_quick_commands: set cli.session_id in the __new__'d CLI so the
  alias-args path doesn't trip AttributeError when fuzzy-matching leaks
  a skill command across xdist test distribution.
This commit is contained in:
Teknium 2026-04-24 03:46:46 -07:00 committed by GitHub
parent 1f9c368622
commit 18f3fc8a6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 83 additions and 29 deletions

View file

@ -251,43 +251,48 @@ class TestGetDisabledSkillNames:
class TestFindAllSkillsFiltering:
@patch("tools.skills_tool._get_disabled_skill_names", return_value={"my-skill"})
@patch("tools.skills_tool.skill_matches_platform", return_value=True)
@patch("tools.skills_tool.SKILLS_DIR")
def test_disabled_skill_excluded(self, mock_dir, mock_platform, mock_disabled, tmp_path):
def test_disabled_skill_excluded(self, mock_platform, mock_disabled, tmp_path, monkeypatch):
skill_dir = tmp_path / "my-skill"
skill_dir.mkdir()
skill_md = skill_dir / "SKILL.md"
skill_md.write_text("---\nname: my-skill\ndescription: A test skill\n---\nContent")
mock_dir.exists.return_value = True
mock_dir.rglob.return_value = [skill_md]
# Point SKILLS_DIR at the real tempdir so iter_skill_index_files
# (which uses os.walk) can actually find the file.
import tools.skills_tool as _st
import agent.skill_utils as _su
monkeypatch.setattr(_st, "SKILLS_DIR", tmp_path)
monkeypatch.setattr(_su, "get_external_skills_dirs", lambda: [])
from tools.skills_tool import _find_all_skills
skills = _find_all_skills()
assert not any(s["name"] == "my-skill" for s in skills)
@patch("tools.skills_tool._get_disabled_skill_names", return_value=set())
@patch("tools.skills_tool.skill_matches_platform", return_value=True)
@patch("tools.skills_tool.SKILLS_DIR")
def test_enabled_skill_included(self, mock_dir, mock_platform, mock_disabled, tmp_path):
def test_enabled_skill_included(self, mock_platform, mock_disabled, tmp_path, monkeypatch):
skill_dir = tmp_path / "my-skill"
skill_dir.mkdir()
skill_md = skill_dir / "SKILL.md"
skill_md.write_text("---\nname: my-skill\ndescription: A test skill\n---\nContent")
mock_dir.exists.return_value = True
mock_dir.rglob.return_value = [skill_md]
import tools.skills_tool as _st
import agent.skill_utils as _su
monkeypatch.setattr(_st, "SKILLS_DIR", tmp_path)
monkeypatch.setattr(_su, "get_external_skills_dirs", lambda: [])
from tools.skills_tool import _find_all_skills
skills = _find_all_skills()
assert any(s["name"] == "my-skill" for s in skills)
@patch("tools.skills_tool._get_disabled_skill_names", return_value={"my-skill"})
@patch("tools.skills_tool.skill_matches_platform", return_value=True)
@patch("tools.skills_tool.SKILLS_DIR")
def test_skip_disabled_returns_all(self, mock_dir, mock_platform, mock_disabled, tmp_path):
def test_skip_disabled_returns_all(self, mock_platform, mock_disabled, tmp_path, monkeypatch):
"""skip_disabled=True ignores the disabled set (for config UI)."""
skill_dir = tmp_path / "my-skill"
skill_dir.mkdir()
skill_md = skill_dir / "SKILL.md"
skill_md.write_text("---\nname: my-skill\ndescription: A test skill\n---\nContent")
mock_dir.exists.return_value = True
mock_dir.rglob.return_value = [skill_md]
import tools.skills_tool as _st
import agent.skill_utils as _su
monkeypatch.setattr(_st, "SKILLS_DIR", tmp_path)
monkeypatch.setattr(_su, "get_external_skills_dirs", lambda: [])
from tools.skills_tool import _find_all_skills
skills = _find_all_skills(skip_disabled=True)
assert any(s["name"] == "my-skill" for s in skills)