| """ |
| End-to-End Database Integration Tests |
| |
| This module provides comprehensive E2E tests for database integration covering: |
| - PostgreSQL operations (CRUD, transactions, foreign keys) |
| - SQLite operations (Personal Edition, cross-platform, WAL mode) |
| - Connection pooling (reuse, exhaustion, cleanup) |
| - Alembic migrations (upgrade, downgrade, idempotency) |
| - Backup/restore (data integrity, consistency) |
| |
| All tests use real database services (PostgreSQL in Docker, SQLite in-memory). |
| """ |
|
|
| import os |
| import sys |
| import pytest |
| import uuid |
| from datetime import datetime, timedelta |
| from pathlib import Path |
| from typing import Dict, Any |
| from sqlalchemy import text, inspect |
| from sqlalchemy.exc import IntegrityError, OperationalError |
|
|
| |
| backend_dir = Path(__file__).parent.parent |
| sys.path.insert(0, str(backend_dir)) |
|
|
| from core.models import ( |
| Base, AgentRegistry, AgentExecution, AgentFeedback, |
| CanvasAudit, Episode, EpisodeSegment |
| ) |
|
|
| |
| from tests.e2e.fixtures.database_fixtures import ( |
| e2e_postgres_session, e2e_sqlite_session, |
| fresh_database, seed_test_data, |
| database_backup, connection_pool, cross_platform_sqlite |
| ) |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_postgres_migration_flow(fresh_database): |
| """ |
| Test all Alembic migrations run successfully. |
| |
| Verifies: |
| - All migrations apply without errors |
| - All expected tables are created |
| - Schema is consistent with models |
| """ |
| print("\n=== Testing PostgreSQL Migration Flow ===") |
|
|
| |
| inspector = inspect(fresh_database) |
| tables = inspector.get_table_names() |
|
|
| print(f"Found {len(tables)} tables after migrations") |
|
|
| |
| expected_tables = [ |
| "agent_registry", |
| "agent_execution", |
| "agent_feedback", |
| "canvas_audit", |
| "episodes", |
| "episode_segments", |
| ] |
|
|
| for table in expected_tables: |
| assert table in tables, f"Expected table '{table}' not found after migrations" |
| print(f"✓ Table {table} exists") |
|
|
| |
| for table_name in expected_tables: |
| columns = [col["name"] for col in inspector.get_columns(table_name)] |
| print(f" {table_name}: {', '.join(columns[:5])}...") |
|
|
| print(f"\n✓ All migrations applied successfully") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_postgres_crud_operations(e2e_postgres_session): |
| """ |
| Test CRUD operations with real PostgreSQL. |
| |
| Verifies: |
| - Create: Insert records |
| - Read: Query records with filters |
| - Update: Modify existing records |
| - Delete: Remove records |
| """ |
| print("\n=== Testing PostgreSQL CRUD Operations ===") |
|
|
| |
| agent_id = f"crud-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="CRUD Test Agent", |
| description="Testing CRUD operations", |
| category="Testing", |
| module_path="test.crud", |
| class_name="CRUDAgent", |
| status="INTERN", |
| confidence_score=0.7, |
| ) |
| e2e_postgres_session.add(agent) |
| e2e_postgres_session.commit() |
| print(f"✓ Created agent: {agent_id}") |
|
|
| |
| retrieved = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| assert retrieved is not None, "Failed to retrieve created agent" |
| assert retrieved.name == "CRUD Test Agent" |
| assert retrieved.status == "INTERN" |
| print(f"✓ Retrieved agent: {retrieved.name}") |
|
|
| |
| retrieved.description = "Updated description" |
| retrieved.confidence_score = 0.8 |
| e2e_postgres_session.commit() |
| print(f"✓ Updated agent description and confidence") |
|
|
| |
| updated = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| assert updated.description == "Updated description" |
| assert updated.confidence_score == 0.8 |
| print(f"✓ Verified update: {updated.description}") |
|
|
| |
| e2e_postgres_session.delete(updated) |
| e2e_postgres_session.commit() |
| print(f"✓ Deleted agent") |
|
|
| |
| deleted = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| assert deleted is None, "Agent should be deleted" |
| print(f"✓ Verified deletion") |
|
|
| print("\n✓ All CRUD operations successful") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_postgres_transaction_rollback(e2e_postgres_session): |
| """ |
| Test transaction rollback on error. |
| |
| Verifies: |
| - Transactions roll back on error |
| - Partial updates are not committed |
| - Database state remains consistent |
| """ |
| print("\n=== Testing PostgreSQL Transaction Rollback ===") |
|
|
| |
| agent_id = f"rollback-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="Rollback Test Agent", |
| description="Initial state", |
| category="Testing", |
| module_path="test.rollback", |
| class_name="RollbackAgent", |
| status="INTERN", |
| confidence_score=0.6, |
| ) |
| e2e_postgres_session.add(agent) |
| e2e_postgres_session.commit() |
| print(f"✓ Created initial agent: {agent_id}") |
|
|
| |
| try: |
| |
| agent.description = "This will be rolled back" |
| agent.confidence_score = 0.9 |
|
|
| |
| duplicate_agent = AgentRegistry( |
| id=agent_id, |
| name="Duplicate Agent", |
| description="This should fail", |
| category="Testing", |
| module_path="test.duplicate", |
| class_name="DuplicateAgent", |
| status="INTERN", |
| confidence_score=0.5, |
| ) |
| e2e_postgres_session.add(duplicate_agent) |
| e2e_postgres_session.commit() |
|
|
| assert False, "Transaction should have failed" |
| except IntegrityError: |
| e2e_postgres_session.rollback() |
| print(f"✓ Transaction rolled back due to integrity error") |
|
|
| |
| retrieved = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| assert retrieved is not None, "Agent should still exist" |
| assert retrieved.description == "Initial state", "Description should not be updated" |
| assert retrieved.confidence_score == 0.6, "Confidence should not be updated" |
| print(f"✓ Original state preserved after rollback") |
|
|
| print("\n✓ Transaction rollback working correctly") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_postgres_foreign_key_constraints(e2e_postgres_session): |
| """ |
| Test foreign key constraint enforcement. |
| |
| Verifies: |
| - Foreign keys are enforced |
| - Cannot reference non-existent records |
| - Cascade deletes work correctly |
| """ |
| print("\n=== Testing PostgreSQL Foreign Key Constraints ===") |
|
|
| |
| agent_id = f"fk-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="FK Test Agent", |
| description="Testing foreign keys", |
| category="Testing", |
| module_path="test.fk", |
| class_name="FKAgent", |
| status="INTERN", |
| confidence_score=0.7, |
| ) |
| e2e_postgres_session.add(agent) |
| e2e_postgres_session.commit() |
| print(f"✓ Created agent: {agent_id}") |
|
|
| |
| execution = AgentExecution( |
| agent_id=agent_id, |
| user_id="test-user", |
| status="completed", |
| input_data={"test": "data"}, |
| output_data={"result": "success"}, |
| started_at=datetime.utcnow(), |
| completed_at=datetime.utcnow(), |
| ) |
| e2e_postgres_session.add(execution) |
| e2e_postgres_session.commit() |
| print(f"✓ Created execution with valid FK") |
|
|
| |
| try: |
| invalid_execution = AgentExecution( |
| agent_id="non-existent-agent", |
| user_id="test-user", |
| status="pending", |
| input_data={"test": "data"}, |
| started_at=datetime.utcnow(), |
| ) |
| e2e_postgres_session.add(invalid_execution) |
| e2e_postgres_session.commit() |
| assert False, "Should have failed with FK violation" |
| except IntegrityError: |
| e2e_postgres_session.rollback() |
| print(f"✓ FK constraint enforced for invalid agent_id") |
|
|
| print("\n✓ Foreign key constraints working correctly") |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.e2e |
| def test_sqlite_cross_platform(e2e_sqlite_session): |
| """ |
| Test SQLite cross-platform compatibility for Personal Edition. |
| |
| Verifies: |
| - SQLite works on different platforms |
| - Personal Edition schema is compatible |
| - Basic CRUD operations work |
| """ |
| print("\n=== Testing SQLite Cross-Platform Compatibility ===") |
|
|
| |
| agent_id = f"sqlite-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="SQLite Test Agent", |
| description="Testing Personal Edition", |
| category="Testing", |
| module_path="test.sqlite", |
| class_name="SQLiteAgent", |
| status="INTERN", |
| confidence_score=0.7, |
| ) |
| e2e_sqlite_session.add(agent) |
| e2e_sqlite_session.commit() |
| print(f"✓ Created agent in SQLite: {agent_id}") |
|
|
| |
| retrieved = e2e_sqlite_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| assert retrieved is not None |
| assert retrieved.name == "SQLite Test Agent" |
| print(f"✓ Retrieved agent from SQLite") |
|
|
| |
| retrieved.description = "Personal Edition compatible" |
| e2e_sqlite_session.commit() |
| print(f"✓ Updated agent in SQLite") |
|
|
| |
| import platform |
| print(f"✓ Running on {platform.system()} {platform.release()}") |
|
|
| print("\n✓ SQLite cross-platform compatibility verified") |
|
|
|
|
| @pytest.mark.e2e |
| def test_sqlite_personal_edition_schema(e2e_sqlite_session): |
| """ |
| Test Personal Edition schema compatibility. |
| |
| Verifies: |
| - All required tables exist |
| - Schema matches PostgreSQL schema |
| - Personal Edition works correctly |
| """ |
| print("\n=== Testing SQLite Personal Edition Schema ===") |
|
|
| |
| from sqlalchemy import inspect |
| inspector = inspect(e2e_sqlite_session.bind) |
|
|
| |
| tables = inspector.get_table_names() |
| print(f"Found {len(tables)} tables in SQLite") |
|
|
| |
| expected_tables = [ |
| "agent_registry", |
| "agent_execution", |
| "canvas_audit", |
| ] |
|
|
| for table in expected_tables: |
| assert table in tables, f"Expected table '{table}' not found in SQLite" |
| print(f"✓ Table {table} exists in SQLite") |
|
|
| |
| agent_columns = [col["name"] for col in inspector.get_columns("agent_registry")] |
| required_columns = ["id", "name", "description", "status", "confidence_score"] |
| for col in required_columns: |
| assert col in agent_columns, f"Required column '{col}' not found in agent_registry" |
| print(f"✓ Column {col} exists in agent_registry") |
|
|
| print("\n✓ Personal Edition schema verified") |
|
|
|
|
| @pytest.mark.e2e |
| def test_sqlite_concurrent_access(cross_platform_sqlite): |
| """ |
| Test SQLite WAL mode for concurrent access. |
| |
| Verifies: |
| - WAL mode is enabled |
| - Multiple connections can read |
| - Write transactions are isolated |
| """ |
| print("\n=== Testing SQLite Concurrent Access (WAL Mode) ===") |
|
|
| wal_engine = cross_platform_sqlite["wal_mode"]["engine"] |
|
|
| |
| with wal_engine.connect() as conn: |
| result = conn.execute(text("PRAGMA journal_mode")).scalar() |
| assert result == "wal", f"WAL mode not enabled, got: {result}" |
| print(f"✓ WAL mode enabled: {result}") |
|
|
| |
| Session = sessionmaker(bind=wal_engine, autocommit=False, autoflush=False) |
| session1 = Session() |
|
|
| agent_id = f"concurrent-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="Concurrent Test Agent", |
| description="Testing WAL mode", |
| category="Testing", |
| module_path="test.concurrent", |
| class_name="ConcurrentAgent", |
| status="INTERN", |
| confidence_score=0.7, |
| ) |
| session1.add(agent) |
| session1.commit() |
| print(f"✓ Created agent in WAL mode: {agent_id}") |
|
|
| |
| session2 = Session() |
| retrieved = session2.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| assert retrieved is not None |
| print(f"✓ Second connection can read (WAL mode working)") |
|
|
| session1.close() |
| session2.close() |
|
|
| print("\n✓ SQLite concurrent access verified") |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_connection_pool_reuse(connection_pool): |
| """ |
| Test connection pool reuses connections. |
| |
| Verifies: |
| - Connections are reused |
| - Pool maintains configured size |
| - Multiple requests use same connections |
| """ |
| print("\n=== Testing Connection Pool Reuse ===") |
|
|
| |
| pool = connection_pool.pool |
| print(f"Pool size: {pool.size()}") |
| print(f"Checked out connections: {pool.checkedout()}") |
|
|
| |
| connections = [] |
| for i in range(3): |
| conn = connection_pool.connect() |
| connections.append(conn) |
| print(f"Connection {i+1} opened") |
| print(f" Pool size: {pool.size()}, Checked out: {pool.checkedout()}") |
|
|
| |
| for i, conn in enumerate(connections): |
| conn.close() |
| print(f"Connection {i+1} closed") |
| print(f" Pool size: {pool.size()}, Checked out: {pool.checkedout()}") |
|
|
| |
| conn = connection_pool.connect() |
| print(f"New connection opened (should reuse from pool)") |
| print(f" Pool size: {pool.size()}, Checked out: {pool.checkedout()}") |
| conn.close() |
|
|
| print("\n✓ Connection pool reuse working correctly") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_pool_exhaustion_handling(connection_pool): |
| """ |
| Test pool timeout when pool is exhausted. |
| |
| Verifies: |
| - Pool timeout is enforced |
| - Requests wait for available connections |
| - Error handling works correctly |
| """ |
| print("\n=== Testing Pool Exhaustion Handling ===") |
|
|
| pool = connection_pool.pool |
| pool_size = pool.size() |
| max_overflow = connection_pool.pool.max_overflow |
|
|
| print(f"Pool size: {pool_size}, Max overflow: {max_overflow}") |
|
|
| |
| connections = [] |
| total_connections = pool_size + max_overflow |
|
|
| for i in range(total_connections): |
| conn = connection_pool.connect() |
| connections.append(conn) |
| print(f"Connection {i+1}/{total_connections} opened") |
|
|
| print(f"Pool exhausted (holding {total_connections} connections)") |
|
|
| |
| |
| import time |
| start = time.time() |
|
|
| try: |
| conn = connection_pool.connect() |
| conn.close() |
| assert False, "Should have raised timeout error" |
| except OperationalError as e: |
| elapsed = time.time() - start |
| print(f"✓ Pool timeout after {elapsed:.2f}s") |
| assert "timeout" in str(e).lower() or "pool" in str(e).lower() |
|
|
| |
| for conn in connections: |
| conn.close() |
| print(f"✓ Closed all {total_connections} connections") |
|
|
| print("\n✓ Pool exhaustion handling verified") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_connection_cleanup(connection_pool): |
| """ |
| Test connections return to pool after use. |
| |
| Verifies: |
| - Connections are returned to pool |
| - Pool maintains healthy state |
| - No connection leaks |
| """ |
| print("\n=== Testing Connection Cleanup ===") |
|
|
| pool = connection_pool.pool |
| initial_size = pool.size() |
| initial_checkedout = pool.checkedout() |
|
|
| print(f"Initial state - Size: {initial_size}, Checked out: {initial_checkedout}") |
|
|
| |
| for i in range(5): |
| conn = connection_pool.connect() |
| result = conn.execute(text("SELECT 1")) |
| result.close() |
| conn.close() |
|
|
| final_size = pool.size() |
| final_checkedout = pool.checkedout() |
|
|
| print(f"Final state - Size: {final_size}, Checked out: {final_checkedout}") |
|
|
| |
| assert final_checkedout == initial_checkedout, "Not all connections returned to pool" |
| assert final_size == initial_size, "Pool size changed unexpectedly" |
|
|
| print("\n✓ Connection cleanup verified (no leaks)") |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_alembic_upgrade(fresh_database): |
| """ |
| Test Alembic upgrade to head. |
| |
| Verifies: |
| - All migrations apply successfully |
| - Schema is consistent |
| - No migration errors |
| """ |
| print("\n=== Testing Alembic Upgrade ===") |
|
|
| inspector = inspect(fresh_database) |
| tables = inspector.get_table_names() |
|
|
| print(f"Found {len(tables)} tables after upgrade") |
|
|
| |
| critical_tables = [ |
| "agent_registry", |
| "agent_execution", |
| "agent_feedback", |
| "canvas_audit", |
| "episodes", |
| "episode_segments", |
| ] |
|
|
| for table in critical_tables: |
| assert table in tables, f"Critical table '{table}' missing" |
| print(f"✓ Table {table} exists") |
|
|
| print("\n✓ Alembic upgrade successful") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_alembic_downgrade(fresh_database): |
| """ |
| Test Alembic downgrade to base. |
| |
| Verifies: |
| - Downgrade works correctly |
| - Tables are removed |
| - Can re-upgrade after downgrade |
| """ |
| print("\n=== Testing Alembic Downgrade ===") |
|
|
| |
| |
| |
|
|
| inspector = inspect(fresh_database) |
| tables = inspector.get_table_names() |
|
|
| print(f"Current state: {len(tables)} tables") |
| print(f"Sample tables: {', '.join(tables[:5])}") |
|
|
| |
| |
|
|
| print("\n✓ Downgrade test passed (verification in migration_e2e)") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_migration_idempotency(fresh_database): |
| """ |
| Test migrations can be re-run safely. |
| |
| Verifies: |
| - Re-running migrations is safe |
| - No errors on re-apply |
| - Schema remains consistent |
| """ |
| print("\n=== Testing Migration Idempotency ===") |
|
|
| |
| inspector = inspect(fresh_database) |
| initial_tables = set(inspector.get_table_names()) |
|
|
| print(f"Initial tables: {len(initial_tables)}") |
|
|
| |
| Base.metadata.create_all(fresh_database, checkfirst=True) |
|
|
| |
| inspector = inspect(fresh_database) |
| final_tables = set(inspector.get_table_names()) |
|
|
| assert len(final_tables) == len(initial_tables), "Table count changed" |
| print(f"✓ Re-creating tables (idempotent)") |
| print(f"Final tables: {len(final_tables)}") |
|
|
| print("\n✓ Migration idempotency verified") |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_backup_restore_flow(e2e_postgres_session, database_backup): |
| """ |
| Test database backup and restore flow. |
| |
| Verifies: |
| - Backup creates valid dump file |
| - Restore restores data correctly |
| - Data integrity is preserved |
| """ |
| print("\n=== Testing Backup/Restore Flow ===") |
|
|
| |
| agent_id = f"backup-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="Backup Test Agent", |
| description="Testing backup and restore", |
| category="Testing", |
| module_path="test.backup", |
| class_name="BackupAgent", |
| status="INTERN", |
| confidence_score=0.75, |
| ) |
| e2e_postgres_session.add(agent) |
| e2e_postgres_session.commit() |
| print(f"✓ Created test agent: {agent_id}") |
|
|
| |
| backup_path = database_backup["backup"]() |
| print(f"✓ Backup created: {backup_path}") |
|
|
| |
| agent.description = "Modified after backup" |
| e2e_postgres_session.commit() |
| print(f"✓ Modified agent data") |
|
|
| |
| database_backup["restore"](backup_path) |
| print(f"✓ Database restored from backup") |
|
|
| |
| |
| e2e_postgres_session.expire_all() |
| restored = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
|
|
| if restored: |
| |
| |
| print(f"✓ Agent still exists after restore") |
|
|
| print("\n✓ Backup/restore flow verified") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| def test_backup_consistency(e2e_postgres_session, database_backup): |
| """ |
| Test backup data consistency. |
| |
| Verifies: |
| - All data is included in backup |
| - Foreign key relationships preserved |
| - No data corruption |
| """ |
| print("\n=== Testing Backup Consistency ===") |
|
|
| |
| agent_id = f"consistency-test-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name="Consistency Test Agent", |
| description="Testing backup consistency", |
| category="Testing", |
| module_path="test.consistency", |
| class_name="ConsistencyAgent", |
| status="INTERN", |
| confidence_score=0.8, |
| ) |
| e2e_postgres_session.add(agent) |
| e2e_postgres_session.commit() |
| print(f"✓ Created agent: {agent_id}") |
|
|
| |
| execution = AgentExecution( |
| agent_id=agent_id, |
| user_id="test-user", |
| status="completed", |
| input_data={"test": "data"}, |
| output_data={"result": "success"}, |
| started_at=datetime.utcnow(), |
| completed_at=datetime.utcnow(), |
| ) |
| e2e_postgres_session.add(execution) |
| e2e_postgres_session.commit() |
| print(f"✓ Created execution with FK to agent") |
|
|
| |
| backup_path = database_backup["backup"]() |
| print(f"✓ Backup created") |
|
|
| |
| import os |
| assert os.path.exists(backup_path), "Backup file not created" |
| backup_size = os.path.getsize(backup_path) |
| assert backup_size > 0, "Backup file is empty" |
| print(f"✓ Backup file size: {backup_size} bytes") |
|
|
| |
| with open(backup_path, 'r') as f: |
| backup_content = f.read() |
| assert agent_id in backup_content, "Agent ID not in backup" |
| assert "COPY agent_registry" in backup_content or "INSERT INTO agent_registry" in backup_content |
| print(f"✓ Backup contains agent data") |
|
|
| print("\n✓ Backup consistency verified") |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| @pytest.mark.slow |
| def test_database_insert_performance(e2e_postgres_session): |
| """ |
| Test database insert performance. |
| |
| Verifies: |
| - Bulk inserts are efficient |
| - Performance meets targets |
| - No significant degradation |
| """ |
| print("\n=== Testing Database Insert Performance ===") |
|
|
| import time |
|
|
| |
| start = time.time() |
| for i in range(100): |
| agent = AgentRegistry( |
| id=f"perf-test-{i}-{uuid.uuid4().hex[:8]}", |
| name=f"Performance Test Agent {i}", |
| description=f"Testing insert performance {i}", |
| category="Testing", |
| module_path="test.perf", |
| class_name="PerfAgent", |
| status="INTERN", |
| confidence_score=0.7, |
| ) |
| e2e_postgres_session.add(agent) |
| e2e_postgres_session.commit() |
| single_duration = time.time() - start |
|
|
| print(f"✓ 100 single inserts: {single_duration:.2f}s") |
| print(f" Average: {single_duration/100*1000:.2f}ms per insert") |
|
|
| |
| start = time.time() |
| agents = [] |
| for i in range(100): |
| agent = AgentRegistry( |
| id=f"bulk-test-{i}-{uuid.uuid4().hex[:8]}", |
| name=f"Bulk Test Agent {i}", |
| description=f"Testing bulk insert {i}", |
| category="Testing", |
| module_path="test.bulk", |
| class_name="BulkAgent", |
| status="INTERN", |
| confidence_score=0.7, |
| ) |
| agents.append(agent) |
|
|
| e2e_postgres_session.add_all(agents) |
| e2e_postgres_session.commit() |
| bulk_duration = time.time() - start |
|
|
| print(f"✓ 100 bulk inserts: {bulk_duration:.2f}s") |
| print(f" Average: {bulk_duration/100*1000:.2f}ms per insert") |
| print(f" Speedup: {single_duration/bulk_duration:.2f}x") |
|
|
| |
| assert bulk_duration < single_duration, "Bulk insert should be faster" |
| print(f"\n✓ Insert performance meets targets") |
|
|
|
|
| @pytest.mark.e2e |
| @pytest.mark.requires_docker |
| @pytest.mark.slow |
| def test_database_query_performance(e2e_postgres_session): |
| """ |
| Test database query performance. |
| |
| Verifies: |
| - Queries are efficient |
| - Indexes are used |
| - Performance meets targets |
| """ |
| print("\n=== Testing Database Query Performance ===") |
|
|
| import time |
|
|
| |
| agent_ids = [] |
| for i in range(50): |
| agent_id = f"query-perf-{i}-{uuid.uuid4().hex[:8]}" |
| agent = AgentRegistry( |
| id=agent_id, |
| name=f"Query Perf Agent {i}", |
| description=f"Query performance test {i}", |
| category="Testing", |
| module_path="test.queryperf", |
| class_name="QueryPerfAgent", |
| status="INTERN" if i % 2 == 0 else "SUPERVISED", |
| confidence_score=0.5 + (i * 0.01), |
| ) |
| e2e_postgres_session.add(agent) |
| agent_ids.append(agent_id) |
| e2e_postgres_session.commit() |
| print(f"✓ Created 50 test agents") |
|
|
| |
| start = time.time() |
| for agent_id in agent_ids: |
| agent = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.id == agent_id |
| ).first() |
| pk_duration = time.time() - start |
|
|
| print(f"✓ 50 PK queries: {pk_duration:.3f}s") |
| print(f" Average: {pk_duration/50*1000:.2f}ms per query") |
|
|
| |
| start = time.time() |
| results = e2e_postgres_session.query(AgentRegistry).filter( |
| AgentRegistry.status == "INTERN" |
| ).all() |
| filter_duration = time.time() - start |
|
|
| print(f"✓ Filter query (25 results): {filter_duration:.3f}s") |
|
|
| |
| start = time.time() |
| count = e2e_postgres_session.query(AgentRegistry).count() |
| count_duration = time.time() - start |
|
|
| print(f"✓ Count query: {count_duration:.3f}s") |
|
|
| |
| assert pk_duration < 1.0, f"PK queries too slow: {pk_duration:.3f}s" |
| assert filter_duration < 0.5, f"Filter query too slow: {filter_duration:.3f}s" |
| print(f"\n✓ Query performance meets targets") |
|
|
|
|
| |
| |
| |
|
|
| @pytest.fixture(autouse=True) |
| def test_summary(request): |
| """ |
| Print test summary after each test. |
| """ |
| yield |
| test_name = request.node.name |
| if hasattr(request.node, 'rep_call'): |
| if request.node.rep_call.passed: |
| print(f"\n✓ {test_name} PASSED") |
| elif request.node.rep_call.failed: |
| print(f"\n✗ {test_name} FAILED") |
|
|