blob: 225a3babc844b81bb1ee36d72a728b94949dddcf [file] [log] [blame]
Benjamin Peterson3ccdd9b2019-11-13 19:08:50 -08001import os
Victor Stinner915bcb02014-02-01 22:49:59 +01002import signal
3import sys
4import unittest
Victor Stinner6fb1e742015-07-31 17:49:43 +02005import warnings
Victor Stinner5ef586f2014-11-25 17:20:33 +01006from unittest import mock
Victor Stinnerdc7765d2014-12-18 12:29:53 +01007
8import asyncio
Victor Stinner47cd10d2015-01-30 00:05:19 +01009from asyncio import base_subprocess
Victor Stinnerdc7765d2014-12-18 12:29:53 +010010from asyncio import subprocess
Yury Selivanov3e975182017-12-11 10:04:40 -050011from test.test_asyncio import utils as test_utils
12from test import support
Hai Shi06a40d72020-06-25 20:15:40 +080013from test.support import os_helper
Yury Selivanov3e975182017-12-11 10:04:40 -050014
Victor Stinnerd7ff5a52014-12-26 21:16:42 +010015if sys.platform != 'win32':
16 from asyncio import unix_events
Victor Stinner915bcb02014-02-01 22:49:59 +010017
Victor Stinner915bcb02014-02-01 22:49:59 +010018# Program blocking
19PROGRAM_BLOCKED = [sys.executable, '-c', 'import time; time.sleep(3600)']
20
Victor Stinner915bcb02014-02-01 22:49:59 +010021# Program copying input to output
22PROGRAM_CAT = [
23 sys.executable, '-c',
24 ';'.join(('import sys',
25 'data = sys.stdin.buffer.read()',
26 'sys.stdout.buffer.write(data)'))]
27
Brett Cannon8425de42018-06-01 20:34:09 -070028
29def tearDownModule():
30 asyncio.set_event_loop_policy(None)
31
32
Victor Stinner47cd10d2015-01-30 00:05:19 +010033class TestSubprocessTransport(base_subprocess.BaseSubprocessTransport):
34 def _start(self, *args, **kwargs):
35 self._proc = mock.Mock()
36 self._proc.stdin = None
37 self._proc.stdout = None
38 self._proc.stderr = None
Christian Heimesd361e992018-05-20 19:57:13 +020039 self._proc.pid = -1
Victor Stinner47cd10d2015-01-30 00:05:19 +010040
41
42class SubprocessTransportTests(test_utils.TestCase):
43 def setUp(self):
Yury Selivanov600a3492016-11-04 14:29:28 -040044 super().setUp()
Victor Stinner47cd10d2015-01-30 00:05:19 +010045 self.loop = self.new_test_loop()
46 self.set_event_loop(self.loop)
47
Victor Stinner47cd10d2015-01-30 00:05:19 +010048 def create_transport(self, waiter=None):
49 protocol = mock.Mock()
50 protocol.connection_made._is_coroutine = False
51 protocol.process_exited._is_coroutine = False
52 transport = TestSubprocessTransport(
53 self.loop, protocol, ['test'], False,
54 None, None, None, 0, waiter=waiter)
55 return (transport, protocol)
56
Victor Stinner47cd10d2015-01-30 00:05:19 +010057 def test_proc_exited(self):
Andrew Svetlov9aee9002019-09-11 16:07:37 +030058 waiter = self.loop.create_future()
Victor Stinner47cd10d2015-01-30 00:05:19 +010059 transport, protocol = self.create_transport(waiter)
60 transport._process_exited(6)
61 self.loop.run_until_complete(waiter)
62
63 self.assertEqual(transport.get_returncode(), 6)
64
65 self.assertTrue(protocol.connection_made.called)
66 self.assertTrue(protocol.process_exited.called)
67 self.assertTrue(protocol.connection_lost.called)
68 self.assertEqual(protocol.connection_lost.call_args[0], (None,))
69
Yury Selivanov5bb1afb2015-11-16 12:43:21 -050070 self.assertFalse(transport.is_closing())
Victor Stinner47cd10d2015-01-30 00:05:19 +010071 self.assertIsNone(transport._loop)
72 self.assertIsNone(transport._proc)
73 self.assertIsNone(transport._protocol)
74
75 # methods must raise ProcessLookupError if the process exited
76 self.assertRaises(ProcessLookupError,
77 transport.send_signal, signal.SIGTERM)
78 self.assertRaises(ProcessLookupError, transport.terminate)
79 self.assertRaises(ProcessLookupError, transport.kill)
80
Victor Stinner06986382015-01-30 00:11:42 +010081 transport.close()
82
Christian Heimesd361e992018-05-20 19:57:13 +020083 def test_subprocess_repr(self):
Andrew Svetlov9aee9002019-09-11 16:07:37 +030084 waiter = self.loop.create_future()
Christian Heimesd361e992018-05-20 19:57:13 +020085 transport, protocol = self.create_transport(waiter)
86 transport._process_exited(6)
87 self.loop.run_until_complete(waiter)
88
89 self.assertEqual(
90 repr(transport),
91 "<TestSubprocessTransport pid=-1 returncode=6>"
92 )
93 transport._returncode = None
94 self.assertEqual(
95 repr(transport),
96 "<TestSubprocessTransport pid=-1 running>"
97 )
98 transport._pid = None
99 transport._returncode = None
100 self.assertEqual(
101 repr(transport),
102 "<TestSubprocessTransport not started>"
103 )
104 transport.close()
105
Victor Stinner47cd10d2015-01-30 00:05:19 +0100106
Victor Stinner915bcb02014-02-01 22:49:59 +0100107class SubprocessMixin:
Yury Selivanov57797522014-02-18 22:56:15 -0500108
Victor Stinner915bcb02014-02-01 22:49:59 +0100109 def test_stdin_stdout(self):
110 args = PROGRAM_CAT
111
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200112 async def run(data):
113 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300114 *args,
115 stdin=subprocess.PIPE,
116 stdout=subprocess.PIPE,
117 )
Victor Stinner915bcb02014-02-01 22:49:59 +0100118
119 # feed data
120 proc.stdin.write(data)
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200121 await proc.stdin.drain()
Victor Stinner915bcb02014-02-01 22:49:59 +0100122 proc.stdin.close()
123
124 # get output and exitcode
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200125 data = await proc.stdout.read()
126 exitcode = await proc.wait()
Victor Stinner915bcb02014-02-01 22:49:59 +0100127 return (exitcode, data)
128
129 task = run(b'some data')
Yury Selivanov9012a0f2018-10-02 13:53:06 -0400130 task = asyncio.wait_for(task, 60.0)
Victor Stinner915bcb02014-02-01 22:49:59 +0100131 exitcode, stdout = self.loop.run_until_complete(task)
132 self.assertEqual(exitcode, 0)
133 self.assertEqual(stdout, b'some data')
134
135 def test_communicate(self):
136 args = PROGRAM_CAT
137
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200138 async def run(data):
139 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300140 *args,
141 stdin=subprocess.PIPE,
142 stdout=subprocess.PIPE,
143 )
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200144 stdout, stderr = await proc.communicate(data)
Victor Stinner915bcb02014-02-01 22:49:59 +0100145 return proc.returncode, stdout
146
147 task = run(b'some data')
Victor Stinnera4ed6ed2019-10-30 16:00:44 +0100148 task = asyncio.wait_for(task, support.LONG_TIMEOUT)
Victor Stinner915bcb02014-02-01 22:49:59 +0100149 exitcode, stdout = self.loop.run_until_complete(task)
150 self.assertEqual(exitcode, 0)
151 self.assertEqual(stdout, b'some data')
152
153 def test_shell(self):
Andrew Svetlova4888792019-09-12 15:40:40 +0300154 proc = self.loop.run_until_complete(
155 asyncio.create_subprocess_shell('exit 7')
156 )
Victor Stinner915bcb02014-02-01 22:49:59 +0100157 exitcode = self.loop.run_until_complete(proc.wait())
158 self.assertEqual(exitcode, 7)
159
160 def test_start_new_session(self):
161 # start the new process in a new session
Andrew Svetlova4888792019-09-12 15:40:40 +0300162 proc = self.loop.run_until_complete(
163 asyncio.create_subprocess_shell(
164 'exit 8',
165 start_new_session=True,
166 )
167 )
Victor Stinner915bcb02014-02-01 22:49:59 +0100168 exitcode = self.loop.run_until_complete(proc.wait())
169 self.assertEqual(exitcode, 8)
170
171 def test_kill(self):
172 args = PROGRAM_BLOCKED
Andrew Svetlova4888792019-09-12 15:40:40 +0300173 proc = self.loop.run_until_complete(
174 asyncio.create_subprocess_exec(*args)
175 )
Victor Stinner915bcb02014-02-01 22:49:59 +0100176 proc.kill()
177 returncode = self.loop.run_until_complete(proc.wait())
178 if sys.platform == 'win32':
179 self.assertIsInstance(returncode, int)
180 # expect 1 but sometimes get 0
181 else:
182 self.assertEqual(-signal.SIGKILL, returncode)
183
184 def test_terminate(self):
185 args = PROGRAM_BLOCKED
Andrew Svetlova4888792019-09-12 15:40:40 +0300186 proc = self.loop.run_until_complete(
187 asyncio.create_subprocess_exec(*args)
188 )
Victor Stinner915bcb02014-02-01 22:49:59 +0100189 proc.terminate()
190 returncode = self.loop.run_until_complete(proc.wait())
191 if sys.platform == 'win32':
192 self.assertIsInstance(returncode, int)
193 # expect 1 but sometimes get 0
194 else:
195 self.assertEqual(-signal.SIGTERM, returncode)
196
197 @unittest.skipIf(sys.platform == 'win32', "Don't have SIGHUP")
198 def test_send_signal(self):
Victor Stinner83008092017-07-25 19:19:09 +0200199 # bpo-31034: Make sure that we get the default signal handler (killing
200 # the process). The parent process may have decided to ignore SIGHUP,
201 # and signal handlers are inherited.
202 old_handler = signal.signal(signal.SIGHUP, signal.SIG_DFL)
203 try:
204 code = 'import time; print("sleeping", flush=True); time.sleep(3600)'
205 args = [sys.executable, '-c', code]
Andrew Svetlova4888792019-09-12 15:40:40 +0300206 proc = self.loop.run_until_complete(
207 asyncio.create_subprocess_exec(
208 *args,
209 stdout=subprocess.PIPE,
210 )
211 )
Victor Stinner98fa3322014-07-17 23:49:11 +0200212
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200213 async def send_signal(proc):
Victor Stinner83008092017-07-25 19:19:09 +0200214 # basic synchronization to wait until the program is sleeping
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200215 line = await proc.stdout.readline()
Victor Stinner83008092017-07-25 19:19:09 +0200216 self.assertEqual(line, b'sleeping\n')
Victor Stinner98fa3322014-07-17 23:49:11 +0200217
Victor Stinner83008092017-07-25 19:19:09 +0200218 proc.send_signal(signal.SIGHUP)
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200219 returncode = await proc.wait()
Victor Stinner83008092017-07-25 19:19:09 +0200220 return returncode
Victor Stinner98fa3322014-07-17 23:49:11 +0200221
Victor Stinner83008092017-07-25 19:19:09 +0200222 returncode = self.loop.run_until_complete(send_signal(proc))
223 self.assertEqual(-signal.SIGHUP, returncode)
224 finally:
225 signal.signal(signal.SIGHUP, old_handler)
Victor Stinner915bcb02014-02-01 22:49:59 +0100226
Victor Stinnercc996b52014-07-17 12:25:27 +0200227 def prepare_broken_pipe_test(self):
228 # buffer large enough to feed the whole pipe buffer
Victor Stinner915bcb02014-02-01 22:49:59 +0100229 large_data = b'x' * support.PIPE_MAX_SIZE
230
Victor Stinnercc996b52014-07-17 12:25:27 +0200231 # the program ends before the stdin can be feeded
Andrew Svetlova4888792019-09-12 15:40:40 +0300232 proc = self.loop.run_until_complete(
233 asyncio.create_subprocess_exec(
234 sys.executable, '-c', 'pass',
235 stdin=subprocess.PIPE,
236 )
237 )
238
Victor Stinnercc996b52014-07-17 12:25:27 +0200239 return (proc, large_data)
240
241 def test_stdin_broken_pipe(self):
242 proc, large_data = self.prepare_broken_pipe_test()
243
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200244 async def write_stdin(proc, data):
Yury Selivanov9012a0f2018-10-02 13:53:06 -0400245 await asyncio.sleep(0.5)
Victor Stinner0dee8ad2014-07-21 16:23:33 +0200246 proc.stdin.write(data)
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200247 await proc.stdin.drain()
Victor Stinner0dee8ad2014-07-21 16:23:33 +0200248
249 coro = write_stdin(proc, large_data)
Victor Stinnerddc8c8d2014-07-17 14:01:14 +0200250 # drain() must raise BrokenPipeError or ConnectionResetError
Victor Stinnerb2614752014-08-25 23:20:52 +0200251 with test_utils.disable_logger():
252 self.assertRaises((BrokenPipeError, ConnectionResetError),
253 self.loop.run_until_complete, coro)
Victor Stinnercc996b52014-07-17 12:25:27 +0200254 self.loop.run_until_complete(proc.wait())
255
256 def test_communicate_ignore_broken_pipe(self):
257 proc, large_data = self.prepare_broken_pipe_test()
258
259 # communicate() must ignore BrokenPipeError when feeding stdin
Andrew Svetlov549f7d42019-06-24 19:47:28 +0300260 self.loop.set_exception_handler(lambda loop, msg: None)
261 self.loop.run_until_complete(proc.communicate(large_data))
Victor Stinner915bcb02014-02-01 22:49:59 +0100262 self.loop.run_until_complete(proc.wait())
263
Victor Stinner5ef586f2014-11-25 17:20:33 +0100264 def test_pause_reading(self):
Victor Stinnercbbd04d2014-11-28 18:02:03 +0100265 limit = 10
266 size = (limit * 2 + 1)
267
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200268 async def test_pause_reading():
Victor Stinner5ef586f2014-11-25 17:20:33 +0100269 code = '\n'.join((
270 'import sys',
Victor Stinnercbbd04d2014-11-28 18:02:03 +0100271 'sys.stdout.write("x" * %s)' % size,
Victor Stinner5ef586f2014-11-25 17:20:33 +0100272 'sys.stdout.flush()',
273 ))
Victor Stinnerf716d8b2015-01-15 22:52:59 +0100274
275 connect_read_pipe = self.loop.connect_read_pipe
276
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200277 async def connect_read_pipe_mock(*args, **kw):
278 transport, protocol = await connect_read_pipe(*args, **kw)
Victor Stinnerf716d8b2015-01-15 22:52:59 +0100279 transport.pause_reading = mock.Mock()
280 transport.resume_reading = mock.Mock()
281 return (transport, protocol)
282
283 self.loop.connect_read_pipe = connect_read_pipe_mock
284
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200285 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300286 sys.executable, '-c', code,
287 stdin=asyncio.subprocess.PIPE,
288 stdout=asyncio.subprocess.PIPE,
289 limit=limit,
290 )
Victor Stinner5ef586f2014-11-25 17:20:33 +0100291 stdout_transport = proc._transport.get_pipe_transport(1)
Victor Stinner5ef586f2014-11-25 17:20:33 +0100292
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200293 stdout, stderr = await proc.communicate()
Victor Stinner5ef586f2014-11-25 17:20:33 +0100294
295 # The child process produced more than limit bytes of output,
296 # the stream reader transport should pause the protocol to not
297 # allocate too much memory.
Victor Stinnercbbd04d2014-11-28 18:02:03 +0100298 return (stdout, stdout_transport)
Victor Stinner5ef586f2014-11-25 17:20:33 +0100299
300 # Issue #22685: Ensure that the stream reader pauses the protocol
301 # when the child process produces too much data
Victor Stinnercbbd04d2014-11-28 18:02:03 +0100302 stdout, transport = self.loop.run_until_complete(test_pause_reading())
303
304 self.assertEqual(stdout, b'x' * size)
305 self.assertTrue(transport.pause_reading.called)
Victor Stinnerdd8224e2014-12-04 23:06:13 +0100306 self.assertTrue(transport.resume_reading.called)
Victor Stinner5ef586f2014-11-25 17:20:33 +0100307
Victor Stinner1e40f102014-12-11 23:30:17 +0100308 def test_stdin_not_inheritable(self):
Victor Stinnere6ecea52015-07-09 23:13:50 +0200309 # asyncio issue #209: stdin must not be inheritable, otherwise
Victor Stinner1e40f102014-12-11 23:30:17 +0100310 # the Process.communicate() hangs
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200311 async def len_message(message):
Victor Stinner1e40f102014-12-11 23:30:17 +0100312 code = 'import sys; data = sys.stdin.read(); print(len(data))'
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200313 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300314 sys.executable, '-c', code,
315 stdin=asyncio.subprocess.PIPE,
316 stdout=asyncio.subprocess.PIPE,
317 stderr=asyncio.subprocess.PIPE,
318 close_fds=False,
319 )
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200320 stdout, stderr = await proc.communicate(message)
321 exitcode = await proc.wait()
Victor Stinner1e40f102014-12-11 23:30:17 +0100322 return (stdout, exitcode)
323
324 output, exitcode = self.loop.run_until_complete(len_message(b'abc'))
325 self.assertEqual(output.rstrip(), b'3')
326 self.assertEqual(exitcode, 0)
327
Yury Selivanov7657f6b2016-05-13 15:35:28 -0400328 def test_empty_input(self):
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200329
330 async def empty_input():
Yury Selivanov7657f6b2016-05-13 15:35:28 -0400331 code = 'import sys; data = sys.stdin.read(); print(len(data))'
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200332 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300333 sys.executable, '-c', code,
334 stdin=asyncio.subprocess.PIPE,
335 stdout=asyncio.subprocess.PIPE,
336 stderr=asyncio.subprocess.PIPE,
337 close_fds=False,
338 )
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200339 stdout, stderr = await proc.communicate(b'')
340 exitcode = await proc.wait()
Yury Selivanov7657f6b2016-05-13 15:35:28 -0400341 return (stdout, exitcode)
342
343 output, exitcode = self.loop.run_until_complete(empty_input())
344 self.assertEqual(output.rstrip(), b'0')
345 self.assertEqual(exitcode, 0)
346
sbstpf0d4c642019-05-27 19:51:19 -0400347 def test_devnull_input(self):
348
349 async def empty_input():
350 code = 'import sys; data = sys.stdin.read(); print(len(data))'
351 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300352 sys.executable, '-c', code,
353 stdin=asyncio.subprocess.DEVNULL,
354 stdout=asyncio.subprocess.PIPE,
355 stderr=asyncio.subprocess.PIPE,
356 close_fds=False,
357 )
sbstpf0d4c642019-05-27 19:51:19 -0400358 stdout, stderr = await proc.communicate()
359 exitcode = await proc.wait()
360 return (stdout, exitcode)
361
362 output, exitcode = self.loop.run_until_complete(empty_input())
363 self.assertEqual(output.rstrip(), b'0')
364 self.assertEqual(exitcode, 0)
365
366 def test_devnull_output(self):
367
368 async def empty_output():
369 code = 'import sys; data = sys.stdin.read(); print(len(data))'
370 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300371 sys.executable, '-c', code,
372 stdin=asyncio.subprocess.PIPE,
373 stdout=asyncio.subprocess.DEVNULL,
374 stderr=asyncio.subprocess.PIPE,
375 close_fds=False,
376 )
sbstpf0d4c642019-05-27 19:51:19 -0400377 stdout, stderr = await proc.communicate(b"abc")
378 exitcode = await proc.wait()
379 return (stdout, exitcode)
380
381 output, exitcode = self.loop.run_until_complete(empty_output())
382 self.assertEqual(output, None)
383 self.assertEqual(exitcode, 0)
384
385 def test_devnull_error(self):
386
387 async def empty_error():
388 code = 'import sys; data = sys.stdin.read(); print(len(data))'
389 proc = await asyncio.create_subprocess_exec(
Andrew Svetlova4888792019-09-12 15:40:40 +0300390 sys.executable, '-c', code,
391 stdin=asyncio.subprocess.PIPE,
392 stdout=asyncio.subprocess.PIPE,
393 stderr=asyncio.subprocess.DEVNULL,
394 close_fds=False,
395 )
sbstpf0d4c642019-05-27 19:51:19 -0400396 stdout, stderr = await proc.communicate(b"abc")
397 exitcode = await proc.wait()
398 return (stderr, exitcode)
399
400 output, exitcode = self.loop.run_until_complete(empty_error())
401 self.assertEqual(output, None)
402 self.assertEqual(exitcode, 0)
403
Victor Stinnerc447ba02015-01-06 01:13:49 +0100404 def test_cancel_process_wait(self):
405 # Issue #23140: cancel Process.wait()
406
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200407 async def cancel_wait():
Andrew Svetlova4888792019-09-12 15:40:40 +0300408 proc = await asyncio.create_subprocess_exec(*PROGRAM_BLOCKED)
Victor Stinnerc447ba02015-01-06 01:13:49 +0100409
410 # Create an internal future waiting on the process exit
Victor Stinner212994e2015-01-06 01:22:45 +0100411 task = self.loop.create_task(proc.wait())
412 self.loop.call_soon(task.cancel)
413 try:
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200414 await task
Victor Stinner212994e2015-01-06 01:22:45 +0100415 except asyncio.CancelledError:
416 pass
Victor Stinnerc447ba02015-01-06 01:13:49 +0100417
418 # Cancel the future
419 task.cancel()
420
421 # Kill the process and wait until it is done
422 proc.kill()
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200423 await proc.wait()
Victor Stinnerc447ba02015-01-06 01:13:49 +0100424
425 self.loop.run_until_complete(cancel_wait())
426
Victor Stinnerf651a602015-01-14 02:10:33 +0100427 def test_cancel_make_subprocess_transport_exec(self):
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200428
429 async def cancel_make_transport():
Andrew Svetlova4888792019-09-12 15:40:40 +0300430 coro = asyncio.create_subprocess_exec(*PROGRAM_BLOCKED)
Victor Stinnerf651a602015-01-14 02:10:33 +0100431 task = self.loop.create_task(coro)
432
433 self.loop.call_soon(task.cancel)
434 try:
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200435 await task
Victor Stinnerf651a602015-01-14 02:10:33 +0100436 except asyncio.CancelledError:
437 pass
438
439 # ignore the log:
440 # "Exception during subprocess creation, kill the subprocess"
441 with test_utils.disable_logger():
442 self.loop.run_until_complete(cancel_make_transport())
443
444 def test_cancel_post_init(self):
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200445
446 async def cancel_make_transport():
Victor Stinnerf651a602015-01-14 02:10:33 +0100447 coro = self.loop.subprocess_exec(asyncio.SubprocessProtocol,
448 *PROGRAM_BLOCKED)
449 task = self.loop.create_task(coro)
450
451 self.loop.call_soon(task.cancel)
452 try:
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200453 await task
Victor Stinnerf651a602015-01-14 02:10:33 +0100454 except asyncio.CancelledError:
455 pass
456
457 # ignore the log:
458 # "Exception during subprocess creation, kill the subprocess"
459 with test_utils.disable_logger():
460 self.loop.run_until_complete(cancel_make_transport())
Victor Stinnerab8848b2015-01-15 14:24:55 +0100461 test_utils.run_briefly(self.loop)
Victor Stinnerf651a602015-01-14 02:10:33 +0100462
Victor Stinner8e368122015-02-10 14:49:32 +0100463 def test_close_kill_running(self):
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200464
465 async def kill_running():
Victor Stinner8e368122015-02-10 14:49:32 +0100466 create = self.loop.subprocess_exec(asyncio.SubprocessProtocol,
467 *PROGRAM_BLOCKED)
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200468 transport, protocol = await create
Victor Stinner4088ad92015-02-17 22:54:11 +0100469
470 kill_called = False
471 def kill():
472 nonlocal kill_called
473 kill_called = True
474 orig_kill()
475
Victor Stinner8e368122015-02-10 14:49:32 +0100476 proc = transport.get_extra_info('subprocess')
Victor Stinner4088ad92015-02-17 22:54:11 +0100477 orig_kill = proc.kill
478 proc.kill = kill
Victor Stinner8e368122015-02-10 14:49:32 +0100479 returncode = transport.get_returncode()
480 transport.close()
Andrew Svetlov0c6e3aa2020-02-27 00:15:12 +0200481 await asyncio.wait_for(transport._wait(), 5)
Victor Stinner4088ad92015-02-17 22:54:11 +0100482 return (returncode, kill_called)
Victor Stinner8e368122015-02-10 14:49:32 +0100483
484 # Ignore "Close running child process: kill ..." log
485 with test_utils.disable_logger():
Andrew Svetlov0c6e3aa2020-02-27 00:15:12 +0200486 try:
487 returncode, killed = self.loop.run_until_complete(
488 kill_running()
489 )
490 except asyncio.TimeoutError:
491 self.skipTest(
492 "Timeout failure on waiting for subprocess stopping"
493 )
Victor Stinner8e368122015-02-10 14:49:32 +0100494 self.assertIsNone(returncode)
495
496 # transport.close() must kill the process if it is still running
497 self.assertTrue(killed)
498 test_utils.run_briefly(self.loop)
499
500 def test_close_dont_kill_finished(self):
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200501
502 async def kill_running():
Victor Stinner8e368122015-02-10 14:49:32 +0100503 create = self.loop.subprocess_exec(asyncio.SubprocessProtocol,
504 *PROGRAM_BLOCKED)
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200505 transport, protocol = await create
Victor Stinner8e368122015-02-10 14:49:32 +0100506 proc = transport.get_extra_info('subprocess')
507
Martin Panter46f50722016-05-26 05:35:26 +0000508 # kill the process (but asyncio is not notified immediately)
Victor Stinner8e368122015-02-10 14:49:32 +0100509 proc.kill()
510 proc.wait()
511
512 proc.kill = mock.Mock()
513 proc_returncode = proc.poll()
514 transport_returncode = transport.get_returncode()
515 transport.close()
516 return (proc_returncode, transport_returncode, proc.kill.called)
517
518 # Ignore "Unknown child process pid ..." log of SafeChildWatcher,
519 # emitted because the test already consumes the exit status:
520 # proc.wait()
521 with test_utils.disable_logger():
522 result = self.loop.run_until_complete(kill_running())
523 test_utils.run_briefly(self.loop)
524
525 proc_returncode, transport_return_code, killed = result
526
527 self.assertIsNotNone(proc_returncode)
528 self.assertIsNone(transport_return_code)
529
530 # transport.close() must not kill the process if it finished, even if
531 # the transport was not notified yet
532 self.assertFalse(killed)
533
Yury Selivanov9eb6c672016-10-05 16:57:12 -0400534 # Unlike SafeChildWatcher, FastChildWatcher does not pop the
535 # callbacks if waitpid() is called elsewhere. Let's clear them
536 # manually to avoid a warning when the watcher is detached.
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200537 if (sys.platform != 'win32' and
538 isinstance(self, SubprocessFastWatcherTests)):
Yury Selivanov9eb6c672016-10-05 16:57:12 -0400539 asyncio.get_child_watcher()._callbacks.clear()
540
Andrew Svetlova4888792019-09-12 15:40:40 +0300541 async def _test_popen_error(self, stdin):
Yury Selivanov9632ea22015-08-09 18:21:25 -0400542 if sys.platform == 'win32':
543 target = 'asyncio.windows_utils.Popen'
544 else:
545 target = 'subprocess.Popen'
546 with mock.patch(target) as popen:
Victor Stinner6fb1e742015-07-31 17:49:43 +0200547 exc = ZeroDivisionError
548 popen.side_effect = exc
549
Yury Selivanov0c6a3442016-03-02 10:37:59 -0500550 with warnings.catch_warnings(record=True) as warns:
Victor Stinner6fb1e742015-07-31 17:49:43 +0200551 with self.assertRaises(exc):
Andrew Svetlova4888792019-09-12 15:40:40 +0300552 await asyncio.create_subprocess_exec(
553 sys.executable,
554 '-c',
555 'pass',
556 stdin=stdin
557 )
Yury Selivanov0c6a3442016-03-02 10:37:59 -0500558 self.assertEqual(warns, [])
Victor Stinner6fb1e742015-07-31 17:49:43 +0200559
Niklas Fiekas9932fd92019-05-20 14:02:17 +0200560 def test_popen_error(self):
561 # Issue #24763: check that the subprocess transport is closed
562 # when BaseSubprocessTransport fails
Andrew Svetlova4888792019-09-12 15:40:40 +0300563 self.loop.run_until_complete(self._test_popen_error(stdin=None))
Niklas Fiekas9932fd92019-05-20 14:02:17 +0200564
565 def test_popen_error_with_stdin_pipe(self):
566 # Issue #35721: check that newly created socket pair is closed when
567 # Popen fails
Andrew Svetlova4888792019-09-12 15:40:40 +0300568 self.loop.run_until_complete(
569 self._test_popen_error(stdin=subprocess.PIPE))
Niklas Fiekas9932fd92019-05-20 14:02:17 +0200570
Seth M. Larson481cb702017-03-02 22:21:18 -0600571 def test_read_stdout_after_process_exit(self):
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200572
573 async def execute():
Seth M. Larson481cb702017-03-02 22:21:18 -0600574 code = '\n'.join(['import sys',
575 'for _ in range(64):',
576 ' sys.stdout.write("x" * 4096)',
577 'sys.stdout.flush()',
578 'sys.exit(1)'])
579
Andrew Svetlova4888792019-09-12 15:40:40 +0300580 process = await asyncio.create_subprocess_exec(
Yury Selivanov2f156452017-03-02 23:25:31 -0500581 sys.executable, '-c', code,
582 stdout=asyncio.subprocess.PIPE,
Andrew Svetlova4888792019-09-12 15:40:40 +0300583 )
Yury Selivanov2f156452017-03-02 23:25:31 -0500584
Seth M. Larson481cb702017-03-02 22:21:18 -0600585 while True:
Andrew Svetlov5f841b52017-12-09 00:23:48 +0200586 data = await process.stdout.read(65536)
Seth M. Larson481cb702017-03-02 22:21:18 -0600587 if data:
Yury Selivanov9012a0f2018-10-02 13:53:06 -0400588 await asyncio.sleep(0.3)
Seth M. Larson481cb702017-03-02 22:21:18 -0600589 else:
590 break
591
592 self.loop.run_until_complete(execute())
Yury Selivanov2f156452017-03-02 23:25:31 -0500593
sbstpf0d4c642019-05-27 19:51:19 -0400594 def test_create_subprocess_exec_text_mode_fails(self):
595 async def execute():
596 with self.assertRaises(ValueError):
597 await subprocess.create_subprocess_exec(sys.executable,
598 text=True)
599
600 with self.assertRaises(ValueError):
601 await subprocess.create_subprocess_exec(sys.executable,
602 encoding="utf-8")
603
604 with self.assertRaises(ValueError):
605 await subprocess.create_subprocess_exec(sys.executable,
606 errors="strict")
607
608 self.loop.run_until_complete(execute())
609
610 def test_create_subprocess_shell_text_mode_fails(self):
611
612 async def execute():
613 with self.assertRaises(ValueError):
614 await subprocess.create_subprocess_shell(sys.executable,
615 text=True)
616
617 with self.assertRaises(ValueError):
618 await subprocess.create_subprocess_shell(sys.executable,
619 encoding="utf-8")
620
621 with self.assertRaises(ValueError):
622 await subprocess.create_subprocess_shell(sys.executable,
623 errors="strict")
624
625 self.loop.run_until_complete(execute())
626
依云744c08a2019-05-29 14:50:59 +0800627 def test_create_subprocess_exec_with_path(self):
628 async def execute():
629 p = await subprocess.create_subprocess_exec(
Hai Shi06a40d72020-06-25 20:15:40 +0800630 os_helper.FakePath(sys.executable), '-c', 'pass')
依云744c08a2019-05-29 14:50:59 +0800631 await p.wait()
632 p = await subprocess.create_subprocess_exec(
Hai Shi06a40d72020-06-25 20:15:40 +0800633 sys.executable, '-c', 'pass', os_helper.FakePath('.'))
依云744c08a2019-05-29 14:50:59 +0800634 await p.wait()
635
636 self.assertIsNone(self.loop.run_until_complete(execute()))
637
Andrew Svetlov0d671c02019-06-30 12:54:59 +0300638
Victor Stinner915bcb02014-02-01 22:49:59 +0100639if sys.platform != 'win32':
640 # Unix
641 class SubprocessWatcherMixin(SubprocessMixin):
Yury Selivanov57797522014-02-18 22:56:15 -0500642
Victor Stinner915bcb02014-02-01 22:49:59 +0100643 Watcher = None
644
645 def setUp(self):
Yury Selivanov600a3492016-11-04 14:29:28 -0400646 super().setUp()
Victor Stinner915bcb02014-02-01 22:49:59 +0100647 policy = asyncio.get_event_loop_policy()
648 self.loop = policy.new_event_loop()
Victor Stinner956de692014-12-26 21:07:52 +0100649 self.set_event_loop(self.loop)
Victor Stinner915bcb02014-02-01 22:49:59 +0100650
651 watcher = self.Watcher()
652 watcher.attach_loop(self.loop)
653 policy.set_child_watcher(watcher)
Andrew Svetlov0d671c02019-06-30 12:54:59 +0300654
655 def tearDown(self):
656 super().tearDown()
657 policy = asyncio.get_event_loop_policy()
658 watcher = policy.get_child_watcher()
659 policy.set_child_watcher(None)
660 watcher.attach_loop(None)
661 watcher.close()
662
663 class SubprocessThreadedWatcherTests(SubprocessWatcherMixin,
664 test_utils.TestCase):
665
666 Watcher = unix_events.ThreadedChildWatcher
667
668 class SubprocessMultiLoopWatcherTests(SubprocessWatcherMixin,
669 test_utils.TestCase):
670
671 Watcher = unix_events.MultiLoopChildWatcher
Victor Stinner915bcb02014-02-01 22:49:59 +0100672
Yury Selivanov57797522014-02-18 22:56:15 -0500673 class SubprocessSafeWatcherTests(SubprocessWatcherMixin,
Victor Stinnerc73701d2014-06-18 01:36:32 +0200674 test_utils.TestCase):
Yury Selivanov57797522014-02-18 22:56:15 -0500675
Victor Stinner915bcb02014-02-01 22:49:59 +0100676 Watcher = unix_events.SafeChildWatcher
677
Yury Selivanov57797522014-02-18 22:56:15 -0500678 class SubprocessFastWatcherTests(SubprocessWatcherMixin,
Victor Stinnerc73701d2014-06-18 01:36:32 +0200679 test_utils.TestCase):
Yury Selivanov57797522014-02-18 22:56:15 -0500680
Victor Stinner915bcb02014-02-01 22:49:59 +0100681 Watcher = unix_events.FastChildWatcher
Yury Selivanov57797522014-02-18 22:56:15 -0500682
Benjamin Peterson3ccdd9b2019-11-13 19:08:50 -0800683 def has_pidfd_support():
684 if not hasattr(os, 'pidfd_open'):
685 return False
686 try:
687 os.close(os.pidfd_open(os.getpid()))
688 except OSError:
689 return False
690 return True
691
692 @unittest.skipUnless(
693 has_pidfd_support(),
694 "operating system does not support pidfds",
695 )
696 class SubprocessPidfdWatcherTests(SubprocessWatcherMixin,
697 test_utils.TestCase):
698 Watcher = unix_events.PidfdChildWatcher
699
Victor Stinner915bcb02014-02-01 22:49:59 +0100700else:
701 # Windows
Victor Stinnerc73701d2014-06-18 01:36:32 +0200702 class SubprocessProactorTests(SubprocessMixin, test_utils.TestCase):
Yury Selivanov57797522014-02-18 22:56:15 -0500703
Victor Stinner915bcb02014-02-01 22:49:59 +0100704 def setUp(self):
Yury Selivanov600a3492016-11-04 14:29:28 -0400705 super().setUp()
Victor Stinner915bcb02014-02-01 22:49:59 +0100706 self.loop = asyncio.ProactorEventLoop()
Victor Stinner956de692014-12-26 21:07:52 +0100707 self.set_event_loop(self.loop)
Victor Stinner915bcb02014-02-01 22:49:59 +0100708
709
Andrew Svetlov0d671c02019-06-30 12:54:59 +0300710class GenericWatcherTests:
711
712 def test_create_subprocess_fails_with_inactive_watcher(self):
713
714 async def execute():
715 watcher = mock.create_authspec(asyncio.AbstractChildWatcher)
716 watcher.is_active.return_value = False
717 asyncio.set_child_watcher(watcher)
718
719 with self.assertRaises(RuntimeError):
720 await subprocess.create_subprocess_exec(
Hai Shi06a40d72020-06-25 20:15:40 +0800721 os_helper.FakePath(sys.executable), '-c', 'pass')
Andrew Svetlov0d671c02019-06-30 12:54:59 +0300722
723 watcher.add_child_handler.assert_not_called()
724
725 self.assertIsNone(self.loop.run_until_complete(execute()))
726
727
728
729
Victor Stinner915bcb02014-02-01 22:49:59 +0100730if __name__ == '__main__':
731 unittest.main()