Skip to content

Commit dd923d0

Browse files
test
1 parent 79c1980 commit dd923d0

File tree

3 files changed

+126
-8
lines changed

3 files changed

+126
-8
lines changed

src/mcp/os/win32/utilities.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ async def create_windows_process(
184184
Returns:
185185
Process | FallbackProcess: Async-compatible subprocess with stdin and stdout streams
186186
"""
187+
# Log event loop information for debugging CI behavior
188+
try:
189+
import asyncio
190+
loop = asyncio.get_running_loop()
191+
logger.warning(f"[DIAGNOSTIC] Windows process creation - Event loop: {loop.__class__.__name__} from {loop.__class__.__module__}")
192+
except Exception:
193+
pass # Don't fail if we can't get loop info
194+
187195
job = _create_job_object()
188196
process = None
189197

@@ -199,19 +207,34 @@ async def create_windows_process(
199207
stderr=errlog,
200208
cwd=cwd,
201209
)
202-
except NotImplementedError:
210+
except NotImplementedError as e:
203211
# If Windows doesn't support async subprocess creation, use fallback
212+
logger.warning(f"[DIAGNOSTIC] anyio.open_process raised NotImplementedError: {e}")
213+
logger.warning("[DIAGNOSTIC] Using FallbackProcess (likely SelectorEventLoop on Windows)")
204214
process = await _create_windows_fallback_process(command, args, env, errlog, cwd)
205-
except Exception:
215+
except Exception as e:
206216
# Try again without creation flags
207-
process = await anyio.open_process(
208-
[command, *args],
209-
env=env,
210-
stderr=errlog,
211-
cwd=cwd,
212-
)
217+
logger.warning(f"[DIAGNOSTIC] anyio.open_process failed with {type(e).__name__}: {e}")
218+
logger.warning("[DIAGNOSTIC] Retrying without creation flags")
219+
try:
220+
process = await anyio.open_process(
221+
[command, *args],
222+
env=env,
223+
stderr=errlog,
224+
cwd=cwd,
225+
)
226+
except Exception as e2:
227+
logger.warning(f"[DIAGNOSTIC] Retry also failed with {type(e2).__name__}: {e2}")
228+
logger.warning("[DIAGNOSTIC] Falling back to FallbackProcess")
229+
process = await _create_windows_fallback_process(command, args, env, errlog, cwd)
213230

214231
_maybe_assign_process_to_job(process, job)
232+
233+
# Log which type of process was created
234+
process_type = type(process).__name__
235+
process_module = type(process).__module__
236+
logger.warning(f"[DIAGNOSTIC] Created process type: {process_type} from {process_module} (pid: {process.pid})")
237+
215238
return process
216239

217240

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
Diagnostic test to determine which process type is created in Windows CI.
3+
This test intentionally fails to ensure output appears in CI logs.
4+
"""
5+
6+
import asyncio
7+
import sys
8+
import tempfile
9+
import textwrap
10+
from pathlib import Path
11+
12+
import pytest
13+
14+
# Import the Windows-specific process creation function
15+
if sys.platform == "win32":
16+
from mcp.os.win32.utilities import create_windows_process, FallbackProcess
17+
from anyio.abc import Process
18+
19+
20+
@pytest.mark.anyio
21+
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific process type detection")
22+
async def test_windows_process_type_diagnostic():
23+
"""Diagnostic test to determine if FallbackProcess is used in Windows CI."""
24+
25+
# Get event loop info
26+
loop = asyncio.get_running_loop()
27+
loop_info = {
28+
"class": loop.__class__.__name__,
29+
"module": loop.__class__.__module__,
30+
}
31+
32+
# Create a simple test script
33+
test_script = textwrap.dedent("""
34+
import sys
35+
print("Test process started")
36+
sys.exit(0)
37+
""")
38+
39+
# Write script to temp file
40+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".py") as f:
41+
script_path = f.name
42+
f.write(test_script)
43+
44+
try:
45+
# Call create_windows_process directly
46+
process = await create_windows_process(
47+
command=sys.executable,
48+
args=[script_path],
49+
env=None,
50+
errlog=sys.stderr,
51+
cwd=None
52+
)
53+
54+
# Get process type info
55+
process_type = type(process).__name__
56+
process_module = type(process).__module__
57+
is_fallback = isinstance(process, FallbackProcess)
58+
is_anyio_process = process_module.startswith("anyio")
59+
60+
# Wait for process to complete
61+
try:
62+
await process.wait()
63+
except Exception:
64+
pass
65+
66+
# Clean up process
67+
if hasattr(process, "__aexit__"):
68+
await process.__aexit__(None, None, None)
69+
70+
finally:
71+
# Clean up script file
72+
Path(script_path).unlink(missing_ok=True)
73+
74+
# Create detailed diagnostic message
75+
diagnostic_msg = f"""
76+
WINDOWS PROCESS TYPE DIAGNOSTICS:
77+
================================
78+
Event Loop: {loop_info['class']} from {loop_info['module']}
79+
80+
Process Created:
81+
- Type: {process_type}
82+
- Module: {process_module}
83+
- Is FallbackProcess: {is_fallback}
84+
- Is anyio Process: {is_anyio_process}
85+
86+
Analysis:
87+
- ProactorEventLoop should support anyio.open_process
88+
- If FallbackProcess is used, anyio.open_process must have failed
89+
- This would indicate a problem with anyio on Windows CI
90+
"""
91+
92+
# Intentionally fail to ensure output appears in CI logs
93+
pytest.fail(f"DIAGNOSTIC TEST - Process type analysis\n{diagnostic_msg}")

tests/issues/test_1027_win_unreachable_cleanup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
from mcp.client.stdio import _create_platform_compatible_process, stdio_client
2222

2323

24+
25+
2426
@pytest.mark.anyio
2527
async def test_lifespan_cleanup_executed():
2628
"""

0 commit comments

Comments
 (0)