Archon/python/tests/test_token_optimization_integration.py
Rasmus Widing c19e85f0c9 fix: include_archived flag now works correctly in task listing
- Add include_archived parameter to TaskService.list_tasks()
- Service now conditionally applies archived filter based on parameter
- Add 'archived' field to task DTO for client visibility
- Update API endpoints to pass include_archived down to service
- Remove redundant client-side filtering in API layer
- Fix type hints in integration tests (dict[str, Any] | None)
- Use pytest.skip() instead of return for proper test reporting

These fixes address the functional bug identified by CodeRabbit where
archived tasks couldn't be retrieved even when explicitly requested.
2025-08-27 11:05:33 +03:00

188 lines
7.4 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Integration tests to verify token optimization in running system.
Run with: uv run pytest tests/test_token_optimization_integration.py -v
"""
import httpx
import json
import asyncio
import pytest
from typing import Dict, Any, Tuple
async def measure_response_size(url: str, params: dict[str, Any] | None = None) -> tuple[int, float]:
"""Measure response size and estimate token count."""
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, params=params, timeout=10.0)
response_text = response.text
response_size = len(response_text)
# Rough token estimate: 1 token ≈ 4 characters
estimated_tokens = response_size / 4
return response_size, estimated_tokens
except httpx.ConnectError:
print(f"⚠️ Could not connect to {url} - is the server running?")
return 0, 0
except Exception as e:
print(f"❌ Error measuring {url}: {e}")
return 0, 0
async def test_projects_endpoint():
"""Test /api/projects with and without include_content."""
base_url = "http://localhost:8181/api/projects"
print("\n=== Testing Projects Endpoint ===")
# Test with full content (backward compatibility)
size_full, tokens_full = await measure_response_size(base_url, {"include_content": "true"})
if size_full > 0:
print(f"Full content: {size_full:,} bytes | ~{tokens_full:,.0f} tokens")
else:
pytest.skip("Server not available on http://localhost:8181")
# Test lightweight
size_light, tokens_light = await measure_response_size(base_url, {"include_content": "false"})
print(f"Lightweight: {size_light:,} bytes | ~{tokens_light:,.0f} tokens")
# Calculate reduction
if size_full > 0:
reduction = (1 - size_light / size_full) * 100 if size_full > size_light else 0
print(f"Reduction: {reduction:.1f}%")
if reduction > 50:
print("✅ Significant token reduction achieved!")
else:
print("⚠️ Token reduction less than expected")
# Verify backward compatibility - default should include content
size_default, _ = await measure_response_size(base_url)
if size_default > 0:
if abs(size_default - size_full) < 100: # Allow small variation
print("✅ Backward compatibility maintained (default includes content)")
else:
print("⚠️ Default behavior may have changed")
async def test_tasks_endpoint():
"""Test /api/tasks with exclude_large_fields."""
base_url = "http://localhost:8181/api/tasks"
print("\n=== Testing Tasks Endpoint ===")
# Test with full content
size_full, tokens_full = await measure_response_size(base_url, {"exclude_large_fields": "false"})
if size_full > 0:
print(f"Full content: {size_full:,} bytes | ~{tokens_full:,.0f} tokens")
else:
pytest.skip("Server not available on http://localhost:8181")
# Test lightweight
size_light, tokens_light = await measure_response_size(base_url, {"exclude_large_fields": "true"})
print(f"Lightweight: {size_light:,} bytes | ~{tokens_light:,.0f} tokens")
# Calculate reduction
if size_full > size_light:
reduction = (1 - size_light / size_full) * 100
print(f"Reduction: {reduction:.1f}%")
if reduction > 30: # Tasks may have less reduction if fewer have large fields
print("✅ Token reduction achieved for tasks!")
else:
print(" Minimal reduction (tasks may not have large fields)")
async def test_documents_endpoint():
"""Test /api/projects/{id}/docs with include_content."""
# First get a project ID if available
async with httpx.AsyncClient() as client:
try:
response = await client.get(
"http://localhost:8181/api/projects",
params={"include_content": "false"},
timeout=10.0
)
if response.status_code == 200:
projects = response.json()
if projects and len(projects) > 0:
project_id = projects[0]["id"]
print(f"\n=== Testing Documents Endpoint (Project: {project_id[:8]}...) ===")
base_url = f"http://localhost:8181/api/projects/{project_id}/docs"
# Test with content
size_full, tokens_full = await measure_response_size(base_url, {"include_content": "true"})
print(f"With content: {size_full:,} bytes | ~{tokens_full:,.0f} tokens")
# Test without content (default)
size_light, tokens_light = await measure_response_size(base_url, {"include_content": "false"})
print(f"Metadata only: {size_light:,} bytes | ~{tokens_light:,.0f} tokens")
# Calculate reduction if there are documents
if size_full > size_light and size_full > 500: # Only if meaningful data
reduction = (1 - size_light / size_full) * 100
print(f"Reduction: {reduction:.1f}%")
print("✅ Document endpoint optimized!")
else:
print(" No documents or minimal content in project")
else:
print("\n⚠️ No projects available for document testing")
except Exception as e:
print(f"\n⚠️ Could not test documents endpoint: {e}")
async def test_mcp_endpoints():
"""Test MCP endpoints if available."""
mcp_url = "http://localhost:8051/health"
print("\n=== Testing MCP Server ===")
async with httpx.AsyncClient() as client:
try:
response = await client.get(mcp_url, timeout=5.0)
if response.status_code == 200:
print("✅ MCP server is running")
# Could add specific MCP tool tests here
else:
print(f"⚠️ MCP server returned status {response.status_code}")
except httpx.ConnectError:
print(" MCP server not running (optional for tests)")
except Exception as e:
print(f"⚠️ Could not check MCP server: {e}")
async def main():
"""Run all integration tests."""
print("=" * 60)
print("Token Optimization Integration Tests")
print("=" * 60)
# Check if server is running
async with httpx.AsyncClient() as client:
try:
response = await client.get("http://localhost:8181/health", timeout=5.0)
if response.status_code == 200:
print("✅ Server is healthy and running")
else:
print(f"⚠️ Server returned status {response.status_code}")
except httpx.ConnectError:
print("❌ Server is not running! Start with: docker-compose up -d")
print("\nTests require a running server. Please start the services first.")
return
except Exception as e:
print(f"❌ Error checking server health: {e}")
return
# Run tests
await test_projects_endpoint()
await test_tasks_endpoint()
await test_documents_endpoint()
await test_mcp_endpoints()
print("\n" + "=" * 60)
print("✅ Integration tests completed!")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())