@@ -686,6 +686,88 @@ async def execute(): |
686 | 686 |
|
687 | 687 | self.assertIsNone(self.loop.run_until_complete(execute())) |
688 | 688 |
|
| 689 | + async def check_stdout_output(self, coro, output): |
| 690 | + proc = await coro |
| 691 | + stdout, _ = await proc.communicate() |
| 692 | + self.assertEqual(stdout, output) |
| 693 | + self.assertEqual(proc.returncode, 0) |
| 694 | + task = asyncio.create_task(proc.wait()) |
| 695 | + await asyncio.sleep(0) |
| 696 | + self.assertEqual(task.result(), proc.returncode) |
| 697 | + |
| 698 | + def test_create_subprocess_env_shell(self) -> None: |
| 699 | + async def main() -> None: |
| 700 | + cmd = f'''{sys.executable} -c "import os, sys; sys.stdout.write(os.getenv('FOO'))"''' |
| 701 | + env = {"FOO": 'bar'} |
| 702 | + proc = await asyncio.create_subprocess_shell( |
| 703 | + cmd, env=env, stdout=subprocess.PIPE |
| 704 | + ) |
| 705 | + return proc |
| 706 | + |
| 707 | + self.loop.run_until_complete(self.check_stdout_output(main(), b'bar')) |
| 708 | + |
| 709 | + def test_create_subprocess_env_exec(self) -> None: |
| 710 | + async def main() -> None: |
| 711 | + cmd = [sys.executable, "-c", |
| 712 | + "import os, sys; sys.stdout.write(os.getenv('FOO'))"] |
| 713 | + env = {"FOO": 'baz'} |
| 714 | + proc = await asyncio.create_subprocess_exec( |
| 715 | + *cmd, env=env, stdout=subprocess.PIPE |
| 716 | + ) |
| 717 | + return proc |
| 718 | + |
| 719 | + self.loop.run_until_complete(self.check_stdout_output(main(), b'baz')) |
| 720 | + |
| 721 | + |
| 722 | + def test_subprocess_concurrent_wait(self) -> None: |
| 723 | + async def main() -> None: |
| 724 | + proc = await asyncio.create_subprocess_exec( |
| 725 | + *PROGRAM_CAT, |
| 726 | + stdin=subprocess.PIPE, |
| 727 | + stdout=subprocess.PIPE, |
| 728 | + ) |
| 729 | + stdout, _ = await proc.communicate(b'some data') |
| 730 | + self.assertEqual(stdout, b"some data") |
| 731 | + self.assertEqual(proc.returncode, 0) |
| 732 | + self.assertEqual(await asyncio.gather(*[proc.wait() for _ in range(10)]), |
| 733 | + [proc.returncode] * 10) |
| 734 | + |
| 735 | + self.loop.run_until_complete(main()) |
| 736 | + |
| 737 | + def test_subprocess_consistent_callbacks(self): |
| 738 | + events = [] |
| 739 | + class MyProtocol(asyncio.SubprocessProtocol): |
| 740 | + def __init__(self, exit_future: asyncio.Future) -> None: |
| 741 | + self.exit_future = exit_future |
| 742 | + |
| 743 | + def pipe_data_received(self, fd, data) -> None: |
| 744 | + events.append(('pipe_data_received', fd, data)) |
| 745 | + |
| 746 | + def pipe_connection_lost(self, fd, exc) -> None: |
| 747 | + events.append('pipe_connection_lost') |
| 748 | + |
| 749 | + def process_exited(self) -> None: |
| 750 | + events.append('process_exited') |
| 751 | + self.exit_future.set_result(True) |
| 752 | + |
| 753 | + async def main() -> None: |
| 754 | + loop = asyncio.get_running_loop() |
| 755 | + exit_future = asyncio.Future() |
| 756 | + code = 'import sys; sys.stdout.write("stdout"); sys.stderr.write("stderr")' |
| 757 | + transport, _ = await loop.subprocess_exec(lambda: MyProtocol(exit_future), |
| 758 | + sys.executable, '-c', code, stdin=None) |
| 759 | + await exit_future |
| 760 | + transport.close() |
| 761 | + self.assertEqual(events, [ |
| 762 | + ('pipe_data_received', 1, b'stdout'), |
| 763 | + ('pipe_data_received', 2, b'stderr'), |
| 764 | + 'pipe_connection_lost', |
| 765 | + 'pipe_connection_lost', |
| 766 | + 'process_exited', |
| 767 | + ]) |
| 768 | + |
| 769 | + self.loop.run_until_complete(main()) |
| 770 | + |
689 | 771 | def test_subprocess_communicate_stdout(self): |
690 | 772 | # See https://github.com/python/cpython/issues/100133 |
691 | 773 | async def get_command_stdout(cmd, *args): |
|