|
10 | 10 | import socket |
11 | 11 | import subprocess |
12 | 12 | import sys |
| 13 | +import threading |
13 | 14 | import uuid |
14 | 15 | from typing import Any, Dict, List, Optional, Union |
15 | 16 |
|
16 | 17 | TEST_DATA_PATH = pathlib.Path(__file__).parent / ".data" |
17 | 18 | from typing_extensions import TypedDict |
18 | 19 |
|
19 | 20 |
|
20 | | -@contextlib.contextmanager |
21 | | -def test_output_file(root: pathlib.Path, ext: str = ".txt"): |
22 | | - """Creates a temporary python file with a random name.""" |
23 | | - basename = ( |
24 | | - "".join(random.choice("abcdefghijklmnopqrstuvwxyz") for _ in range(9)) + ext |
25 | | - ) |
26 | | - fullpath = root / basename |
27 | | - try: |
28 | | - fullpath.write_text("", encoding="utf-8") |
29 | | - yield fullpath |
30 | | - finally: |
31 | | - os.unlink(str(fullpath)) |
32 | | - |
33 | | - |
34 | 21 | def create_server( |
35 | 22 | host: str = "127.0.0.1", |
36 | 23 | port: int = 0, |
@@ -116,31 +103,51 @@ def runner(args: List[str]) -> Optional[Dict[str, Any]]: |
116 | 103 | "-p", |
117 | 104 | "vscode_pytest", |
118 | 105 | ] + args |
| 106 | + listener: socket.socket = create_server() |
| 107 | + _, port = listener.getsockname() |
| 108 | + listener.listen() |
| 109 | + |
| 110 | + env = os.environ.copy() |
| 111 | + env.update( |
| 112 | + { |
| 113 | + "TEST_UUID": str(uuid.uuid4()), |
| 114 | + "TEST_PORT": str(port), |
| 115 | + "PYTHONPATH": os.fspath(pathlib.Path(__file__).parent.parent.parent), |
| 116 | + } |
| 117 | + ) |
| 118 | + |
| 119 | + result: list = [] |
| 120 | + t1: threading.Thread = threading.Thread( |
| 121 | + target=_listen_on_socket, args=(listener, result) |
| 122 | + ) |
| 123 | + t1.start() |
| 124 | + |
| 125 | + t2 = threading.Thread( |
| 126 | + target=lambda proc_args, proc_env, proc_cwd: subprocess.run( |
| 127 | + proc_args, env=proc_env, cwd=proc_cwd |
| 128 | + ), |
| 129 | + args=(process_args, env, TEST_DATA_PATH), |
| 130 | + ) |
| 131 | + t2.start() |
| 132 | + |
| 133 | + t1.join() |
| 134 | + t2.join() |
| 135 | + |
| 136 | + return process_rpc_json(result[0]) if result else None |
| 137 | + |
119 | 138 |
|
120 | | - with test_output_file(TEST_DATA_PATH) as output_path: |
121 | | - env = os.environ.copy() |
122 | | - env.update( |
123 | | - { |
124 | | - "TEST_UUID": str(uuid.uuid4()), |
125 | | - "TEST_PORT": str(12345), # port is not used for tests |
126 | | - "PYTHONPATH": os.fspath(pathlib.Path(__file__).parent.parent.parent), |
127 | | - "TEST_OUTPUT_FILE": os.fspath(output_path), |
128 | | - } |
129 | | - ) |
130 | | - |
131 | | - result = subprocess.run( |
132 | | - process_args, |
133 | | - env=env, |
134 | | - cwd=os.fspath(TEST_DATA_PATH), |
135 | | - stdout=subprocess.PIPE, |
136 | | - stderr=subprocess.PIPE, |
137 | | - ) |
138 | | - if result.returncode != 0: |
139 | | - print("Subprocess Run failed with:") |
140 | | - print(result.stdout.decode(encoding="utf-8")) |
141 | | - print(result.stderr.decode(encoding="utf-8")) |
142 | | - |
143 | | - return process_rpc_json(output_path.read_text(encoding="utf-8")) |
| 139 | +def _listen_on_socket(listener: socket.socket, result: List[str]): |
| 140 | + """Listen on the socket for the JSON data from the server. |
| 141 | + Created as a seperate function for clarity in threading. |
| 142 | + """ |
| 143 | + sock, (other_host, other_port) = listener.accept() |
| 144 | + all_data: list = [] |
| 145 | + while True: |
| 146 | + data: bytes = sock.recv(1024 * 1024) |
| 147 | + if not data: |
| 148 | + break |
| 149 | + all_data.append(data.decode("utf-8")) |
| 150 | + result.append("".join(all_data)) |
144 | 151 |
|
145 | 152 |
|
146 | 153 | def find_test_line_number(test_name: str, test_file_path) -> str: |
|
0 commit comments