test(hanzo-tools): add tests and CI for 53 tools across 13 packages

- Add test_all_tools.py with 28 tests covering:
  - Package imports and tool counts
  - Import speed verification (no blocking)
  - Async call method verification
  - Total tool count validation (53 tools)

- Add test-hanzo-tools.yml CI workflow:
  - Runs on push/PR to pkg/hanzo-tools-*
  - Installs all 13 tool packages
  - Verifies all tools import correctly
This commit is contained in:
2025-12-25 23:18:58 -08:00
parent d5f8e3f2b5
commit c63f370fea
3 changed files with 274 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
name: Test Hanzo Tools
on:
push:
branches: [main]
paths:
- 'pkg/hanzo-tools-*/**'
- '.github/workflows/test-hanzo-tools.yml'
pull_request:
branches: [main]
paths:
- 'pkg/hanzo-tools-*/**'
- '.github/workflows/test-hanzo-tools.yml'
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
python-version: ['3.12']
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install hanzo-tools packages
run: |
uv venv
source .venv/bin/activate
# Install all tool packages
uv pip install -e pkg/hanzo-tools-core
uv pip install -e pkg/hanzo-tools-filesystem
uv pip install -e pkg/hanzo-tools-shell
uv pip install -e pkg/hanzo-tools-browser
uv pip install -e pkg/hanzo-tools-memory
uv pip install -e pkg/hanzo-tools-todo
uv pip install -e pkg/hanzo-tools-reasoning
uv pip install -e pkg/hanzo-tools-lsp
uv pip install -e pkg/hanzo-tools-refactor
uv pip install -e pkg/hanzo-tools-database
uv pip install -e pkg/hanzo-tools-agent
uv pip install -e pkg/hanzo-tools-jupyter
uv pip install -e pkg/hanzo-tools-editor
uv pip install pytest pytest-asyncio
- name: Run tests
run: |
source .venv/bin/activate
python -m pytest pkg/hanzo-tools-core/tests/test_all_tools.py -v --tb=short
- name: Verify tool counts
run: |
source .venv/bin/activate
python -c "
packages = [
('hanzo_tools.filesystem', 7),
('hanzo_tools.shell', 7),
('hanzo_tools.browser', 1),
('hanzo_tools.memory', 9),
('hanzo_tools.todo', 1),
('hanzo_tools.reasoning', 2),
('hanzo_tools.lsp', 1),
('hanzo_tools.refactor', 1),
('hanzo_tools.database', 8),
('hanzo_tools.agent', 12),
('hanzo_tools.jupyter', 1),
('hanzo_tools.editor', 3),
]
total = 0
for pkg_name, expected in packages:
import importlib
pkg = importlib.import_module(pkg_name)
tools = getattr(pkg, 'TOOLS', [])
actual = len(tools)
status = '✓' if actual == expected else '✗'
print(f'{status} {pkg_name}: {actual}/{expected} tools')
assert actual == expected, f'{pkg_name}: expected {expected}, got {actual}'
total += actual
print(f'\\nTotal: {total} tools')
assert total == 53, f'Expected 53 tools, got {total}'
print('✓ All tool packages verified')
"
+1
View File
@@ -0,0 +1 @@
# Tests for hanzo-tools-core
@@ -0,0 +1,180 @@
"""Test all hanzo-tools-* packages import and register correctly."""
import asyncio
import time
import pytest
class TestToolPackages:
"""Test that all tool packages import correctly."""
def test_core_imports(self):
"""Test hanzo-tools-core imports."""
from hanzo_tools.core import BaseTool, ToolContext
from hanzo_tools.core.permissions import PermissionManager
from hanzo_tools.core.decorators import auto_timeout
assert BaseTool is not None
assert ToolContext is not None
assert PermissionManager is not None
assert auto_timeout is not None
def test_filesystem_tools(self):
"""Test hanzo-tools-filesystem has 7 tools."""
from hanzo_tools.filesystem import TOOLS
assert len(TOOLS) == 7
names = {t.name for t in TOOLS}
expected = {'read', 'write', 'edit', 'tree', 'find', 'search', 'ast'}
assert names == expected
def test_shell_tools(self):
"""Test hanzo-tools-shell has 7 tools."""
from hanzo_tools.shell import TOOLS
assert len(TOOLS) == 7
names = {t.name for t in TOOLS}
expected = {'dag', 'ps', 'zsh', 'shell', 'npx', 'uvx', 'open'}
assert names == expected
def test_memory_tools(self):
"""Test hanzo-tools-memory has 9 tools."""
from hanzo_tools.memory import TOOLS
assert len(TOOLS) == 9
def test_todo_tools(self):
"""Test hanzo-tools-todo has 1 tool."""
from hanzo_tools.todo import TOOLS
assert len(TOOLS) == 1
assert TOOLS[0].name == 'todo'
def test_reasoning_tools(self):
"""Test hanzo-tools-reasoning has 2 tools."""
from hanzo_tools.reasoning import TOOLS
assert len(TOOLS) == 2
names = {t.name for t in TOOLS}
assert names == {'think', 'critic'}
def test_lsp_tools(self):
"""Test hanzo-tools-lsp has 1 tool."""
from hanzo_tools.lsp import TOOLS
assert len(TOOLS) == 1
assert TOOLS[0].name == 'lsp'
def test_refactor_tools(self):
"""Test hanzo-tools-refactor has 1 tool."""
from hanzo_tools.refactor import TOOLS
assert len(TOOLS) == 1
assert TOOLS[0].name == 'refactor'
def test_database_tools(self):
"""Test hanzo-tools-database has 8 tools."""
from hanzo_tools.database import TOOLS
assert len(TOOLS) == 8
def test_agent_tools(self):
"""Test hanzo-tools-agent has 12 tools."""
from hanzo_tools.agent import TOOLS
assert len(TOOLS) == 12
def test_jupyter_tools(self):
"""Test hanzo-tools-jupyter has 1 tool."""
from hanzo_tools.jupyter import TOOLS
assert len(TOOLS) == 1
def test_editor_tools(self):
"""Test hanzo-tools-editor has 3 tools."""
from hanzo_tools.editor import TOOLS
assert len(TOOLS) == 3
def test_browser_tools(self):
"""Test hanzo-tools-browser has 1 tool."""
from hanzo_tools.browser import TOOLS
assert len(TOOLS) == 1
class TestToolImportSpeed:
"""Test that tool imports are fast (no blocking)."""
@pytest.mark.parametrize("module,max_time", [
("hanzo_tools.core", 1.0),
("hanzo_tools.filesystem", 1.0),
("hanzo_tools.shell", 1.0),
("hanzo_tools.memory", 1.0),
("hanzo_tools.todo", 1.0),
("hanzo_tools.reasoning", 1.0),
("hanzo_tools.lsp", 1.0),
("hanzo_tools.refactor", 1.0),
("hanzo_tools.database", 1.0),
("hanzo_tools.jupyter", 1.0),
("hanzo_tools.editor", 1.0),
("hanzo_tools.browser", 1.0),
("hanzo_tools.agent", 2.0), # Agent has litellm, allow more time
])
def test_import_speed(self, module, max_time):
"""Test that imports complete quickly."""
import importlib
start = time.time()
importlib.import_module(module)
elapsed = time.time() - start
assert elapsed < max_time, f"{module} took {elapsed:.2f}s (max {max_time}s)"
class TestToolAsync:
"""Test that all tools have async call methods."""
def test_all_tools_async(self):
"""Verify all tool .call() methods are async."""
packages = [
'hanzo_tools.filesystem',
'hanzo_tools.shell',
'hanzo_tools.memory',
'hanzo_tools.todo',
'hanzo_tools.reasoning',
'hanzo_tools.lsp',
'hanzo_tools.refactor',
'hanzo_tools.database',
'hanzo_tools.agent',
'hanzo_tools.jupyter',
'hanzo_tools.editor',
'hanzo_tools.browser',
]
for pkg_name in packages:
import importlib
pkg = importlib.import_module(pkg_name)
tools = getattr(pkg, 'TOOLS', [])
for tool in tools:
if hasattr(tool, 'call'):
assert asyncio.iscoroutinefunction(tool.call), \
f"{pkg_name}.{tool.name}.call() is not async"
class TestTotalToolCount:
"""Test total tool count across all packages."""
def test_total_53_tools(self):
"""Verify we have exactly 53 tools across all packages."""
packages = [
('hanzo_tools.filesystem', 7),
('hanzo_tools.shell', 7),
('hanzo_tools.browser', 1),
('hanzo_tools.memory', 9),
('hanzo_tools.todo', 1),
('hanzo_tools.reasoning', 2),
('hanzo_tools.lsp', 1),
('hanzo_tools.refactor', 1),
('hanzo_tools.database', 8),
('hanzo_tools.agent', 12),
('hanzo_tools.jupyter', 1),
('hanzo_tools.editor', 3),
]
total = 0
for pkg_name, expected_count in packages:
import importlib
pkg = importlib.import_module(pkg_name)
tools = getattr(pkg, 'TOOLS', [])
actual = len(tools)
assert actual == expected_count, \
f"{pkg_name}: expected {expected_count} tools, got {actual}"
total += actual
assert total == 53, f"Expected 53 total tools, got {total}"