|
8 | 8 | These tests verify the fix continues to work correctly across all platforms. |
9 | 9 | """ |
10 | 10 |
|
| 11 | +import platform |
| 12 | + |
11 | 13 | import asyncio |
12 | 14 | import sys |
13 | 15 | import tempfile |
|
21 | 23 | from mcp.client.stdio import _create_platform_compatible_process, stdio_client |
22 | 24 |
|
23 | 25 |
|
| 26 | +def _get_event_loop_info(): |
| 27 | + """Get information about the current event loop for debugging.""" |
| 28 | + try: |
| 29 | + loop = asyncio.get_running_loop() |
| 30 | + return { |
| 31 | + "class": loop.__class__.__name__, |
| 32 | + "module": loop.__class__.__module__, |
| 33 | + "is_proactor": "Proactor" in loop.__class__.__name__, |
| 34 | + "is_selector": "Selector" in loop.__class__.__name__, |
| 35 | + } |
| 36 | + except RuntimeError: |
| 37 | + return {"error": "No running event loop"} |
| 38 | + |
| 39 | + |
| 40 | +@pytest.mark.anyio |
| 41 | +@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific event loop detection") |
| 42 | +async def test_windows_event_loop_detection(): |
| 43 | + """Test to detect which event loop is being used on Windows CI.""" |
| 44 | + loop_info = _get_event_loop_info() |
| 45 | + |
| 46 | + # Print diagnostic info that will appear in CI logs |
| 47 | + print(f"\n{'='*60}") |
| 48 | + print("WINDOWS CI EVENT LOOP DIAGNOSTICS") |
| 49 | + print(f"{'='*60}") |
| 50 | + print(f"Python Version: {sys.version}") |
| 51 | + print(f"Platform: {platform.platform()}") |
| 52 | + print(f"Event Loop Class: {loop_info.get('class', 'Unknown')}") |
| 53 | + print(f"Event Loop Module: {loop_info.get('module', 'Unknown')}") |
| 54 | + print(f"Is ProactorEventLoop: {loop_info.get('is_proactor', False)}") |
| 55 | + print(f"Is SelectorEventLoop: {loop_info.get('is_selector', False)}") |
| 56 | + print(f"{'='*60}") |
| 57 | + print("ProactorEventLoop = Supports subprocesses (default since Python 3.8)") |
| 58 | + print("SelectorEventLoop = Does NOT support subprocesses (uses FallbackProcess)") |
| 59 | + print(f"{'='*60}\n") |
| 60 | + |
| 61 | + # Intentionally fail to ensure output appears in CI logs |
| 62 | + pytest.fail("DIAGNOSTIC TEST - Intentionally failing to show event loop info in CI") |
| 63 | + |
| 64 | + |
24 | 65 | @pytest.mark.anyio |
25 | 66 | async def test_lifespan_cleanup_executed(): |
26 | 67 | """ |
@@ -195,9 +236,19 @@ def echo(text: str) -> str: |
195 | 236 | try: |
196 | 237 | # This test manually manages the process to verify stdin-based shutdown |
197 | 238 | # Start the server process |
| 239 | + if sys.platform == "win32": |
| 240 | + # Force output to stderr which is captured even with xdist |
| 241 | + import sys as sys_module |
| 242 | + print(f"\n[WINDOWS DIAGNOSTICS] Event loop: {_get_event_loop_info()}", file=sys_module.stderr) |
| 243 | + print(f"[WINDOWS DIAGNOSTICS] About to create process...", file=sys_module.stderr) |
| 244 | + |
198 | 245 | process = await _create_platform_compatible_process( |
199 | 246 | command=sys.executable, args=[server_script], env=None, errlog=sys.stderr, cwd=None |
200 | 247 | ) |
| 248 | + |
| 249 | + if sys.platform == "win32": |
| 250 | + print(f"[WINDOWS DIAGNOSTICS] Created process type: {type(process).__name__}", file=sys_module.stderr) |
| 251 | + print(f"[WINDOWS DIAGNOSTICS] Has returncode: {hasattr(process, 'returncode')}", file=sys_module.stderr) |
201 | 252 |
|
202 | 253 | # Wait for server to start |
203 | 254 | await asyncio.sleep(1.0) # Give more time on Windows |
|
0 commit comments