Context manager to create a test subprocess with socket synchronization. Args: script: Python code to execute in the subprocess. If wait_for_working is True, script should send b"working" after starting work. wait_for_working: If True, wait for both "ready" and "
(script, wait_for_working=False)
| 113 | |
| 114 | @contextlib.contextmanager |
| 115 | def test_subprocess(script, wait_for_working=False): |
| 116 | """Context manager to create a test subprocess with socket synchronization. |
| 117 | |
| 118 | Args: |
| 119 | script: Python code to execute in the subprocess. If wait_for_working |
| 120 | is True, script should send b"working" after starting work. |
| 121 | wait_for_working: If True, wait for both "ready" and "working" signals. |
| 122 | Default False for backward compatibility. |
| 123 | |
| 124 | Yields: |
| 125 | SubprocessInfo: Named tuple with process and socket objects |
| 126 | """ |
| 127 | # Find an unused port for socket communication |
| 128 | port = find_unused_port() |
| 129 | |
| 130 | # Inject socket connection code at the beginning of the script |
| 131 | socket_code = f""" |
| 132 | import socket |
| 133 | _test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 134 | _test_sock.connect(('localhost', {port})) |
| 135 | _test_sock.sendall(b"ready") |
| 136 | """ |
| 137 | |
| 138 | # Combine socket code with user script |
| 139 | full_script = socket_code + script |
| 140 | |
| 141 | # Create server socket to wait for process to be ready |
| 142 | server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 143 | server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
| 144 | server_socket.bind(("localhost", port)) |
| 145 | server_socket.settimeout(SHORT_TIMEOUT) |
| 146 | server_socket.listen(1) |
| 147 | |
| 148 | proc = subprocess.Popen( |
| 149 | [sys.executable, "-c", full_script], |
| 150 | stdout=subprocess.DEVNULL, |
| 151 | stderr=subprocess.DEVNULL, |
| 152 | ) |
| 153 | |
| 154 | client_socket = None |
| 155 | try: |
| 156 | # Wait for process to connect and send ready signal |
| 157 | client_socket, _ = server_socket.accept() |
| 158 | server_socket.close() |
| 159 | server_socket = None |
| 160 | |
| 161 | # Wait for ready signal, and optionally working signal |
| 162 | if wait_for_working: |
| 163 | _wait_for_signal(client_socket, [b"ready", b"working"]) |
| 164 | else: |
| 165 | _wait_for_signal(client_socket, b"ready") |
| 166 | |
| 167 | yield SubprocessInfo(proc, client_socket) |
| 168 | finally: |
| 169 | _cleanup_sockets(client_socket, server_socket) |
| 170 | _cleanup_process(proc) |
| 171 | |
| 172 |
no test coverage detected
searching dependent graphs…