PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/test/test_asyncio/test_subprocess.py

https://bitbucket.org/jaraco/cpython-issue13540
Python | 215 lines | 156 code | 43 blank | 16 comment | 8 complexity | 076d700de89147a0033f13446986f60f MD5 | raw file
Possible License(s): BSD-3-Clause, 0BSD
  1. from asyncio import subprocess
  2. from asyncio import test_utils
  3. import asyncio
  4. import signal
  5. import sys
  6. import unittest
  7. from test import support
  8. if sys.platform != 'win32':
  9. from asyncio import unix_events
  10. # Program blocking
  11. PROGRAM_BLOCKED = [sys.executable, '-c', 'import time; time.sleep(3600)']
  12. # Program copying input to output
  13. PROGRAM_CAT = [
  14. sys.executable, '-c',
  15. ';'.join(('import sys',
  16. 'data = sys.stdin.buffer.read()',
  17. 'sys.stdout.buffer.write(data)'))]
  18. class SubprocessMixin:
  19. def test_stdin_stdout(self):
  20. args = PROGRAM_CAT
  21. @asyncio.coroutine
  22. def run(data):
  23. proc = yield from asyncio.create_subprocess_exec(
  24. *args,
  25. stdin=subprocess.PIPE,
  26. stdout=subprocess.PIPE,
  27. loop=self.loop)
  28. # feed data
  29. proc.stdin.write(data)
  30. yield from proc.stdin.drain()
  31. proc.stdin.close()
  32. # get output and exitcode
  33. data = yield from proc.stdout.read()
  34. exitcode = yield from proc.wait()
  35. return (exitcode, data)
  36. task = run(b'some data')
  37. task = asyncio.wait_for(task, 60.0, loop=self.loop)
  38. exitcode, stdout = self.loop.run_until_complete(task)
  39. self.assertEqual(exitcode, 0)
  40. self.assertEqual(stdout, b'some data')
  41. def test_communicate(self):
  42. args = PROGRAM_CAT
  43. @asyncio.coroutine
  44. def run(data):
  45. proc = yield from asyncio.create_subprocess_exec(
  46. *args,
  47. stdin=subprocess.PIPE,
  48. stdout=subprocess.PIPE,
  49. loop=self.loop)
  50. stdout, stderr = yield from proc.communicate(data)
  51. return proc.returncode, stdout
  52. task = run(b'some data')
  53. task = asyncio.wait_for(task, 60.0, loop=self.loop)
  54. exitcode, stdout = self.loop.run_until_complete(task)
  55. self.assertEqual(exitcode, 0)
  56. self.assertEqual(stdout, b'some data')
  57. def test_shell(self):
  58. create = asyncio.create_subprocess_shell('exit 7',
  59. loop=self.loop)
  60. proc = self.loop.run_until_complete(create)
  61. exitcode = self.loop.run_until_complete(proc.wait())
  62. self.assertEqual(exitcode, 7)
  63. def test_start_new_session(self):
  64. # start the new process in a new session
  65. create = asyncio.create_subprocess_shell('exit 8',
  66. start_new_session=True,
  67. loop=self.loop)
  68. proc = self.loop.run_until_complete(create)
  69. exitcode = self.loop.run_until_complete(proc.wait())
  70. self.assertEqual(exitcode, 8)
  71. def test_kill(self):
  72. args = PROGRAM_BLOCKED
  73. create = asyncio.create_subprocess_exec(*args, loop=self.loop)
  74. proc = self.loop.run_until_complete(create)
  75. proc.kill()
  76. returncode = self.loop.run_until_complete(proc.wait())
  77. if sys.platform == 'win32':
  78. self.assertIsInstance(returncode, int)
  79. # expect 1 but sometimes get 0
  80. else:
  81. self.assertEqual(-signal.SIGKILL, returncode)
  82. def test_terminate(self):
  83. args = PROGRAM_BLOCKED
  84. create = asyncio.create_subprocess_exec(*args, loop=self.loop)
  85. proc = self.loop.run_until_complete(create)
  86. proc.terminate()
  87. returncode = self.loop.run_until_complete(proc.wait())
  88. if sys.platform == 'win32':
  89. self.assertIsInstance(returncode, int)
  90. # expect 1 but sometimes get 0
  91. else:
  92. self.assertEqual(-signal.SIGTERM, returncode)
  93. @unittest.skipIf(sys.platform == 'win32', "Don't have SIGHUP")
  94. def test_send_signal(self):
  95. code = 'import time; print("sleeping", flush=True); time.sleep(3600)'
  96. args = [sys.executable, '-c', code]
  97. create = asyncio.create_subprocess_exec(*args, loop=self.loop, stdout=subprocess.PIPE)
  98. proc = self.loop.run_until_complete(create)
  99. @asyncio.coroutine
  100. def send_signal(proc):
  101. # basic synchronization to wait until the program is sleeping
  102. line = yield from proc.stdout.readline()
  103. self.assertEqual(line, b'sleeping\n')
  104. proc.send_signal(signal.SIGHUP)
  105. returncode = (yield from proc.wait())
  106. return returncode
  107. returncode = self.loop.run_until_complete(send_signal(proc))
  108. self.assertEqual(-signal.SIGHUP, returncode)
  109. def prepare_broken_pipe_test(self):
  110. # buffer large enough to feed the whole pipe buffer
  111. large_data = b'x' * support.PIPE_MAX_SIZE
  112. # the program ends before the stdin can be feeded
  113. create = asyncio.create_subprocess_exec(
  114. sys.executable, '-c', 'pass',
  115. stdin=subprocess.PIPE,
  116. loop=self.loop)
  117. proc = self.loop.run_until_complete(create)
  118. return (proc, large_data)
  119. def test_stdin_broken_pipe(self):
  120. proc, large_data = self.prepare_broken_pipe_test()
  121. @asyncio.coroutine
  122. def write_stdin(proc, data):
  123. proc.stdin.write(data)
  124. yield from proc.stdin.drain()
  125. coro = write_stdin(proc, large_data)
  126. # drain() must raise BrokenPipeError or ConnectionResetError
  127. self.assertRaises((BrokenPipeError, ConnectionResetError),
  128. self.loop.run_until_complete, coro)
  129. self.loop.run_until_complete(proc.wait())
  130. def test_communicate_ignore_broken_pipe(self):
  131. proc, large_data = self.prepare_broken_pipe_test()
  132. # communicate() must ignore BrokenPipeError when feeding stdin
  133. self.loop.run_until_complete(proc.communicate(large_data))
  134. self.loop.run_until_complete(proc.wait())
  135. if sys.platform != 'win32':
  136. # Unix
  137. class SubprocessWatcherMixin(SubprocessMixin):
  138. Watcher = None
  139. def setUp(self):
  140. policy = asyncio.get_event_loop_policy()
  141. self.loop = policy.new_event_loop()
  142. # ensure that the event loop is passed explicitly in asyncio
  143. policy.set_event_loop(None)
  144. watcher = self.Watcher()
  145. watcher.attach_loop(self.loop)
  146. policy.set_child_watcher(watcher)
  147. def tearDown(self):
  148. policy = asyncio.get_event_loop_policy()
  149. policy.set_child_watcher(None)
  150. self.loop.close()
  151. super().tearDown()
  152. class SubprocessSafeWatcherTests(SubprocessWatcherMixin,
  153. test_utils.TestCase):
  154. Watcher = unix_events.SafeChildWatcher
  155. class SubprocessFastWatcherTests(SubprocessWatcherMixin,
  156. test_utils.TestCase):
  157. Watcher = unix_events.FastChildWatcher
  158. else:
  159. # Windows
  160. class SubprocessProactorTests(SubprocessMixin, test_utils.TestCase):
  161. def setUp(self):
  162. policy = asyncio.get_event_loop_policy()
  163. self.loop = asyncio.ProactorEventLoop()
  164. # ensure that the event loop is passed explicitly in asyncio
  165. policy.set_event_loop(None)
  166. def tearDown(self):
  167. policy = asyncio.get_event_loop_policy()
  168. self.loop.close()
  169. policy.set_event_loop(None)
  170. super().tearDown()
  171. if __name__ == '__main__':
  172. unittest.main()