test_performance.py•9.83 kB
"""Performance tests for DAP-based debugging.
Tests measure latency and throughput of debug operations.
"""
import time
import sys
from pathlib import Path
import pytest
from mcp_debug_tool.schemas import BreakpointRequest, StartSessionRequest
from mcp_debug_tool.sessions import SessionManager
@pytest.fixture
def workspace_root(tmp_path: Path) -> Path:
"""Create a temporary workspace for testing."""
return tmp_path
@pytest.fixture
def manager(workspace_root: Path) -> SessionManager:
"""Create a session manager."""
return SessionManager(workspace_root=workspace_root)
class TestPerformance:
"""Performance benchmarks for debug operations."""
def test_single_breakpoint_latency(
self, manager: SessionManager, workspace_root: Path
):
"""Measure latency for single breakpoint operation.
Success criteria: <2000ms for first breakpoint (includes DAP setup)
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
x = 10
y = 20
z = x + y
print(z)
"""
)
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
request = BreakpointRequest(file=str(script), line=4)
start_time = time.time()
response = manager.run_to_breakpoint(session_id, request)
elapsed = time.time() - start_time
assert response.hit, "Breakpoint should be hit"
assert elapsed < 2.0, f"Latency {elapsed:.3f}s exceeds 2s threshold"
manager.end_session(session_id)
def test_subsequent_breakpoint_latency(
self, manager: SessionManager, workspace_root: Path
):
"""Measure latency for subsequent breakpoint operations.
Success criteria: <500ms for subsequent breakpoints
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
x = 10
y = 20
z = x + y
w = z * 2
result = w + 1
print(result)
"""
)
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
# First breakpoint (setup)
request1 = BreakpointRequest(file=str(script), line=4)
response1 = manager.run_to_breakpoint(session_id, request1)
assert response1.hit
# Second breakpoint (measure)
request2 = BreakpointRequest(file=str(script), line=5)
start_time = time.time()
response2 = manager.continue_to_breakpoint(session_id, request2)
elapsed = time.time() - start_time
assert response2.hit, "Second breakpoint should be hit"
assert elapsed < 0.5, f"Latency {elapsed:.3f}s exceeds 500ms threshold"
manager.end_session(session_id)
def test_multiple_sessions_overhead(
self, manager: SessionManager, workspace_root: Path
):
"""Measure overhead of managing multiple concurrent sessions.
Success criteria: Can handle 5 concurrent sessions
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
x = 10
y = 20
z = x + y
print(z)
"""
)
session_ids = []
start_time = time.time()
# Create 5 sessions
for i in range(5):
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
session_ids.append(session_id)
creation_time = time.time() - start_time
# Run breakpoint in each session
for session_id in session_ids:
request = BreakpointRequest(file=str(script), line=4)
response = manager.run_to_breakpoint(session_id, request)
assert response.hit
# Cleanup
for session_id in session_ids:
manager.end_session(session_id)
assert creation_time < 1.0, f"Session creation {creation_time:.3f}s too slow"
def test_step_operation_latency(
self, manager: SessionManager, workspace_root: Path
):
"""Measure latency for step operations.
Success criteria: <500ms per step operation
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
def add(a, b):
return a + b
x = 10
y = 20
z = add(x, y)
print(z)
"""
)
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
# Run to first breakpoint
request = BreakpointRequest(file=str(script), line=5)
response = manager.run_to_breakpoint(session_id, request)
assert response.hit
# Measure step over
start_time = time.time()
step_response = manager.step_over(session_id)
elapsed = time.time() - start_time
assert step_response.hit, "Step should succeed"
assert elapsed < 0.5, f"Step latency {elapsed:.3f}s exceeds 500ms threshold"
manager.end_session(session_id)
def test_large_script_initialization(
self, manager: SessionManager, workspace_root: Path
):
"""Test performance with a larger script.
Success criteria: <3s to reach breakpoint in 100-line script
"""
# Generate a script with 100 lines
lines = ["# Header comment"]
for i in range(1, 95):
lines.append(f"x{i} = {i}")
lines.append("target = sum([x1, x2, x3, x4, x5])")
lines.append("result = target * 2")
lines.append("print(result)")
script = workspace_root / "large_script.py"
script.write_text("\n".join(lines))
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
request = BreakpointRequest(file=str(script), line=96)
start_time = time.time()
response = manager.run_to_breakpoint(session_id, request)
elapsed = time.time() - start_time
assert response.hit, "Breakpoint should be hit"
assert elapsed < 3.0, f"Initialization {elapsed:.3f}s too slow for large script"
manager.end_session(session_id)
def test_deep_variable_inspection_performance(
self, manager: SessionManager, workspace_root: Path
):
"""Test performance of variable inspection with complex data.
Success criteria: <1s to retrieve variables with nested structures
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
# Create nested data structure
data = {
'level1': {
'level2': {
'level3': {
'values': [1, 2, 3, 4, 5]
}
}
}
}
matrix = [[i*j for j in range(10)] for i in range(10)]
result = len(matrix)
print(result)
"""
)
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
request = BreakpointRequest(file=str(script), line=13)
start_time = time.time()
response = manager.run_to_breakpoint(session_id, request)
elapsed = time.time() - start_time
assert response.hit, "Breakpoint should be hit"
assert 'data' in response.locals, "Should have data variable"
assert 'matrix' in response.locals, "Should have matrix variable"
assert elapsed < 1.0, f"Variable inspection {elapsed:.3f}s too slow"
manager.end_session(session_id)
@pytest.mark.slow
def test_session_lifecycle_stress(
self, manager: SessionManager, workspace_root: Path
):
"""Stress test: Create and destroy many sessions rapidly.
Success criteria: Handle 20 session create/destroy cycles without error
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
x = 10
y = 20
z = x + y
print(z)
"""
)
start_time = time.time()
for i in range(20):
create_response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = create_response.sessionId
request = BreakpointRequest(file=str(script), line=4)
response = manager.run_to_breakpoint(session_id, request)
assert response.hit, f"Breakpoint should hit in iteration {i}"
manager.end_session(session_id)
elapsed = time.time() - start_time
# Should complete in reasonable time (40s = 2s per cycle)
assert elapsed < 40.0, f"Stress test {elapsed:.3f}s too slow"
def test_error_handling_performance(
self, manager: SessionManager, workspace_root: Path
):
"""Test that error handling doesn't significantly impact performance.
Success criteria: Error responses returned quickly (<1s)
"""
script = workspace_root / "perf_test.py"
script.write_text(
"""
x = 10
y = 20
z = x + y
print(z)
"""
)
response = manager.create_session(StartSessionRequest(entry=str(script, pythonPath=sys.executable)))
session_id = response.sessionId
# Try to set breakpoint on invalid line
request = BreakpointRequest(file=str(script), line=100)
start_time = time.time()
with pytest.raises((ValueError, AssertionError)):
manager.run_to_breakpoint(session_id, request)
elapsed = time.time() - start_time
assert elapsed < 1.0, f"Error handling {elapsed:.3f}s too slow"
manager.end_session(session_id)