feat: Timmy system introspection, delegation, and session logging (#74)
* test: remove hardcoded sleeps, add pytest-timeout
- Replace fixed time.sleep() calls with intelligent polling or WebDriverWait
- Add pytest-timeout dependency and --timeout=30 to prevent hangs
- Fixes test flakiness and improves test suite speed
* feat: add Aider AI tool to Forge's toolkit
- Add Aider tool that calls local Ollama (qwen2.5:14b) for AI coding assist
- Register tool in Forge's code toolkit
- Add functional tests for the Aider tool
* config: add opencode.json with local Ollama provider for sovereign AI
* feat: Timmy fixes and improvements
## Bug Fixes
- Fix read_file path resolution: add ~ expansion, proper relative path handling
- Add repo_root to config.py with auto-detection from .git location
- Fix hardcoded llama3.2 - now dynamic from settings.ollama_model
## Timmy's Requests
- Add communication protocol to AGENTS.md (read context first, explain changes)
- Create DECISIONS.md for architectural decision documentation
- Add reasoning guidance to system prompts (step-by-step, state uncertainty)
- Update tests to reflect correct model name (llama3.1:8b-instruct)
## Testing
- All 177 dashboard tests pass
- All 32 prompt/tool tests pass
* feat: Timmy system introspection, delegation, and session logging
## System Introspection (Sovereign Self-Knowledge)
- Add get_system_info() tool - Timmy can now query his runtime environment
- Add check_ollama_health() - verify Ollama status
- Add get_memory_status() - check memory tier status
- True introspection vs hardcoded prompts
## Path Resolution Fix
- Fix all toolkits to use settings.repo_root consistently
- Now uses Path(settings.repo_root) instead of Path.cwd()
## Inter-Agent Delegation
- Add delegate_task() tool - Timmy can dispatch to Seer, Forge, Echo, etc.
- Add list_swarm_agents() - query available agents
## Session Logging
- Add SessionLogger for comprehensive interaction logging
- Records messages, tool calls, errors, decisions
- Writes to /logs/session_{date}.jsonl
## Tests
- Add tests for introspection tools
- Add tests for delegation tools
- Add tests for session logging
- Add tests for path resolution
- All 18 new tests pass
- All 177 dashboard tests pass
---------
Co-authored-by: Alexander Payne <apayne@MM.local>
2026-02-27 00:11:53 -05:00
|
|
|
"""Tests for system introspection tools."""
|
|
|
|
|
|
2026-03-14 18:02:14 -04:00
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
|
|
|
|
import httpx
|
|
|
|
|
|
feat: Timmy system introspection, delegation, and session logging (#74)
* test: remove hardcoded sleeps, add pytest-timeout
- Replace fixed time.sleep() calls with intelligent polling or WebDriverWait
- Add pytest-timeout dependency and --timeout=30 to prevent hangs
- Fixes test flakiness and improves test suite speed
* feat: add Aider AI tool to Forge's toolkit
- Add Aider tool that calls local Ollama (qwen2.5:14b) for AI coding assist
- Register tool in Forge's code toolkit
- Add functional tests for the Aider tool
* config: add opencode.json with local Ollama provider for sovereign AI
* feat: Timmy fixes and improvements
## Bug Fixes
- Fix read_file path resolution: add ~ expansion, proper relative path handling
- Add repo_root to config.py with auto-detection from .git location
- Fix hardcoded llama3.2 - now dynamic from settings.ollama_model
## Timmy's Requests
- Add communication protocol to AGENTS.md (read context first, explain changes)
- Create DECISIONS.md for architectural decision documentation
- Add reasoning guidance to system prompts (step-by-step, state uncertainty)
- Update tests to reflect correct model name (llama3.1:8b-instruct)
## Testing
- All 177 dashboard tests pass
- All 32 prompt/tool tests pass
* feat: Timmy system introspection, delegation, and session logging
## System Introspection (Sovereign Self-Knowledge)
- Add get_system_info() tool - Timmy can now query his runtime environment
- Add check_ollama_health() - verify Ollama status
- Add get_memory_status() - check memory tier status
- True introspection vs hardcoded prompts
## Path Resolution Fix
- Fix all toolkits to use settings.repo_root consistently
- Now uses Path(settings.repo_root) instead of Path.cwd()
## Inter-Agent Delegation
- Add delegate_task() tool - Timmy can dispatch to Seer, Forge, Echo, etc.
- Add list_swarm_agents() - query available agents
## Session Logging
- Add SessionLogger for comprehensive interaction logging
- Records messages, tool calls, errors, decisions
- Writes to /logs/session_{date}.jsonl
## Tests
- Add tests for introspection tools
- Add tests for delegation tools
- Add tests for session logging
- Add tests for path resolution
- All 18 new tests pass
- All 177 dashboard tests pass
---------
Co-authored-by: Alexander Payne <apayne@MM.local>
2026-02-27 00:11:53 -05:00
|
|
|
|
|
|
|
|
def test_get_system_info_returns_dict():
|
|
|
|
|
"""System info should return a dictionary."""
|
|
|
|
|
from timmy.tools_intro import get_system_info
|
|
|
|
|
|
|
|
|
|
info = get_system_info()
|
|
|
|
|
|
|
|
|
|
assert isinstance(info, dict)
|
|
|
|
|
assert "python_version" in info
|
|
|
|
|
assert "platform" in info
|
|
|
|
|
assert "model" in info
|
|
|
|
|
assert "repo_root" in info
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_system_info_contains_model():
|
2026-03-14 18:02:14 -04:00
|
|
|
"""System info should include a model name (may differ from config if
|
|
|
|
|
the actual running model is different — see issue #77)."""
|
2026-03-08 12:50:44 -04:00
|
|
|
from timmy.tools_intro import get_system_info
|
feat: Timmy system introspection, delegation, and session logging (#74)
* test: remove hardcoded sleeps, add pytest-timeout
- Replace fixed time.sleep() calls with intelligent polling or WebDriverWait
- Add pytest-timeout dependency and --timeout=30 to prevent hangs
- Fixes test flakiness and improves test suite speed
* feat: add Aider AI tool to Forge's toolkit
- Add Aider tool that calls local Ollama (qwen2.5:14b) for AI coding assist
- Register tool in Forge's code toolkit
- Add functional tests for the Aider tool
* config: add opencode.json with local Ollama provider for sovereign AI
* feat: Timmy fixes and improvements
## Bug Fixes
- Fix read_file path resolution: add ~ expansion, proper relative path handling
- Add repo_root to config.py with auto-detection from .git location
- Fix hardcoded llama3.2 - now dynamic from settings.ollama_model
## Timmy's Requests
- Add communication protocol to AGENTS.md (read context first, explain changes)
- Create DECISIONS.md for architectural decision documentation
- Add reasoning guidance to system prompts (step-by-step, state uncertainty)
- Update tests to reflect correct model name (llama3.1:8b-instruct)
## Testing
- All 177 dashboard tests pass
- All 32 prompt/tool tests pass
* feat: Timmy system introspection, delegation, and session logging
## System Introspection (Sovereign Self-Knowledge)
- Add get_system_info() tool - Timmy can now query his runtime environment
- Add check_ollama_health() - verify Ollama status
- Add get_memory_status() - check memory tier status
- True introspection vs hardcoded prompts
## Path Resolution Fix
- Fix all toolkits to use settings.repo_root consistently
- Now uses Path(settings.repo_root) instead of Path.cwd()
## Inter-Agent Delegation
- Add delegate_task() tool - Timmy can dispatch to Seer, Forge, Echo, etc.
- Add list_swarm_agents() - query available agents
## Session Logging
- Add SessionLogger for comprehensive interaction logging
- Records messages, tool calls, errors, decisions
- Writes to /logs/session_{date}.jsonl
## Tests
- Add tests for introspection tools
- Add tests for delegation tools
- Add tests for session logging
- Add tests for path resolution
- All 18 new tests pass
- All 177 dashboard tests pass
---------
Co-authored-by: Alexander Payne <apayne@MM.local>
2026-02-27 00:11:53 -05:00
|
|
|
|
|
|
|
|
info = get_system_info()
|
|
|
|
|
|
|
|
|
|
assert "model" in info
|
2026-03-14 18:02:14 -04:00
|
|
|
# Model should be a non-empty string — exact value depends on what
|
|
|
|
|
# Ollama has loaded (verified by TestGetOllamaModelExactMatch tests)
|
|
|
|
|
assert isinstance(info["model"], str)
|
|
|
|
|
assert len(info["model"]) > 0
|
feat: Timmy system introspection, delegation, and session logging (#74)
* test: remove hardcoded sleeps, add pytest-timeout
- Replace fixed time.sleep() calls with intelligent polling or WebDriverWait
- Add pytest-timeout dependency and --timeout=30 to prevent hangs
- Fixes test flakiness and improves test suite speed
* feat: add Aider AI tool to Forge's toolkit
- Add Aider tool that calls local Ollama (qwen2.5:14b) for AI coding assist
- Register tool in Forge's code toolkit
- Add functional tests for the Aider tool
* config: add opencode.json with local Ollama provider for sovereign AI
* feat: Timmy fixes and improvements
## Bug Fixes
- Fix read_file path resolution: add ~ expansion, proper relative path handling
- Add repo_root to config.py with auto-detection from .git location
- Fix hardcoded llama3.2 - now dynamic from settings.ollama_model
## Timmy's Requests
- Add communication protocol to AGENTS.md (read context first, explain changes)
- Create DECISIONS.md for architectural decision documentation
- Add reasoning guidance to system prompts (step-by-step, state uncertainty)
- Update tests to reflect correct model name (llama3.1:8b-instruct)
## Testing
- All 177 dashboard tests pass
- All 32 prompt/tool tests pass
* feat: Timmy system introspection, delegation, and session logging
## System Introspection (Sovereign Self-Knowledge)
- Add get_system_info() tool - Timmy can now query his runtime environment
- Add check_ollama_health() - verify Ollama status
- Add get_memory_status() - check memory tier status
- True introspection vs hardcoded prompts
## Path Resolution Fix
- Fix all toolkits to use settings.repo_root consistently
- Now uses Path(settings.repo_root) instead of Path.cwd()
## Inter-Agent Delegation
- Add delegate_task() tool - Timmy can dispatch to Seer, Forge, Echo, etc.
- Add list_swarm_agents() - query available agents
## Session Logging
- Add SessionLogger for comprehensive interaction logging
- Records messages, tool calls, errors, decisions
- Writes to /logs/session_{date}.jsonl
## Tests
- Add tests for introspection tools
- Add tests for delegation tools
- Add tests for session logging
- Add tests for path resolution
- All 18 new tests pass
- All 177 dashboard tests pass
---------
Co-authored-by: Alexander Payne <apayne@MM.local>
2026-02-27 00:11:53 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_system_info_contains_repo_root():
|
|
|
|
|
"""System info should include repo_root."""
|
|
|
|
|
from config import settings
|
2026-03-08 12:50:44 -04:00
|
|
|
from timmy.tools_intro import get_system_info
|
feat: Timmy system introspection, delegation, and session logging (#74)
* test: remove hardcoded sleeps, add pytest-timeout
- Replace fixed time.sleep() calls with intelligent polling or WebDriverWait
- Add pytest-timeout dependency and --timeout=30 to prevent hangs
- Fixes test flakiness and improves test suite speed
* feat: add Aider AI tool to Forge's toolkit
- Add Aider tool that calls local Ollama (qwen2.5:14b) for AI coding assist
- Register tool in Forge's code toolkit
- Add functional tests for the Aider tool
* config: add opencode.json with local Ollama provider for sovereign AI
* feat: Timmy fixes and improvements
## Bug Fixes
- Fix read_file path resolution: add ~ expansion, proper relative path handling
- Add repo_root to config.py with auto-detection from .git location
- Fix hardcoded llama3.2 - now dynamic from settings.ollama_model
## Timmy's Requests
- Add communication protocol to AGENTS.md (read context first, explain changes)
- Create DECISIONS.md for architectural decision documentation
- Add reasoning guidance to system prompts (step-by-step, state uncertainty)
- Update tests to reflect correct model name (llama3.1:8b-instruct)
## Testing
- All 177 dashboard tests pass
- All 32 prompt/tool tests pass
* feat: Timmy system introspection, delegation, and session logging
## System Introspection (Sovereign Self-Knowledge)
- Add get_system_info() tool - Timmy can now query his runtime environment
- Add check_ollama_health() - verify Ollama status
- Add get_memory_status() - check memory tier status
- True introspection vs hardcoded prompts
## Path Resolution Fix
- Fix all toolkits to use settings.repo_root consistently
- Now uses Path(settings.repo_root) instead of Path.cwd()
## Inter-Agent Delegation
- Add delegate_task() tool - Timmy can dispatch to Seer, Forge, Echo, etc.
- Add list_swarm_agents() - query available agents
## Session Logging
- Add SessionLogger for comprehensive interaction logging
- Records messages, tool calls, errors, decisions
- Writes to /logs/session_{date}.jsonl
## Tests
- Add tests for introspection tools
- Add tests for delegation tools
- Add tests for session logging
- Add tests for path resolution
- All 18 new tests pass
- All 177 dashboard tests pass
---------
Co-authored-by: Alexander Payne <apayne@MM.local>
2026-02-27 00:11:53 -05:00
|
|
|
|
|
|
|
|
info = get_system_info()
|
|
|
|
|
|
|
|
|
|
assert "repo_root" in info
|
|
|
|
|
assert info["repo_root"] == settings.repo_root
|
fix: Docker-first test suite, UX improvements, and bug fixes (#100)
Dashboard UX:
- Restructure nav from 22 flat links to 6 core + MORE dropdown
- Add mobile nav section labels (Core, Intelligence, Agents, System, Commerce)
- Defer marked.js and dompurify.js loading, consolidate CDN to jsdelivr
- Optimize font weights (drop unused 300/500), bump style.css cache buster
- Remove duplicate HTMX load triggers from sidebar and health panels
Bug fixes:
- Fix Timmy showing OFFLINE by registering after swarm recovery sweep
- Fix ThinkingEngine await bug with asyncio.run_coroutine_threadsafe
- Fix chat auto-scroll by calling scrollChat() after history partial loads
- Add missing /voice/button page and /voice/command endpoint
- Fix Grok api_key="" treated as falsy falling through to env key
- Fix self_modify PROJECT_ROOT using settings.repo_root instead of __file__
Docker test infrastructure:
- Bind-mount hands/, docker/, Dockerfiles, and compose files into test container
- Add fontconfig + fonts-dejavu-core for creative/assembler TextClip tests
- Initialize minimal git repo in Dockerfile.test for GitSafety compatibility
- Fix introspection and path resolution tests for Docker /app context
All 1863 tests pass in Docker (0 failures, 77 skipped).
Co-authored-by: Alexander Payne <apayne@MM.local>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:14:37 -05:00
|
|
|
# In Docker the CWD is /app, so just verify it's a non-empty path
|
|
|
|
|
assert len(info["repo_root"]) > 0
|
feat: Timmy system introspection, delegation, and session logging (#74)
* test: remove hardcoded sleeps, add pytest-timeout
- Replace fixed time.sleep() calls with intelligent polling or WebDriverWait
- Add pytest-timeout dependency and --timeout=30 to prevent hangs
- Fixes test flakiness and improves test suite speed
* feat: add Aider AI tool to Forge's toolkit
- Add Aider tool that calls local Ollama (qwen2.5:14b) for AI coding assist
- Register tool in Forge's code toolkit
- Add functional tests for the Aider tool
* config: add opencode.json with local Ollama provider for sovereign AI
* feat: Timmy fixes and improvements
## Bug Fixes
- Fix read_file path resolution: add ~ expansion, proper relative path handling
- Add repo_root to config.py with auto-detection from .git location
- Fix hardcoded llama3.2 - now dynamic from settings.ollama_model
## Timmy's Requests
- Add communication protocol to AGENTS.md (read context first, explain changes)
- Create DECISIONS.md for architectural decision documentation
- Add reasoning guidance to system prompts (step-by-step, state uncertainty)
- Update tests to reflect correct model name (llama3.1:8b-instruct)
## Testing
- All 177 dashboard tests pass
- All 32 prompt/tool tests pass
* feat: Timmy system introspection, delegation, and session logging
## System Introspection (Sovereign Self-Knowledge)
- Add get_system_info() tool - Timmy can now query his runtime environment
- Add check_ollama_health() - verify Ollama status
- Add get_memory_status() - check memory tier status
- True introspection vs hardcoded prompts
## Path Resolution Fix
- Fix all toolkits to use settings.repo_root consistently
- Now uses Path(settings.repo_root) instead of Path.cwd()
## Inter-Agent Delegation
- Add delegate_task() tool - Timmy can dispatch to Seer, Forge, Echo, etc.
- Add list_swarm_agents() - query available agents
## Session Logging
- Add SessionLogger for comprehensive interaction logging
- Records messages, tool calls, errors, decisions
- Writes to /logs/session_{date}.jsonl
## Tests
- Add tests for introspection tools
- Add tests for delegation tools
- Add tests for session logging
- Add tests for path resolution
- All 18 new tests pass
- All 177 dashboard tests pass
---------
Co-authored-by: Alexander Payne <apayne@MM.local>
2026-02-27 00:11:53 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_check_ollama_health_returns_dict():
|
|
|
|
|
"""Ollama health check should return a dictionary."""
|
|
|
|
|
from timmy.tools_intro import check_ollama_health
|
|
|
|
|
|
|
|
|
|
result = check_ollama_health()
|
|
|
|
|
|
|
|
|
|
assert isinstance(result, dict)
|
|
|
|
|
assert "accessible" in result
|
|
|
|
|
assert "model" in result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_memory_status_returns_dict():
|
|
|
|
|
"""Memory status should return a dictionary with tier info."""
|
|
|
|
|
from timmy.tools_intro import get_memory_status
|
|
|
|
|
|
|
|
|
|
status = get_memory_status()
|
|
|
|
|
|
|
|
|
|
assert isinstance(status, dict)
|
|
|
|
|
assert "tier1_hot_memory" in status
|
|
|
|
|
assert "tier2_vault" in status
|
2026-03-14 18:02:14 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- _get_ollama_model exact-match tests (issue #77) ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _mock_response(json_data, status_code=200):
|
|
|
|
|
"""Create a mock httpx response."""
|
|
|
|
|
resp = MagicMock(spec=httpx.Response)
|
|
|
|
|
resp.status_code = status_code
|
|
|
|
|
resp.json.return_value = json_data
|
|
|
|
|
return resp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestGetOllamaModelExactMatch:
|
|
|
|
|
"""Ensure _get_ollama_model uses exact match, not prefix match."""
|
|
|
|
|
|
|
|
|
|
@patch("timmy.tools_intro.httpx.get")
|
|
|
|
|
def test_exact_match_from_ps(self, mock_get):
|
|
|
|
|
"""Should return exact model from /api/ps."""
|
|
|
|
|
from timmy.tools_intro import _get_ollama_model
|
|
|
|
|
|
|
|
|
|
ps_resp = _mock_response({"models": [{"name": "qwen3:30b"}]})
|
|
|
|
|
mock_get.return_value = ps_resp
|
|
|
|
|
|
|
|
|
|
with patch("config.settings") as mock_settings:
|
|
|
|
|
mock_settings.ollama_model = "qwen3:30b"
|
|
|
|
|
mock_settings.ollama_url = "http://localhost:11434"
|
|
|
|
|
result = _get_ollama_model()
|
|
|
|
|
|
|
|
|
|
assert result == "qwen3:30b"
|
|
|
|
|
|
|
|
|
|
@patch("timmy.tools_intro.httpx.get")
|
|
|
|
|
def test_prefix_collision_returns_correct_model(self, mock_get):
|
2026-03-15 12:34:21 -04:00
|
|
|
"""qwen3:8b configured — must NOT match qwen3:30b (prefix bug)."""
|
2026-03-14 18:02:14 -04:00
|
|
|
from timmy.tools_intro import _get_ollama_model
|
|
|
|
|
|
2026-03-15 12:34:21 -04:00
|
|
|
# /api/ps has both models loaded; configured is qwen3:8b
|
|
|
|
|
ps_resp = _mock_response({"models": [{"name": "qwen3:30b"}, {"name": "qwen3:8b"}]})
|
2026-03-14 18:02:14 -04:00
|
|
|
mock_get.return_value = ps_resp
|
|
|
|
|
|
|
|
|
|
with patch("config.settings") as mock_settings:
|
2026-03-15 12:34:21 -04:00
|
|
|
mock_settings.ollama_model = "qwen3:8b"
|
2026-03-14 18:02:14 -04:00
|
|
|
mock_settings.ollama_url = "http://localhost:11434"
|
|
|
|
|
result = _get_ollama_model()
|
|
|
|
|
|
2026-03-15 12:34:21 -04:00
|
|
|
assert result == "qwen3:8b", f"Got '{result}' — prefix collision bug!"
|
2026-03-14 18:02:14 -04:00
|
|
|
|
|
|
|
|
@patch("timmy.tools_intro.httpx.get")
|
|
|
|
|
def test_configured_model_not_running_returns_actual(self, mock_get):
|
|
|
|
|
"""If configured model isn't loaded, report what IS running."""
|
|
|
|
|
from timmy.tools_intro import _get_ollama_model
|
|
|
|
|
|
2026-03-15 12:34:21 -04:00
|
|
|
ps_resp = _mock_response({"models": [{"name": "qwen3:30b"}]})
|
2026-03-14 18:02:14 -04:00
|
|
|
mock_get.return_value = ps_resp
|
|
|
|
|
|
|
|
|
|
with patch("config.settings") as mock_settings:
|
2026-03-15 12:34:21 -04:00
|
|
|
mock_settings.ollama_model = "qwen3:8b"
|
2026-03-14 18:02:14 -04:00
|
|
|
mock_settings.ollama_url = "http://localhost:11434"
|
|
|
|
|
result = _get_ollama_model()
|
|
|
|
|
|
|
|
|
|
# Should report actual running model, not configured one
|
2026-03-15 12:34:21 -04:00
|
|
|
assert result == "qwen3:30b"
|
2026-03-14 18:02:14 -04:00
|
|
|
|
|
|
|
|
@patch("timmy.tools_intro.httpx.get")
|
|
|
|
|
def test_latest_suffix_match(self, mock_get):
|
|
|
|
|
"""'qwen3:30b' config should match 'qwen3:30b:latest' from API."""
|
|
|
|
|
from timmy.tools_intro import _get_ollama_model
|
|
|
|
|
|
|
|
|
|
ps_resp = _mock_response({"models": []})
|
|
|
|
|
tags_resp = _mock_response({"models": [{"name": "qwen3:30b:latest"}]})
|
|
|
|
|
mock_get.side_effect = [ps_resp, tags_resp]
|
|
|
|
|
|
|
|
|
|
with patch("config.settings") as mock_settings:
|
|
|
|
|
mock_settings.ollama_model = "qwen3:30b"
|
|
|
|
|
mock_settings.ollama_url = "http://localhost:11434"
|
|
|
|
|
result = _get_ollama_model()
|
|
|
|
|
|
|
|
|
|
# Falls back to configured since no exact match
|
|
|
|
|
assert result == "qwen3:30b"
|
|
|
|
|
|
|
|
|
|
@patch("timmy.tools_intro.httpx.get")
|
|
|
|
|
def test_ollama_down_returns_configured(self, mock_get):
|
|
|
|
|
"""If Ollama is unreachable, return configured model."""
|
|
|
|
|
from timmy.tools_intro import _get_ollama_model
|
|
|
|
|
|
|
|
|
|
mock_get.side_effect = httpx.ConnectError("connection refused")
|
|
|
|
|
|
|
|
|
|
with patch("config.settings") as mock_settings:
|
|
|
|
|
mock_settings.ollama_model = "qwen3:30b"
|
|
|
|
|
mock_settings.ollama_url = "http://localhost:11434"
|
|
|
|
|
result = _get_ollama_model()
|
|
|
|
|
|
|
|
|
|
assert result == "qwen3:30b"
|
2026-03-14 20:28:24 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestRunSelfTests:
|
|
|
|
|
"""Tests for run_self_tests() — Timmy's self-verification tool."""
|
|
|
|
|
|
2026-03-15 12:17:50 -04:00
|
|
|
def test_returns_dict_with_expected_keys(self, monkeypatch, tmp_path):
|
2026-03-14 20:28:24 -04:00
|
|
|
"""run_self_tests should return structured test results."""
|
2026-03-15 12:17:50 -04:00
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
def mock_run(*args, **kwargs):
|
|
|
|
|
return subprocess.CompletedProcess(
|
|
|
|
|
args=args[0] if args else [],
|
|
|
|
|
returncode=0,
|
|
|
|
|
stdout="5 passed in 0.5s",
|
|
|
|
|
stderr="",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(subprocess, "run", mock_run)
|
|
|
|
|
|
|
|
|
|
# Create fake venv so check passes
|
|
|
|
|
venv_python = tmp_path / ".venv" / "bin" / "python"
|
|
|
|
|
venv_python.parent.mkdir(parents=True)
|
|
|
|
|
venv_python.write_text("#!/bin/sh\necho mock")
|
|
|
|
|
|
2026-03-14 20:28:24 -04:00
|
|
|
from timmy.tools_intro import run_self_tests
|
|
|
|
|
|
2026-03-15 12:17:50 -04:00
|
|
|
result = run_self_tests(scope="tests/timmy/test_introspection.py", _repo_root=str(tmp_path))
|
2026-03-14 20:28:24 -04:00
|
|
|
assert isinstance(result, dict)
|
|
|
|
|
assert "success" in result
|
2026-03-15 12:17:50 -04:00
|
|
|
assert result["success"] is True
|
|
|
|
|
assert "passed" in result
|
|
|
|
|
assert "failed" in result
|
|
|
|
|
assert "total" in result
|
|
|
|
|
assert result["passed"] == 5
|
|
|
|
|
assert result["total"] == 5
|
2026-03-14 20:28:24 -04:00
|
|
|
|
|
|
|
|
def test_fast_scope_skips_integration(self, monkeypatch, tmp_path):
|
|
|
|
|
"""Fast scope should exclude functional/e2e/integration dirs."""
|
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
calls = []
|
|
|
|
|
|
|
|
|
|
def capture_run(*args, **kwargs):
|
|
|
|
|
calls.append(args[0] if args else kwargs.get("cmd"))
|
|
|
|
|
# Return a fake result
|
|
|
|
|
return subprocess.CompletedProcess(
|
|
|
|
|
args=args[0] if args else [], returncode=0, stdout="1 passed in 0.5s", stderr=""
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(subprocess, "run", capture_run)
|
|
|
|
|
|
|
|
|
|
# Create fake venv so check passes
|
|
|
|
|
venv_python = tmp_path / ".venv" / "bin" / "python"
|
|
|
|
|
venv_python.parent.mkdir(parents=True)
|
|
|
|
|
venv_python.write_text("#!/bin/sh\necho mock")
|
|
|
|
|
|
|
|
|
|
from timmy.tools_intro import run_self_tests
|
|
|
|
|
|
|
|
|
|
run_self_tests(scope="fast", _repo_root=str(tmp_path))
|
|
|
|
|
assert len(calls) == 1
|
|
|
|
|
cmd = calls[0]
|
|
|
|
|
assert "--ignore=tests/functional" in cmd
|
|
|
|
|
assert "--ignore=tests/e2e" in cmd
|
|
|
|
|
|
|
|
|
|
def test_specific_path_scope(self, monkeypatch, tmp_path):
|
|
|
|
|
"""Specific path scope passes path directly to pytest."""
|
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
calls = []
|
|
|
|
|
|
|
|
|
|
def capture_run(*args, **kwargs):
|
|
|
|
|
calls.append(args[0] if args else kwargs.get("cmd"))
|
|
|
|
|
return subprocess.CompletedProcess(
|
|
|
|
|
args=args[0] if args else [], returncode=0, stdout="5 passed in 1.0s", stderr=""
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(subprocess, "run", capture_run)
|
|
|
|
|
|
|
|
|
|
# Create fake venv so check passes
|
|
|
|
|
venv_python = tmp_path / ".venv" / "bin" / "python"
|
|
|
|
|
venv_python.parent.mkdir(parents=True)
|
|
|
|
|
venv_python.write_text("#!/bin/sh\necho mock")
|
|
|
|
|
|
|
|
|
|
from timmy.tools_intro import run_self_tests
|
|
|
|
|
|
|
|
|
|
run_self_tests(scope="tests/timmy/", _repo_root=str(tmp_path))
|
|
|
|
|
assert len(calls) == 1
|
|
|
|
|
assert "tests/timmy/" in calls[0]
|
|
|
|
|
|
|
|
|
|
def test_missing_venv_returns_error(self, monkeypatch, tmp_path):
|
|
|
|
|
"""Should handle missing venv gracefully."""
|
|
|
|
|
from timmy.tools_intro import run_self_tests
|
|
|
|
|
|
|
|
|
|
result = run_self_tests(_repo_root=str(tmp_path))
|
|
|
|
|
assert result["success"] is False
|
|
|
|
|
assert "venv" in result.get("error", "").lower()
|
|
|
|
|
|
|
|
|
|
def test_timeout_returns_error(self, monkeypatch, tmp_path):
|
|
|
|
|
"""Should handle subprocess timeout gracefully."""
|
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
def timeout_run(*args, **kwargs):
|
|
|
|
|
raise subprocess.TimeoutExpired(cmd="pytest", timeout=120)
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(subprocess, "run", timeout_run)
|
|
|
|
|
|
|
|
|
|
# Create fake venv so check passes
|
|
|
|
|
venv_python = tmp_path / ".venv" / "bin" / "python"
|
|
|
|
|
venv_python.parent.mkdir(parents=True)
|
|
|
|
|
venv_python.write_text("#!/bin/sh\necho mock")
|
|
|
|
|
|
|
|
|
|
from timmy.tools_intro import run_self_tests
|
|
|
|
|
|
|
|
|
|
result = run_self_tests(_repo_root=str(tmp_path))
|
|
|
|
|
assert result["success"] is False
|
|
|
|
|
assert "timed out" in result.get("error", "").lower()
|