mirror of
https://github.com/Xe138/AI-Trader.git
synced 2026-04-07 11:17:25 -04:00
feat: transform to REST API service with SQLite persistence (v0.3.0)
Major architecture transformation from batch-only to API service with
database persistence for Windmill integration.
## REST API Implementation
- POST /simulate/trigger - Start simulation jobs
- GET /simulate/status/{job_id} - Monitor job progress
- GET /results - Query results with filters (job_id, date, model)
- GET /health - Service health checks
## Database Layer
- SQLite persistence with 6 tables (jobs, job_details, positions,
holdings, reasoning_logs, tool_usage)
- Foreign key constraints with cascade deletes
- Replaces JSONL file storage
## Backend Components
- JobManager: Job lifecycle management with concurrency control
- RuntimeConfigManager: Thread-safe isolated runtime configs
- ModelDayExecutor: Single model-day execution engine
- SimulationWorker: Date-sequential, model-parallel orchestration
## Testing
- 102 unit and integration tests (85% coverage)
- Database: 98% coverage
- Job manager: 98% coverage
- API endpoints: 81% coverage
- Pydantic models: 100% coverage
- TDD approach throughout
## Docker Deployment
- Dual-mode: API server (persistent) + batch (one-time)
- Health checks with 30s interval
- Volume persistence for database and logs
- Separate entrypoints for each mode
## Validation Tools
- scripts/validate_docker_build.sh - Build validation
- scripts/test_api_endpoints.sh - Complete API testing
- scripts/test_batch_mode.sh - Batch mode validation
- DOCKER_API.md - Deployment guide
- TESTING_GUIDE.md - Testing procedures
## Configuration
- API_PORT environment variable (default: 8080)
- Backwards compatible with existing configs
- FastAPI, uvicorn, pydantic>=2.0 dependencies
Co-Authored-By: AI Assistant <noreply@example.com>
This commit is contained in:
140
tests/conftest.py
Normal file
140
tests/conftest.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
Shared pytest fixtures for AI-Trader API tests.
|
||||
|
||||
This module provides reusable fixtures for:
|
||||
- Test database setup/teardown
|
||||
- Mock configurations
|
||||
- Test data factories
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
from api.database import initialize_database, get_db_connection
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def test_db_path():
|
||||
"""Create temporary database file for testing session."""
|
||||
temp_db = tempfile.NamedTemporaryFile(delete=False, suffix=".db")
|
||||
temp_db.close()
|
||||
|
||||
yield temp_db.name
|
||||
|
||||
# Cleanup after all tests
|
||||
try:
|
||||
os.unlink(temp_db.name)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def clean_db(test_db_path):
|
||||
"""
|
||||
Provide clean database for each test function.
|
||||
|
||||
This fixture:
|
||||
1. Initializes schema if needed
|
||||
2. Clears all data before test
|
||||
3. Returns database path
|
||||
|
||||
Usage:
|
||||
def test_something(clean_db):
|
||||
conn = get_db_connection(clean_db)
|
||||
# ... test code
|
||||
"""
|
||||
# Ensure schema exists
|
||||
initialize_database(test_db_path)
|
||||
|
||||
# Clear all tables
|
||||
conn = get_db_connection(test_db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Delete in correct order (respecting foreign keys)
|
||||
cursor.execute("DELETE FROM tool_usage")
|
||||
cursor.execute("DELETE FROM reasoning_logs")
|
||||
cursor.execute("DELETE FROM holdings")
|
||||
cursor.execute("DELETE FROM positions")
|
||||
cursor.execute("DELETE FROM job_details")
|
||||
cursor.execute("DELETE FROM jobs")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return test_db_path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_job_data():
|
||||
"""Sample job data for testing."""
|
||||
return {
|
||||
"job_id": "test-job-123",
|
||||
"config_path": "configs/test.json",
|
||||
"status": "pending",
|
||||
"date_range": '["2025-01-16", "2025-01-17"]',
|
||||
"models": '["gpt-5", "claude-3.7-sonnet"]',
|
||||
"created_at": "2025-01-20T14:30:00Z"
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_position_data():
|
||||
"""Sample position data for testing."""
|
||||
return {
|
||||
"job_id": "test-job-123",
|
||||
"date": "2025-01-16",
|
||||
"model": "gpt-5",
|
||||
"action_id": 1,
|
||||
"action_type": "buy",
|
||||
"symbol": "AAPL",
|
||||
"amount": 10,
|
||||
"price": 255.88,
|
||||
"cash": 7441.2,
|
||||
"portfolio_value": 10000.0,
|
||||
"daily_profit": 0.0,
|
||||
"daily_return_pct": 0.0,
|
||||
"cumulative_profit": 0.0,
|
||||
"cumulative_return_pct": 0.0,
|
||||
"created_at": "2025-01-16T09:30:00Z"
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_config():
|
||||
"""Mock configuration for testing."""
|
||||
return {
|
||||
"agent_type": "BaseAgent",
|
||||
"date_range": {
|
||||
"init_date": "2025-01-16",
|
||||
"end_date": "2025-01-17"
|
||||
},
|
||||
"models": [
|
||||
{
|
||||
"name": "test-model",
|
||||
"basemodel": "openai/gpt-4",
|
||||
"signature": "test-model",
|
||||
"enabled": True
|
||||
}
|
||||
],
|
||||
"agent_config": {
|
||||
"max_steps": 10,
|
||||
"max_retries": 3,
|
||||
"base_delay": 0.5,
|
||||
"initial_cash": 10000.0
|
||||
},
|
||||
"log_config": {
|
||||
"log_path": "./data/agent_data"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Pytest configuration hooks
|
||||
def pytest_configure(config):
|
||||
"""Configure pytest with custom markers."""
|
||||
config.addinivalue_line("markers", "unit: Unit tests (fast, isolated)")
|
||||
config.addinivalue_line("markers", "integration: Integration tests (with dependencies)")
|
||||
config.addinivalue_line("markers", "performance: Performance and benchmark tests")
|
||||
config.addinivalue_line("markers", "security: Security tests")
|
||||
config.addinivalue_line("markers", "e2e: End-to-end tests (Docker required)")
|
||||
config.addinivalue_line("markers", "slow: Tests that take >10 seconds")
|
||||
Reference in New Issue
Block a user