Skip to content

Commit 98012bf

Browse files
Simplify stdio cleanup tests to reduce flakiness
- Remove test_stdio_client_immediate_completion (too prone to race conditions) - Simplify test_stdio_client_cleanup_timeout to use consistent Python script - Focus on core issue: ensuring cleanup doesn't hang forever
1 parent caa5628 commit 98012bf

File tree

1 file changed

+23
-55
lines changed

1 file changed

+23
-55
lines changed

tests/client/test_stdio.py

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -97,26 +97,33 @@ async def test_stdio_client_nonexistent_command():
9797

9898

9999
@pytest.mark.anyio
100-
async def test_stdio_client_universal_cleanup():
100+
async def test_stdio_client_cleanup_timeout():
101101
"""
102102
Test that stdio_client completes cleanup within reasonable time
103-
even when connected to processes that exit slowly.
103+
even when connected to processes that don't exit cleanly.
104104
"""
105105

106-
# Use a simple sleep command that's available on all platforms
107-
# This simulates a process that takes time to terminate
108-
if sys.platform == "win32":
109-
# Windows: use ping with timeout to simulate a running process
110-
server_params = StdioServerParameters(
111-
command="ping",
112-
args=["127.0.0.1", "-n", "10"], # Ping 10 times, takes ~10 seconds
113-
)
114-
else:
115-
# Unix: use sleep command
116-
server_params = StdioServerParameters(
117-
command="sleep",
118-
args=["10"], # Sleep for 10 seconds
119-
)
106+
# Use a Python script that ignores SIGTERM and runs forever
107+
# This simulates a stubborn process that won't terminate cleanly
108+
script_content = textwrap.dedent(
109+
"""
110+
import signal
111+
import time
112+
113+
# Ignore SIGTERM on Unix
114+
if hasattr(signal, 'SIGTERM'):
115+
signal.signal(signal.SIGTERM, signal.SIG_IGN)
116+
117+
# Just keep running
118+
while True:
119+
time.sleep(0.1)
120+
"""
121+
)
122+
123+
server_params = StdioServerParameters(
124+
command=sys.executable,
125+
args=["-c", script_content],
126+
)
120127

121128
start_time = time.time()
122129

@@ -143,45 +150,6 @@ async def test_stdio_client_universal_cleanup():
143150
)
144151

145152

146-
@pytest.mark.anyio
147-
async def test_stdio_client_immediate_completion():
148-
"""
149-
Test that stdio_client doesn't introduce unnecessary delays
150-
when processes exit normally and quickly.
151-
"""
152-
153-
# Use a Python script that prints and exits after a brief moment
154-
# This avoids race conditions on fast systems where the process
155-
# exits before async tasks are fully initialized
156-
script_content = "import time; print('hello'); time.sleep(0.1)"
157-
158-
server_params = StdioServerParameters(
159-
command=sys.executable,
160-
args=["-c", script_content],
161-
)
162-
163-
start_time = time.time()
164-
165-
# Use move_on_after which is more reliable for cleanup scenarios
166-
with anyio.move_on_after(3.0) as cancel_scope:
167-
async with stdio_client(server_params) as (read_stream, write_stream):
168-
pass
169-
170-
end_time = time.time()
171-
elapsed = end_time - start_time
172-
173-
# Should complete very quickly when process exits normally
174-
assert elapsed < 2.0, (
175-
f"stdio_client took {elapsed:.1f} seconds for fast-exiting process, "
176-
f"expected < 2.0 seconds. Timeout mechanism may be introducing delays."
177-
)
178-
179-
# Check if we timed out
180-
if cancel_scope.cancelled_caught:
181-
pytest.fail(
182-
"stdio_client timed out after 3.0 seconds for fast-exiting process. "
183-
"This indicates a serious hang in the cleanup mechanism."
184-
)
185153

186154

187155
@pytest.mark.anyio

0 commit comments

Comments
 (0)