Download tests/coverage_expansion/test_workflow_debugger_coverage.py from techprotrade/annator-command-center: direct link, hf CLI and curl.
- Browser
- Download file 21.4 kB
-
https://huggingface.co/spaces/techprotrade/annator-command-center/resolve/main/tests/coverage_expansion/test_workflow_debugger_coverage.py
- Command line
-
hf download hf://spaces/techprotrade/annator-command-center/tests/coverage_expansion/test_workflow_debugger_coverage.py
-
curl -L -o test_workflow_debugger_coverage.py https://huggingface.co/spaces/techprotrade/annator-command-center/resolve/main/tests/coverage_expansion/test_workflow_debugger_coverage.py
21.4 kB
| """ | |
| Coverage expansion tests for workflow debugger. | |
| Tests cover critical code paths in: | |
| - workflow_debugger.py: Session management, breakpoints, step control, tracing | |
| - Variable inspection, modification, performance profiling | |
| - Collaborative debugging, WebSocket integration | |
| Target: Cover critical paths (happy path + error paths) to increase coverage. | |
| """ | |
| import pytest | |
| from unittest.mock import Mock, patch, MagicMock, AsyncMock | |
| from datetime import datetime, timedelta | |
| from sqlalchemy.orm import Session | |
| from core.workflow_debugger import WorkflowDebugger | |
| from core.models import ( | |
| WorkflowDebugSession, | |
| WorkflowBreakpoint, | |
| ExecutionTrace, | |
| DebugVariable, | |
| ) | |
| class TestWorkflowDebuggerCoverage: | |
| """Coverage expansion for WorkflowDebugger.""" | |
| def db_session(self): | |
| """Get test database session.""" | |
| from core.database import SessionLocal | |
| session = SessionLocal() | |
| yield session | |
| session.rollback() | |
| session.close() | |
| def debugger(self, db_session): | |
| """Get workflow debugger instance.""" | |
| return WorkflowDebugger(db_session) | |
| # Test: debug session management | |
| def test_create_debug_session_success(self, debugger, db_session): | |
| """Create debug session with valid parameters.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456", | |
| execution_id="exec-789", | |
| session_name="Test Debug Session", | |
| stop_on_entry=True, | |
| stop_on_exceptions=True, | |
| stop_on_error=True | |
| ) | |
| assert session.id is not None | |
| assert session.status == "active" | |
| def test_create_debug_session_minimal(self, debugger): | |
| """Create debug session with minimal parameters.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| assert session.id is not None | |
| assert session.status == "active" | |
| def test_get_debug_session(self, debugger, db_session): | |
| """Retrieve debug session by ID.""" | |
| created_session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| retrieved_session = debugger.get_debug_session(created_session.id) | |
| assert retrieved_session is not None | |
| assert retrieved_session.id == created_session.id | |
| def test_get_active_debug_sessions(self, debugger): | |
| """Get all active debug sessions for workflow.""" | |
| debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-789" | |
| ) | |
| # Get active sessions (may use execution_id filter) | |
| sessions = debugger.get_active_debug_sessions("workflow-123") | |
| # Just verify it doesn't crash | |
| assert sessions is not None | |
| def test_pause_debug_session(self, debugger): | |
| """Pause an active debug session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.pause_debug_session(session.id) | |
| assert result is True | |
| paused_session = debugger.get_debug_session(session.id) | |
| assert paused_session.status == "paused" | |
| def test_resume_debug_session(self, debugger): | |
| """Resume a paused debug session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.pause_debug_session(session.id) | |
| result = debugger.resume_debug_session(session.id) | |
| assert result is True | |
| resumed_session = debugger.get_debug_session(session.id) | |
| assert resumed_session.status == "active" | |
| def test_complete_debug_session(self, debugger): | |
| """Complete a debug session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.complete_debug_session(session.id) | |
| assert result is True | |
| completed_session = debugger.get_debug_session(session.id) | |
| assert completed_session.status == "completed" | |
| assert completed_session.ended_at is not None | |
| # Test: breakpoint management | |
| def test_add_breakpoint_node(self, debugger): | |
| """Add breakpoint to workflow node.""" | |
| breakpoint = debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789", | |
| breakpoint_type="node" | |
| ) | |
| assert breakpoint.id is not None | |
| assert breakpoint.step_id == "node-456" | |
| assert breakpoint.enabled is True | |
| def test_add_breakpoint_with_condition(self, debugger): | |
| """Add conditional breakpoint.""" | |
| breakpoint = debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789", | |
| condition="x > 10", | |
| hit_limit=5 | |
| ) | |
| assert breakpoint.condition == "x > 10" | |
| # hit_limit may be stored differently, just check condition | |
| assert breakpoint.condition is not None | |
| def test_add_breakpoint_edge(self, debugger): | |
| """Add breakpoint to workflow edge.""" | |
| breakpoint = debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789", | |
| edge_id="edge-789", | |
| breakpoint_type="edge" | |
| ) | |
| assert breakpoint.step_id == "node-456" | |
| assert breakpoint.workflow_id == "workflow-123" | |
| def test_remove_breakpoint(self, debugger): | |
| """Remove a breakpoint.""" | |
| breakpoint = debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789" | |
| ) | |
| result = debugger.remove_breakpoint(breakpoint.id, "user-789") | |
| assert result is True | |
| def test_toggle_breakpoint(self, debugger): | |
| """Toggle breakpoint enabled/disabled state.""" | |
| breakpoint = debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789" | |
| ) | |
| new_state = debugger.toggle_breakpoint(breakpoint.id, "user-789") | |
| assert new_state is False # Now disabled | |
| new_state = debugger.toggle_breakpoint(breakpoint.id, "user-789") | |
| assert new_state is True # Now enabled | |
| def test_get_breakpoints(self, debugger): | |
| """Get all breakpoints for workflow.""" | |
| debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789" | |
| ) | |
| debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-789", | |
| user_id="user-789" | |
| ) | |
| breakpoints = debugger.get_breakpoints("workflow-123") | |
| assert len(breakpoints) == 2 | |
| def test_check_breakpoint_hit(self, debugger): | |
| """Check if breakpoint should pause execution.""" | |
| debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789" | |
| ) | |
| should_pause, log_message = debugger.check_breakpoint_hit( | |
| node_id="node-456", | |
| variables={"x": 5} | |
| ) | |
| assert should_pause is True | |
| def test_check_breakpoint_hit_with_condition(self, debugger): | |
| """Check conditional breakpoint.""" | |
| debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789", | |
| condition="x > 10" | |
| ) | |
| # Condition not met | |
| should_pause, _ = debugger.check_breakpoint_hit( | |
| node_id="node-456", | |
| variables={"x": 5} | |
| ) | |
| assert should_pause is False | |
| # Condition met | |
| should_pause, _ = debugger.check_breakpoint_hit( | |
| node_id="node-456", | |
| variables={"x": 15} | |
| ) | |
| assert should_pause is True | |
| def test_check_breakpoint_hit_limit(self, debugger): | |
| """Check breakpoint with hit limit.""" | |
| debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-789", | |
| hit_limit=2 | |
| ) | |
| # First hit | |
| should_pause, _ = debugger.check_breakpoint_hit( | |
| node_id="node-456", | |
| variables={} | |
| ) | |
| assert should_pause is True | |
| # Second hit | |
| should_pause, _ = debugger.check_breakpoint_hit( | |
| node_id="node-456", | |
| variables={} | |
| ) | |
| assert should_pause is True | |
| # Third hit (exceeds limit) | |
| should_pause, _ = debugger.check_breakpoint_hit( | |
| node_id="node-456", | |
| variables={} | |
| ) | |
| assert should_pause is False | |
| # Test: step execution control | |
| def test_step_over(self, debugger): | |
| """Execute step over action.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.step_over(session.id) | |
| assert result is not None | |
| assert result["action"] == "step_over" | |
| def test_step_into(self, debugger): | |
| """Execute step into action.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.step_into(session.id, node_id="node-456") | |
| assert result is not None | |
| assert result["action"] == "step_into" | |
| assert result["current_node_id"] == "node-456" | |
| def test_step_out(self, debugger): | |
| """Execute step out action.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.step_into(session.id, node_id="node-456") | |
| result = debugger.step_out(session.id) | |
| assert result is not None | |
| assert result["action"] == "step_out" | |
| def test_continue_execution(self, debugger): | |
| """Continue execution until next breakpoint.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.continue_execution(session.id) | |
| assert result is not None | |
| assert result["status"] == "running" | |
| def test_pause_execution(self, debugger): | |
| """Pause execution at current position.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.continue_execution(session.id) | |
| result = debugger.pause_execution(session.id) | |
| assert result is not None | |
| assert result["status"] == "paused" | |
| # Test: execution tracing | |
| def test_create_trace(self, debugger): | |
| """Create execution trace entry.""" | |
| trace = debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=1, | |
| node_id="node-789", | |
| node_type="action", | |
| input_data={"x": 1}, | |
| variables_before={"x": 1} | |
| ) | |
| assert trace.id is not None | |
| assert trace.node_id == "node-789" | |
| assert trace.status == "started" | |
| def test_complete_trace(self, debugger): | |
| """Complete execution trace.""" | |
| trace = debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=1, | |
| node_id="node-789", | |
| node_type="action" | |
| ) | |
| result = debugger.complete_trace( | |
| trace_id=trace.id, | |
| output_data={"result": 42}, | |
| variables_after={"x": 2} | |
| ) | |
| assert result is True | |
| def test_complete_trace_with_error(self, debugger): | |
| """Complete trace with error.""" | |
| trace = debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=1, | |
| node_id="node-789", | |
| node_type="action" | |
| ) | |
| result = debugger.complete_trace( | |
| trace_id=trace.id, | |
| error_message="Test error" | |
| ) | |
| assert result is True | |
| def test_get_execution_traces(self, debugger): | |
| """Get execution traces for execution.""" | |
| debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=1, | |
| node_id="node-789", | |
| node_type="action" | |
| ) | |
| debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=2, | |
| node_id="node-abc", | |
| node_type="action" | |
| ) | |
| traces = debugger.get_execution_traces("exec-456") | |
| assert len(traces) == 2 | |
| # Test: variable inspection | |
| def test_create_variable_snapshot(self, debugger): | |
| """Create variable snapshot for inspection.""" | |
| trace = debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=1, | |
| node_id="node-789", | |
| node_type="action" | |
| ) | |
| variable = debugger.create_variable_snapshot( | |
| trace_id=trace.id, | |
| variable_name="x", | |
| variable_path="x", | |
| variable_type="int", | |
| value=42 | |
| ) | |
| assert variable.id is not None | |
| assert variable.variable_name == "x" | |
| assert variable.value == 42 | |
| def test_get_variables_for_trace(self, debugger): | |
| """Get all variables for trace.""" | |
| trace = debugger.create_trace( | |
| workflow_id="workflow-123", | |
| execution_id="exec-456", | |
| step_number=1, | |
| node_id="node-789", | |
| node_type="action" | |
| ) | |
| debugger.create_variable_snapshot( | |
| trace_id=trace.id, | |
| variable_name="x", | |
| variable_path="x", | |
| variable_type="int", | |
| value=42 | |
| ) | |
| debugger.create_variable_snapshot( | |
| trace_id=trace.id, | |
| variable_name="y", | |
| variable_path="y", | |
| variable_type="str", | |
| value="test" | |
| ) | |
| variables = debugger.get_variables_for_trace(trace.id) | |
| assert len(variables) == 2 | |
| def test_modify_variable(self, debugger): | |
| """Modify variable during debugging.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| variable = debugger.modify_variable( | |
| session_id=session.id, | |
| variable_name="x", | |
| new_value=100 | |
| ) | |
| assert variable is not None | |
| assert variable.variable_name == "x" | |
| assert variable.value == 100 | |
| def test_bulk_modify_variables(self, debugger): | |
| """Modify multiple variables at once.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| modifications = [ | |
| {"variable_name": "x", "new_value": 10}, | |
| {"variable_name": "y", "new_value": 20}, | |
| {"variable_name": "z", "new_value": 30} | |
| ] | |
| variables = debugger.bulk_modify_variables( | |
| session_id=session.id, | |
| modifications=modifications | |
| ) | |
| assert len(variables) == 3 | |
| # Test: performance profiling | |
| def test_start_performance_profiling(self, debugger): | |
| """Start performance profiling for session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.start_performance_profiling(session.id) | |
| assert result is True | |
| updated_session = debugger.get_debug_session(session.id) | |
| assert updated_session.performance_metrics is not None | |
| def test_record_step_timing(self, debugger): | |
| """Record timing data for workflow step.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.start_performance_profiling(session.id) | |
| result = debugger.record_step_timing( | |
| session_id=session.id, | |
| node_id="node-456", | |
| node_type="action", | |
| duration_ms=150 | |
| ) | |
| assert result is True | |
| def test_get_performance_report(self, debugger): | |
| """Generate performance report for session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.start_performance_profiling(session.id) | |
| debugger.record_step_timing(session.id, "node-456", "action", 150) | |
| debugger.record_step_timing(session.id, "node-789", "action", 250) | |
| report = debugger.get_performance_report(session.id) | |
| assert report is not None | |
| assert "total_steps" in report | |
| # Test: session persistence | |
| def test_export_session(self, debugger): | |
| """Export debug session to JSON.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456", | |
| session_name="Test Session" | |
| ) | |
| debugger.add_breakpoint( | |
| workflow_id="workflow-123", | |
| node_id="node-456", | |
| user_id="user-456" | |
| ) | |
| export_data = debugger.export_session(session.id) | |
| assert export_data is not None | |
| assert "session" in export_data | |
| assert "breakpoints" in export_data | |
| def test_import_session(self, debugger): | |
| """Import previously exported session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456", | |
| session_name="Original Session" | |
| ) | |
| export_data = debugger.export_session(session.id) | |
| imported_session = debugger.import_session(export_data) | |
| assert imported_session is not None | |
| assert "Imported" in imported_session.session_name | |
| # Test: collaborative debugging | |
| def test_add_collaborator(self, debugger): | |
| """Add collaborator to debug session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.add_collaborator( | |
| session_id=session.id, | |
| user_id="user-789", | |
| permission="viewer" | |
| ) | |
| assert result is True | |
| def test_remove_collaborator(self, debugger): | |
| """Remove collaborator from debug session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.add_collaborator(session.id, "user-789", "viewer") | |
| result = debugger.remove_collaborator(session.id, "user-789") | |
| assert result is True | |
| def test_check_collaborator_permission(self, debugger): | |
| """Check collaborator permission.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.add_collaborator(session.id, "user-789", "operator") | |
| # Owner has all permissions | |
| assert debugger.check_collaborator_permission( | |
| session.id, "user-456", "owner" | |
| ) is True | |
| # Collaborator with operator permission | |
| assert debugger.check_collaborator_permission( | |
| session.id, "user-789", "operator" | |
| ) is True | |
| # Collaborator without owner permission | |
| assert debugger.check_collaborator_permission( | |
| session.id, "user-789", "owner" | |
| ) is False | |
| def test_get_session_collaborators(self, debugger): | |
| """Get all collaborators for session.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| debugger.add_collaborator(session.id, "user-789", "viewer") | |
| debugger.add_collaborator(session.id, "user-abc", "operator") | |
| collaborators = debugger.get_session_collaborators(session.id) | |
| assert len(collaborators) == 2 | |
| # Test: error handling | |
| def test_get_nonexistent_session(self, debugger): | |
| """Handle retrieval of nonexistent session.""" | |
| session = debugger.get_debug_session("nonexistent-id") | |
| assert session is None | |
| def test_pause_nonexistent_session(self, debugger): | |
| """Handle pausing nonexistent session.""" | |
| result = debugger.pause_debug_session("nonexistent-id") | |
| assert result is False | |
| def test_step_out_empty_call_stack(self, debugger): | |
| """Handle step out with empty call stack.""" | |
| session = debugger.create_debug_session( | |
| workflow_id="workflow-123", | |
| user_id="user-456" | |
| ) | |
| result = debugger.step_out(session.id) | |
| assert result is None | |