@@ -97,26 +97,33 @@ async def test_stdio_client_nonexistent_command():
97
97
98
98
99
99
@pytest .mark .anyio
100
- async def test_stdio_client_universal_cleanup ():
100
+ async def test_stdio_client_cleanup_timeout ():
101
101
"""
102
102
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 .
104
104
"""
105
105
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
+ )
120
127
121
128
start_time = time .time ()
122
129
@@ -143,45 +150,6 @@ async def test_stdio_client_universal_cleanup():
143
150
)
144
151
145
152
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
- )
185
153
186
154
187
155
@pytest .mark .anyio
0 commit comments