| """ |
| Database transaction rollback integration tests (Phase 3, Plan 1, Task 2.1). |
| |
| Tests cover: |
| - Transaction rollback for agent creation |
| - Transaction rollback for canvas creation |
| - Transaction rollback for episode creation |
| - Transaction rollback for browser session creation |
| |
| Coverage target: All database changes rolled back after tests, no test data pollution |
| """ |
|
|
| import pytest |
| from datetime import datetime |
| from sqlalchemy.orm import Session |
| from sqlalchemy import text |
|
|
| from core.models import ( |
| AgentRegistry, AgentExecution, AgentFeedback, AgentStatus, |
| CanvasAudit, |
| Episode, EpisodeSegment, |
| BrowserSession, BrowserAudit, |
| User |
| ) |
|
|
|
|
| class TestAgentTransactionRollback: |
| """Integration tests for agent creation transaction rollback.""" |
|
|
| def test_agent_creation_rollback_on_error(self, db_session: Session): |
| """Test agent creation rolls back on error.""" |
| initial_count = db_session.query(AgentRegistry).count() |
|
|
| |
| agent = AgentRegistry( |
| name="RollbackAgent", |
| category="test", |
| module_path="test.module", |
| class_name="RollbackAgent", |
| status=AgentStatus.INTERN.value, |
| confidence_score=0.6 |
| ) |
| db_session.add(agent) |
| db_session.flush() |
|
|
| |
| assert db_session.query(AgentRegistry).count() == initial_count + 1 |
|
|
| |
| db_session.rollback() |
|
|
| |
| assert db_session.query(AgentRegistry).count() == initial_count |
|
|
| |
| rolled_back = db_session.query(AgentRegistry).filter_by( |
| name="RollbackAgent" |
| ).first() |
| assert rolled_back is None |
|
|
| def test_agent_execution_rollback(self, db_session: Session): |
| """Test agent execution creation rolls back.""" |
| initial_count = db_session.query(AgentExecution).count() |
|
|
| execution = AgentExecution( |
| agent_id="test_agent", |
| workspace_id="default", |
| status="running", |
| input_data={"test": "data"} |
| ) |
| db_session.add(execution) |
| db_session.flush() |
|
|
| assert db_session.query(AgentExecution).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(AgentExecution).count() == initial_count |
|
|
| def test_agent_feedback_rollback(self, db_session: Session): |
| """Test agent feedback creation rolls back.""" |
| initial_count = db_session.query(AgentFeedback).count() |
|
|
| feedback = AgentFeedback( |
| agent_id="test_agent", |
| execution_id="test_execution", |
| rating=5, |
| feedback="Great work!" |
| ) |
| db_session.add(feedback) |
| db_session.flush() |
|
|
| assert db_session.query(AgentFeedback).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(AgentFeedback).count() == initial_count |
|
|
| def test_multiple_agent_operations_rollback(self, db_session: Session): |
| """Test multiple agent operations rollback atomically.""" |
| initial_agent_count = db_session.query(AgentRegistry).count() |
| initial_exec_count = db_session.query(AgentExecution).count() |
|
|
| |
| agent = AgentRegistry( |
| name="MultiRollbackAgent", |
| category="test", |
| module_path="test.module", |
| class_name="MultiRollbackAgent", |
| status=AgentStatus.STUDENT.value, |
| confidence_score=0.3 |
| ) |
| db_session.add(agent) |
| db_session.flush() |
|
|
| |
| execution = AgentExecution( |
| agent_id=agent.id, |
| workspace_id="default", |
| status="completed", |
| input_data={} |
| ) |
| db_session.add(execution) |
| db_session.flush() |
|
|
| |
| feedback = AgentFeedback( |
| agent_id=agent.id, |
| execution_id=execution.id, |
| rating=4 |
| ) |
| db_session.add(feedback) |
| db_session.flush() |
|
|
| |
| assert db_session.query(AgentRegistry).count() == initial_agent_count + 1 |
| assert db_session.query(AgentExecution).count() == initial_exec_count + 1 |
|
|
| |
| db_session.rollback() |
|
|
| |
| assert db_session.query(AgentRegistry).count() == initial_agent_count |
| assert db_session.query(AgentExecution).count() == initial_exec_count |
|
|
|
|
| class TestCanvasTransactionRollback: |
| """Integration tests for canvas audit transaction rollback.""" |
|
|
| def test_canvas_audit_rollback(self, db_session: Session): |
| """Test canvas audit creation rolls back.""" |
| initial_count = db_session.query(CanvasAudit).count() |
|
|
| audit = CanvasAudit( |
| id="rollback_audit_123", |
| canvas_id="audit_canvas", |
| agent_id="audit_agent", |
| user_id="audit_user", |
| action="present", |
| component_type="sheets" |
| ) |
| db_session.add(audit) |
| db_session.flush() |
|
|
| assert db_session.query(CanvasAudit).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(CanvasAudit).count() == initial_count |
|
|
|
|
| class TestEpisodeTransactionRollback: |
| """Integration tests for episode creation transaction rollback.""" |
|
|
| def test_episode_creation_rollback(self, db_session: Session): |
| """Test episode creation rolls back.""" |
| initial_count = db_session.query(Episode).count() |
|
|
| episode = Episode( |
| agent_id="episode_agent", |
| title="Test Episode", |
| summary="A test episode", |
| start_time=datetime.utcnow(), |
| end_time=datetime.utcnow(), |
| maturity_level="INTERN", |
| intervention_count=0 |
| ) |
| db_session.add(episode) |
| db_session.flush() |
|
|
| assert db_session.query(Episode).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(Episode).count() == initial_count |
|
|
| def test_episode_segment_rollback(self, db_session: Session): |
| """Test episode segment creation rolls back.""" |
| initial_count = db_session.query(EpisodeSegment).count() |
|
|
| segment = EpisodeSegment( |
| episode_id="episode_123", |
| segment_type="action", |
| content={"action": "test"}, |
| timestamp=datetime.utcnow() |
| ) |
| db_session.add(segment) |
| db_session.flush() |
|
|
| assert db_session.query(EpisodeSegment).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(EpisodeSegment).count() == initial_count |
|
|
| def test_episode_with_segments_rollback(self, db_session: Session): |
| """Test episode with multiple segments rolls back.""" |
| initial_episode_count = db_session.query(Episode).count() |
| initial_segment_count = db_session.query(EpisodeSegment).count() |
|
|
| episode = Episode( |
| agent_id="multi_segment_agent", |
| title="Multi-Segment Episode", |
| summary="Episode with segments", |
| start_time=datetime.utcnow(), |
| end_time=datetime.utcnow(), |
| maturity_level="SUPERVISED", |
| intervention_count=0 |
| ) |
| db_session.add(episode) |
| db_session.flush() |
|
|
| segment1 = EpisodeSegment( |
| episode_id=episode.id, |
| segment_type="action", |
| content={"step": 1}, |
| timestamp=datetime.utcnow() |
| ) |
| db_session.add(segment1) |
| db_session.flush() |
|
|
| segment2 = EpisodeSegment( |
| episode_id=episode.id, |
| segment_type="result", |
| content={"step": 2}, |
| timestamp=datetime.utcnow() |
| ) |
| db_session.add(segment2) |
| db_session.flush() |
|
|
| assert db_session.query(Episode).count() == initial_episode_count + 1 |
| assert db_session.query(EpisodeSegment).count() == initial_segment_count + 2 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(Episode).count() == initial_episode_count |
| assert db_session.query(EpisodeSegment).count() == initial_segment_count |
|
|
|
|
| class TestBrowserSessionTransactionRollback: |
| """Integration tests for browser session creation transaction rollback.""" |
|
|
| def test_browser_session_rollback(self, db_session: Session): |
| """Test browser session creation rolls back.""" |
| initial_count = db_session.query(BrowserSession).count() |
|
|
| session = BrowserSession( |
| id="browser_session_rollback", |
| user_id="test_user", |
| browser_type="chromium", |
| headless=True, |
| status="active" |
| ) |
| db_session.add(session) |
| db_session.flush() |
|
|
| assert db_session.query(BrowserSession).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(BrowserSession).count() == initial_count |
|
|
| def test_browser_audit_rollback(self, db_session: Session): |
| """Test browser audit creation rolls back.""" |
| initial_count = db_session.query(BrowserAudit).count() |
|
|
| audit = BrowserAudit( |
| id="browser_audit_rollback", |
| session_id="test_session", |
| agent_id="test_agent", |
| user_id="test_user", |
| action_type="navigate", |
| action_target="https://example.com", |
| action_params={}, |
| success=True |
| ) |
| db_session.add(audit) |
| db_session.flush() |
|
|
| assert db_session.query(BrowserAudit).count() == initial_count + 1 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(BrowserAudit).count() == initial_count |
|
|
| def test_browser_session_with_audits_rollback(self, db_session: Session): |
| """Test browser session with multiple audits rolls back.""" |
| initial_session_count = db_session.query(BrowserSession).count() |
| initial_audit_count = db_session.query(BrowserAudit).count() |
|
|
| session = BrowserSession( |
| id="multi_audit_session", |
| user_id="test_user", |
| browser_type="chromium", |
| headless=True, |
| status="active" |
| ) |
| db_session.add(session) |
| db_session.flush() |
|
|
| audit1 = BrowserAudit( |
| id="audit1_rollback", |
| session_id=session.id, |
| user_id="test_user", |
| action_type="navigate", |
| action_target="https://example.com", |
| action_params={}, |
| success=True |
| ) |
| db_session.add(audit1) |
| db_session.flush() |
|
|
| audit2 = BrowserAudit( |
| id="audit2_rollback", |
| session_id=session.id, |
| user_id="test_user", |
| action_type="screenshot", |
| action_params={"full_page": False}, |
| success=True |
| ) |
| db_session.add(audit2) |
| db_session.flush() |
|
|
| assert db_session.query(BrowserSession).count() == initial_session_count + 1 |
| assert db_session.query(BrowserAudit).count() == initial_audit_count + 2 |
|
|
| db_session.rollback() |
|
|
| assert db_session.query(BrowserSession).count() == initial_session_count |
| assert db_session.query(BrowserAudit).count() == initial_audit_count |
|
|
|
|
| class TestCrossModelTransactionRollback: |
| """Integration tests for transaction rollback across multiple models.""" |
|
|
| def test_complex_workflow_rollback(self, db_session: Session): |
| """Test complex workflow with agent, execution, canvas audit, and episode rolls back.""" |
| initial_counts = { |
| "agents": db_session.query(AgentRegistry).count(), |
| "executions": db_session.query(AgentExecution).count(), |
| "canvas_audits": db_session.query(CanvasAudit).count(), |
| "episodes": db_session.query(Episode).count() |
| } |
|
|
| |
| agent = AgentRegistry( |
| name="ComplexAgent", |
| category="test", |
| module_path="test.module", |
| class_name="ComplexAgent", |
| status=AgentStatus.AUTONOMOUS.value, |
| confidence_score=0.95 |
| ) |
| db_session.add(agent) |
| db_session.flush() |
|
|
| |
| execution = AgentExecution( |
| agent_id=agent.id, |
| workspace_id="default", |
| status="completed", |
| input_data={}, |
| output_data={"canvas_id": "complex_canvas"} |
| ) |
| db_session.add(execution) |
| db_session.flush() |
|
|
| |
| audit = CanvasAudit( |
| id="complex_canvas_audit", |
| canvas_id="complex_canvas", |
| agent_id=agent.id, |
| user_id="test_user", |
| action="present", |
| component_type="sheets" |
| ) |
| db_session.add(audit) |
| db_session.flush() |
|
|
| |
| episode = Episode( |
| agent_id=agent.id, |
| title="Complex Episode", |
| summary="Complex workflow episode", |
| start_time=datetime.utcnow(), |
| end_time=datetime.utcnow(), |
| maturity_level="AUTONOMOUS", |
| intervention_count=0 |
| ) |
| db_session.add(episode) |
| db_session.flush() |
|
|
| |
| assert db_session.query(AgentRegistry).count() == initial_counts["agents"] + 1 |
| assert db_session.query(AgentExecution).count() == initial_counts["executions"] + 1 |
| assert db_session.query(CanvasAudit).count() == initial_counts["canvas_audits"] + 1 |
| assert db_session.query(Episode).count() == initial_counts["episodes"] + 1 |
|
|
| |
| db_session.rollback() |
|
|
| |
| assert db_session.query(AgentRegistry).count() == initial_counts["agents"] |
| assert db_session.query(AgentExecution).count() == initial_counts["executions"] |
| assert db_session.query(CanvasAudit).count() == initial_counts["canvas_audits"] |
| assert db_session.query(Episode).count() == initial_counts["episodes"] |
|
|
| def test_transaction_isolation_between_tests(self, db_session: Session): |
| """Test that transactions are isolated between tests.""" |
| |
| agent = AgentRegistry( |
| name="IsolationAgent", |
| category="test", |
| module_path="test.module", |
| class_name="IsolationAgent", |
| status=AgentStatus.INTERN.value, |
| confidence_score=0.6 |
| ) |
| db_session.add(agent) |
| db_session.commit() |
|
|
| agent_id = agent.id |
|
|
| |
| assert db_session.query(AgentRegistry).filter_by(id=agent_id).first() is not None |
|
|
| |
| db_session.rollback() |
|
|
| |
| |
| assert True |
|
|