Skip to content

test: close coverage gaps in MCP glue and remaining tool handlers - #23

Merged
musicsms merged 1 commit into
masterfrom
close-coverage-gaps
Sep 10, 2026
Merged

musicsms merged 1 commit into
masterfrom
close-coverage-gaps

Conversation

@musicsms

Copy link
Copy Markdown
Owner

Summary

Measured coverage with pytest-cov: 92% overall (1856 stmts, 140 miss). The weakest spots were the MCP dispatch path every one of the 99 tools goes through, plus two handlers that only had a registration-existence test and no invocation test.

  • tests/test_mcp_client.py (new): HexStrikeClient had 0% coverage — the HTTP client used by every single MCP tool call to reach the Flask API. Now covers check_health() and execute_tool() for the success path, an HTTP error status, and a request exception. → 100%.
  • tests/test_mcp.py: added a test that calls mcp.call_tool("nmap_scan", ...) with client.execute_tool mocked, asserting tool_func's sig.bind(...).apply_defaults() actually fills in every handler parameter before dispatch. This closure is what turns a ToolSpec into a working MCP tool for all 99 registered tools — previously only its metadata (name/description) was exercised, never an actual call through it.
  • tests/test_api.py: added a GET-request variant (exercises the request.args.to_dict() branch), a missing-required-argument case (exercises the TypeError → 400 branch), and a handler-raises case (exercises the generic Exception → 500 branch) of create_tool_view. api/app.py → 100%.
  • tests/test_password_tools.py: hydra_attack had no invocation test (only hashcat_scan/john_scan did). Added two, covering both branches of each optional flag. password.py → 100%.
  • tests/test_osint_tools.py: same gap for amass_enum (only hakrawler_crawl was tested). Added two. osint.py → 100%.

Deliberately left uncovered: hexstrike/core/visual.py (banner/color constants, no branching logic) and mcp/server.py's main()/if __name__ block (argparse + a blocking mcp.run() call — mocking it out mainly re-tests argparse plumbing for little value).

Result: 94% overall, 241/241 tests passing (up from 92%/228).

Test plan

  • pytest tests/ -q --cov=hexstrike --cov-report=term-missing locally → 241 passed, 94% coverage
  • Confirmed each targeted file (api/app.py, mcp/client.py, password.py, osint.py) hits 100%
  • CI will run the full suite on this PR (no coverage gate added — just closing gaps this round)

🤖 Generated with Claude Code

https://claude.ai/code/session_01UCXzPVYGQRPh8iwyajTsRt

@musicsms
musicsms merged commit c57078d into master Sep 10, 2026
1 check passed
@musicsms
musicsms deleted the close-coverage-gaps branch September 10, 2026 14:00
Measured with pytest-cov: 92% overall (1856 stmts, 140 miss). The
weakest spots were the MCP dispatch path every one of the 99 tools
goes through, plus two handlers that only had a registration-existence
test and no invocation test.

- tests/test_mcp_client.py (new): HexStrikeClient had 0% coverage.
  check_health() and execute_tool() are now covered for the success
  path, an HTTP error status, and a request exception -> 100%.
- tests/test_mcp.py: added a test that calls mcp.call_tool("nmap_scan",
  ...) with client.execute_tool mocked, asserting tool_func's
  sig.bind(...).apply_defaults() actually fills in every handler
  parameter before dispatch - this closure is what turns a ToolSpec
  into a working MCP tool for all 99 registered tools, and previously
  only its metadata (name/description) was exercised, never a real
  call through it.
- tests/test_api.py: added a GET-request variant (exercises the
  request.args.to_dict() branch), a missing-required-argument case
  (exercises the TypeError -> 400 branch), and a handler-raises case
  (exercises the generic Exception -> 500 branch) of create_tool_view.
  api/app.py -> 100%.
- tests/test_password_tools.py: hydra_attack had no invocation test
  (only hashcat_scan/john_scan did). Added two, covering both branches
  of each optional flag. password.py -> 100%.
- tests/test_osint_tools.py: same gap for amass_enum (only
  hakrawler_crawl was tested). Added two. osint.py -> 100%.

Deliberately left uncovered: hexstrike/core/visual.py (a banner/color
constants module, no branching logic to test) and mcp/server.py's
main()/`if __name__` block (argparse + a blocking mcp.run() call -
mocking it out mainly re-tests argparse plumbing for little value).

Result: 94% overall, 241/241 tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UCXzPVYGQRPh8iwyajTsRt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant