"""Integration tests for direct database access feature.""" import sqlite3 from pathlib import Path import pytest from xer_mcp.db import db @pytest.fixture(autouse=True) def setup_db(): """Reset database state for each test.""" if db.is_initialized: db.close() yield if db.is_initialized: db.close() class TestDirectDatabaseAccess: """Integration tests verifying external script can access database.""" async def test_external_script_can_query_database( self, tmp_path: Path, sample_xer_single_project: Path ) -> None: """External script can query database using returned path.""" from xer_mcp.tools.load_xer import load_xer db_file = tmp_path / "schedule.db" result = await load_xer( file_path=str(sample_xer_single_project), db_path=str(db_file), ) # Simulate external script access (as shown in quickstart.md) db_path = result["database"]["db_path"] conn = sqlite3.connect(db_path) conn.row_factory = sqlite3.Row # Query milestones cursor = conn.execute(""" SELECT task_code, task_name, target_start_date, milestone_type FROM activities WHERE task_type IN ('TT_Mile', 'TT_FinMile') ORDER BY target_start_date """) milestones = cursor.fetchall() conn.close() assert len(milestones) > 0 assert all(row["task_code"] for row in milestones) async def test_external_script_can_query_critical_path( self, tmp_path: Path, sample_xer_single_project: Path ) -> None: """External script can query critical path activities.""" from xer_mcp.tools.load_xer import load_xer db_file = tmp_path / "schedule.db" result = await load_xer( file_path=str(sample_xer_single_project), db_path=str(db_file), ) db_path = result["database"]["db_path"] conn = sqlite3.connect(db_path) cursor = conn.execute(""" SELECT task_code, task_name, target_start_date, target_end_date FROM activities WHERE driving_path_flag = 1 ORDER BY target_start_date """) critical_activities = cursor.fetchall() conn.close() assert len(critical_activities) > 0 async def test_external_script_can_join_tables( self, tmp_path: Path, sample_xer_single_project: Path ) -> None: """External script can join activities with WBS.""" from xer_mcp.tools.load_xer import load_xer db_file = tmp_path / "schedule.db" result = await load_xer( file_path=str(sample_xer_single_project), db_path=str(db_file), ) db_path = result["database"]["db_path"] conn = sqlite3.connect(db_path) cursor = conn.execute(""" SELECT a.task_code, a.task_name, w.wbs_name FROM activities a JOIN wbs w ON a.wbs_id = w.wbs_id LIMIT 10 """) joined_rows = cursor.fetchall() conn.close() assert len(joined_rows) > 0 async def test_database_accessible_after_mcp_load( self, tmp_path: Path, sample_xer_single_project: Path ) -> None: """Database remains accessible while MCP tools are active.""" from xer_mcp.tools.load_xer import load_xer db_file = tmp_path / "schedule.db" result = await load_xer( file_path=str(sample_xer_single_project), db_path=str(db_file), ) loaded_count = result["activity_count"] # External script queries database conn = sqlite3.connect(str(db_file)) cursor = conn.execute("SELECT COUNT(*) FROM activities") external_count = cursor.fetchone()[0] conn.close() # Both should match assert external_count == loaded_count async def test_schema_info_matches_actual_database( self, tmp_path: Path, sample_xer_single_project: Path ) -> None: """Returned schema info matches actual database structure.""" from xer_mcp.tools.load_xer import load_xer db_file = tmp_path / "schedule.db" result = await load_xer( file_path=str(sample_xer_single_project), db_path=str(db_file), ) schema = result["database"]["schema"] db_path = result["database"]["db_path"] # Verify tables exist in actual database conn = sqlite3.connect(db_path) cursor = conn.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'" ) actual_tables = {row[0] for row in cursor.fetchall()} conn.close() schema_tables = {t["name"] for t in schema["tables"]} assert schema_tables == actual_tables async def test_row_counts_match_actual_data( self, tmp_path: Path, sample_xer_single_project: Path ) -> None: """Schema row counts match actual database row counts.""" from xer_mcp.tools.load_xer import load_xer db_file = tmp_path / "schedule.db" result = await load_xer( file_path=str(sample_xer_single_project), db_path=str(db_file), ) schema = result["database"]["schema"] db_path = result["database"]["db_path"] conn = sqlite3.connect(db_path) for table_info in schema["tables"]: cursor = conn.execute( f"SELECT COUNT(*) FROM {table_info['name']}" # noqa: S608 ) actual_count = cursor.fetchone()[0] assert table_info["row_count"] == actual_count, ( f"Table {table_info['name']}: expected {table_info['row_count']}, " f"got {actual_count}" ) conn.close()