Skip to main content
Glama
swesmith-repos

MCP Server for WinDbg Crash Analysis

test_remote_debugging.py8.34 kB
import pytest import subprocess import time import threading import os import sys from typing import Optional # Add the src directory to the Python path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from mcp_windbg.cdb_session import CDBSession, CDBError, DEFAULT_CDB_PATHS from mcp_windbg.server import get_or_create_session, unload_session class CDBServerProcess: """Helper class to manage a CDB server process for testing.""" def __init__(self, port: int = 5005): self.port = port self.process: Optional[subprocess.Popen] = None self.output_lines = [] self.reader_thread: Optional[threading.Thread] = None self.running = False def start(self, timeout: int = 10) -> bool: """Start the CDB server process.""" try: # Find cdb.exe cdb_path = self._find_cdb_executable() if not cdb_path: raise Exception("Could not find cdb.exe") # Use CDB to launch and debug a new instance of CDB self.process = subprocess.Popen( [cdb_path, "-o", cdb_path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1 ) # Start output reader thread self.running = True self.reader_thread = threading.Thread(target=self._read_output) self.reader_thread.daemon = True self.reader_thread.start() # Wait for CDB to initialize if not self._wait_for_prompt(timeout): return False # Start the remote server server_command = f".server tcp:port={self.port}\n" self.process.stdin.write(server_command) self.process.stdin.flush() # Wait for server to start and check for success message start_time = time.time() while time.time() - start_time < 5: recent_lines = self.output_lines[-10:] if any("Server started" in line for line in recent_lines): return True time.sleep(0.1) return True # Assume success if we got this far except Exception as e: print(f"Failed to start CDB server: {e}") self.cleanup() return False def cleanup(self): """Clean up the CDB server process.""" self.running = False if self.process and self.process.poll() is None: try: # Send quit command self.process.stdin.write("q\n") self.process.stdin.flush() self.process.wait(timeout=3) except Exception: pass if self.process.poll() is None: self.process.terminate() try: self.process.wait(timeout=3) except subprocess.TimeoutExpired: self.process.kill() if self.reader_thread and self.reader_thread.is_alive(): self.reader_thread.join(timeout=1) self.process = None def _find_cdb_executable(self) -> Optional[str]: """Find the cdb.exe executable.""" for path in DEFAULT_CDB_PATHS: if os.path.isfile(path): return path return None def _read_output(self): """Thread function to read CDB output.""" if not self.process or not self.process.stdout: return try: for line in self.process.stdout: line = line.rstrip() self.output_lines.append(line) print(f"CDB Server: {line}") # Debug output except Exception as e: print(f"CDB server output reader error: {e}") def _wait_for_prompt(self, timeout: int) -> bool: """Wait for CDB to be ready.""" start_time = time.time() while time.time() - start_time < timeout: # Look for the CDB prompt pattern (e.g., "0:000>") recent_lines = self.output_lines[-10:] # Check last 10 lines for line in recent_lines: if ":000>" in line or "Break instruction exception" in line: return True time.sleep(0.1) return False @pytest.mark.skipif(not os.name == 'nt', reason="Windows-only test") class TestRemoteDebugging: """Test cases for remote debugging functionality.""" def test_remote_debugging_workflow(self): """Test the complete remote debugging workflow.""" server = CDBServerProcess(port=5005) connection_string = "tcp:Port=5005,Server=127.0.0.1" try: # Start the CDB server process assert server.start(timeout=15), "Failed to start CDB server process" # Test opening remote connection session = get_or_create_session(connection_string=connection_string, timeout=10, verbose=True) assert session is not None, "Failed to create remote session" # Test sending a command try: output = session.send_command("r") # Show registers assert len(output) > 0, "No output from remote command" print(f"Remote command output: {output[:3]}") # Show first 3 lines except CDBError as e: # Sometimes the first command might timeout during connection establishment print(f"First command failed (this might be expected): {e}") # Test that session exists in active sessions from mcp_windbg.server import active_sessions session_id = f"remote:{connection_string}" assert session_id in active_sessions, "Session not found in active sessions" # Test closing the remote connection success = unload_session(connection_string=connection_string) assert success, "Failed to unload remote session" # Verify session was removed assert session_id not in active_sessions, "Session still exists after unloading" finally: # Clean up the server process server.cleanup() def test_remote_connection_validation(self): """Test validation of remote connection parameters.""" # Test that CDBSession validates parameters correctly with pytest.raises(ValueError, match="Either dump_path or remote_connection must be provided"): CDBSession() with pytest.raises(ValueError, match="dump_path and remote_connection are mutually exclusive"): CDBSession(dump_path="test.dmp", remote_connection="tcp:Port=5005,Server=127.0.0.1") def test_invalid_remote_connection(self): """Test handling of invalid remote connections.""" invalid_connection = "tcp:Port=99999,Server=192.168.255.255" # Invalid server with pytest.raises(CDBError): session = CDBSession(remote_connection=invalid_connection, timeout=2) # The session creation might succeed but commands should fail session.send_command("r") if __name__ == "__main__": # Run a simple test manually print("Running remote debugging test...") server = CDBServerProcess(port=5005) connection_string = "tcp:Port=5005,Server=127.0.0.1" try: print("Starting CDB server...") if server.start(timeout=15): print("CDB server started successfully") print("Creating remote session...") session = get_or_create_session(connection_string=connection_string, timeout=10, verbose=True) print("Sending test command...") try: output = session.send_command("r") print(f"Command successful, got {len(output)} lines of output") except Exception as e: print(f"Command failed: {e}") print("Closing remote session...") unload_session(connection_string=connection_string) print("Test completed successfully!") else: print("Failed to start CDB server") except Exception as e: print(f"Test failed: {e}") finally: print("Cleaning up...") server.cleanup()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/swesmith-repos/svnscha__mcp-windbg.20b852b5'

If you have feedback or need assistance with the MCP directory API, please join our Discord server