Skip to content

Commit af60262

Browse files
authored
fix for testing capacity (#24695)
fixes #24656 this change: restores the reverted code which switches to using fifo fixes the bug for large workspaces with fifo for mac
1 parent 00befaf commit af60262

File tree

20 files changed

+478
-373
lines changed

20 files changed

+478
-373
lines changed

noxfile.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def install_python_libs(session: nox.Session):
5353
)
5454

5555
session.install("packaging")
56+
session.install("debugpy")
5657

5758
# Download get-pip script
5859
session.run(

python_files/testing_tools/socket_manager.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,39 +20,24 @@ def __exit__(self, *_):
2020
self.close()
2121

2222
def connect(self):
23-
if sys.platform == "win32":
24-
self._writer = open(self.name, "w", encoding="utf-8") # noqa: SIM115, PTH123
25-
# reader created in read method
26-
else:
27-
self._socket = _SOCKET(socket.AF_UNIX, socket.SOCK_STREAM)
28-
self._socket.connect(self.name)
23+
self._writer = open(self.name, "w", encoding="utf-8") # noqa: SIM115, PTH123
24+
# reader created in read method
2925
return self
3026

3127
def close(self):
32-
if sys.platform == "win32":
33-
self._writer.close()
34-
else:
35-
# add exception catch
36-
self._socket.close()
28+
self._writer.close()
29+
if hasattr(self, "_reader"):
30+
self._reader.close()
3731

3832
def write(self, data: str):
39-
if sys.platform == "win32":
40-
try:
41-
# for windows, is should only use \n\n
42-
request = (
43-
f"""content-length: {len(data)}\ncontent-type: application/json\n\n{data}"""
44-
)
45-
self._writer.write(request)
46-
self._writer.flush()
47-
except Exception as e:
48-
print("error attempting to write to pipe", e)
49-
raise (e)
50-
else:
51-
# must include the carriage-return defined (as \r\n) for unix systems
52-
request = (
53-
f"""content-length: {len(data)}\r\ncontent-type: application/json\r\n\r\n{data}"""
54-
)
55-
self._socket.send(request.encode("utf-8"))
33+
try:
34+
# for windows, is should only use \n\n
35+
request = f"""content-length: {len(data)}\ncontent-type: application/json\n\n{data}"""
36+
self._writer.write(request)
37+
self._writer.flush()
38+
except Exception as e:
39+
print("error attempting to write to pipe", e)
40+
raise (e)
5641

5742
def read(self, bufsize=1024) -> str:
5843
"""Read data from the socket.
@@ -63,17 +48,10 @@ def read(self, bufsize=1024) -> str:
6348
Returns:
6449
data (str): Data received from the socket.
6550
"""
66-
if sys.platform == "win32":
67-
# returns a string automatically from read
68-
if not hasattr(self, "_reader"):
69-
self._reader = open(self.name, encoding="utf-8") # noqa: SIM115, PTH123
70-
return self._reader.read(bufsize)
71-
else:
72-
# receive bytes and convert to string
73-
while True:
74-
part: bytes = self._socket.recv(bufsize)
75-
data: str = part.decode("utf-8")
76-
return data
51+
# returns a string automatically from read
52+
if not hasattr(self, "_reader"):
53+
self._reader = open(self.name, encoding="utf-8") # noqa: SIM115, PTH123
54+
return self._reader.read(bufsize)
7755

7856

7957
class SocketManager:

python_files/tests/pytestadapter/helpers.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ def parse_rpc_message(data: str) -> Tuple[Dict[str, str], str]:
128128
print("json decode error")
129129

130130

131+
def _listen_on_fifo(pipe_name: str, result: List[str], completed: threading.Event):
132+
# Open the FIFO for reading
133+
fifo_path = pathlib.Path(pipe_name)
134+
with fifo_path.open() as fifo:
135+
print("Waiting for data...")
136+
while True:
137+
if completed.is_set():
138+
break # Exit loop if completed event is set
139+
data = fifo.read() # This will block until data is available
140+
if len(data) == 0:
141+
# If data is empty, assume EOF
142+
break
143+
print(f"Received: {data}")
144+
result.append(data)
145+
146+
131147
def _listen_on_pipe_new(listener, result: List[str], completed: threading.Event):
132148
"""Listen on the named pipe or Unix domain socket for JSON data from the server.
133149
@@ -307,14 +323,19 @@ def runner_with_cwd_env(
307323
# if additional environment variables are passed, add them to the environment
308324
if env_add:
309325
env.update(env_add)
310-
server = UnixPipeServer(pipe_name)
311-
server.start()
326+
# server = UnixPipeServer(pipe_name)
327+
# server.start()
328+
#################
329+
# Create the FIFO (named pipe) if it doesn't exist
330+
# if not pathlib.Path.exists(pipe_name):
331+
os.mkfifo(pipe_name)
332+
#################
312333

313334
completed = threading.Event()
314335

315336
result = [] # result is a string array to store the data during threading
316337
t1: threading.Thread = threading.Thread(
317-
target=_listen_on_pipe_new, args=(server, result, completed)
338+
target=_listen_on_fifo, args=(pipe_name, result, completed)
318339
)
319340
t1.start()
320341

@@ -364,14 +385,14 @@ def generate_random_pipe_name(prefix=""):
364385

365386
# For Windows, named pipes have a specific naming convention.
366387
if sys.platform == "win32":
367-
return f"\\\\.\\pipe\\{prefix}-{random_suffix}-sock"
388+
return f"\\\\.\\pipe\\{prefix}-{random_suffix}"
368389

369390
# For Unix-like systems, use either the XDG_RUNTIME_DIR or a temporary directory.
370391
xdg_runtime_dir = os.getenv("XDG_RUNTIME_DIR")
371392
if xdg_runtime_dir:
372-
return os.path.join(xdg_runtime_dir, f"{prefix}-{random_suffix}.sock") # noqa: PTH118
393+
return os.path.join(xdg_runtime_dir, f"{prefix}-{random_suffix}") # noqa: PTH118
373394
else:
374-
return os.path.join(tempfile.gettempdir(), f"{prefix}-{random_suffix}.sock") # noqa: PTH118
395+
return os.path.join(tempfile.gettempdir(), f"{prefix}-{random_suffix}") # noqa: PTH118
375396

376397

377398
class UnixPipeServer:

python_files/unittestadapter/pvsc_utils.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
from typing_extensions import NotRequired # noqa: E402
2020

21-
from testing_tools import socket_manager # noqa: E402
22-
2321
# Types
2422

2523

@@ -331,10 +329,10 @@ def send_post_request(
331329

332330
if __writer is None:
333331
try:
334-
__writer = socket_manager.PipeManager(test_run_pipe)
335-
__writer.connect()
332+
__writer = open(test_run_pipe, "wb") # noqa: SIM115, PTH123
336333
except Exception as error:
337334
error_msg = f"Error attempting to connect to extension named pipe {test_run_pipe}[vscode-unittest]: {error}"
335+
print(error_msg, file=sys.stderr)
338336
__writer = None
339337
raise VSCodeUnittestError(error_msg) from error
340338

@@ -343,10 +341,19 @@ def send_post_request(
343341
"params": payload,
344342
}
345343
data = json.dumps(rpc)
346-
347344
try:
348345
if __writer:
349-
__writer.write(data)
346+
request = (
347+
f"""content-length: {len(data)}\r\ncontent-type: application/json\r\n\r\n{data}"""
348+
)
349+
size = 4096
350+
encoded = request.encode("utf-8")
351+
bytes_written = 0
352+
while bytes_written < len(encoded):
353+
print("writing more bytes!")
354+
segment = encoded[bytes_written : bytes_written + size]
355+
bytes_written += __writer.write(segment)
356+
__writer.flush()
350357
else:
351358
print(
352359
f"Connection error[vscode-unittest], writer is None \n[vscode-unittest] data: \n{data} \n",

python_files/vscode_pytest/__init__.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@
2121

2222
import pytest
2323

24-
script_dir = pathlib.Path(__file__).parent.parent
25-
sys.path.append(os.fspath(script_dir))
26-
sys.path.append(os.fspath(script_dir / "lib" / "python"))
27-
from testing_tools import socket_manager # noqa: E402
28-
2924
if TYPE_CHECKING:
3025
from pluggy import Result
3126

@@ -171,7 +166,7 @@ def pytest_exception_interact(node, call, report):
171166
collected_test = TestRunResultDict()
172167
collected_test[node_id] = item_result
173168
cwd = pathlib.Path.cwd()
174-
execution_post(
169+
send_execution_message(
175170
os.fsdecode(cwd),
176171
"success",
177172
collected_test if collected_test else None,
@@ -295,7 +290,7 @@ def pytest_report_teststatus(report, config): # noqa: ARG001
295290
)
296291
collected_test = TestRunResultDict()
297292
collected_test[absolute_node_id] = item_result
298-
execution_post(
293+
send_execution_message(
299294
os.fsdecode(cwd),
300295
"success",
301296
collected_test if collected_test else None,
@@ -329,7 +324,7 @@ def pytest_runtest_protocol(item, nextitem): # noqa: ARG001
329324
)
330325
collected_test = TestRunResultDict()
331326
collected_test[absolute_node_id] = item_result
332-
execution_post(
327+
send_execution_message(
333328
os.fsdecode(cwd),
334329
"success",
335330
collected_test if collected_test else None,
@@ -405,15 +400,15 @@ def pytest_sessionfinish(session, exitstatus):
405400
"children": [],
406401
"id_": "",
407402
}
408-
post_response(os.fsdecode(cwd), error_node)
403+
send_discovery_message(os.fsdecode(cwd), error_node)
409404
try:
410405
session_node: TestNode | None = build_test_tree(session)
411406
if not session_node:
412407
raise VSCodePytestError(
413408
"Something went wrong following pytest finish, \
414409
no session node was created"
415410
)
416-
post_response(os.fsdecode(cwd), session_node)
411+
send_discovery_message(os.fsdecode(cwd), session_node)
417412
except Exception as e:
418413
ERRORS.append(
419414
f"Error Occurred, traceback: {(traceback.format_exc() if e.__traceback__ else '')}"
@@ -425,7 +420,7 @@ def pytest_sessionfinish(session, exitstatus):
425420
"children": [],
426421
"id_": "",
427422
}
428-
post_response(os.fsdecode(cwd), error_node)
423+
send_discovery_message(os.fsdecode(cwd), error_node)
429424
else:
430425
if exitstatus == 0 or exitstatus == 1:
431426
exitstatus_bool = "success"
@@ -435,7 +430,7 @@ def pytest_sessionfinish(session, exitstatus):
435430
)
436431
exitstatus_bool = "error"
437432

438-
execution_post(
433+
send_execution_message(
439434
os.fsdecode(cwd),
440435
exitstatus_bool,
441436
None,
@@ -485,7 +480,7 @@ def pytest_sessionfinish(session, exitstatus):
485480
result=file_coverage_map,
486481
error=None,
487482
)
488-
send_post_request(payload)
483+
send_message(payload)
489484

490485

491486
def build_test_tree(session: pytest.Session) -> TestNode:
@@ -853,8 +848,10 @@ def get_node_path(node: Any) -> pathlib.Path:
853848
atexit.register(lambda: __writer.close() if __writer else None)
854849

855850

856-
def execution_post(cwd: str, status: Literal["success", "error"], tests: TestRunResultDict | None):
857-
"""Sends a POST request with execution payload details.
851+
def send_execution_message(
852+
cwd: str, status: Literal["success", "error"], tests: TestRunResultDict | None
853+
):
854+
"""Sends message execution payload details.
858855
859856
Args:
860857
cwd (str): Current working directory.
@@ -866,10 +863,10 @@ def execution_post(cwd: str, status: Literal["success", "error"], tests: TestRun
866863
)
867864
if ERRORS:
868865
payload["error"] = ERRORS
869-
send_post_request(payload)
866+
send_message(payload)
870867

871868

872-
def post_response(cwd: str, session_node: TestNode) -> None:
869+
def send_discovery_message(cwd: str, session_node: TestNode) -> None:
873870
"""
874871
Sends a POST request with test session details in payload.
875872
@@ -885,7 +882,7 @@ def post_response(cwd: str, session_node: TestNode) -> None:
885882
}
886883
if ERRORS is not None:
887884
payload["error"] = ERRORS
888-
send_post_request(payload, cls_encoder=PathEncoder)
885+
send_message(payload, cls_encoder=PathEncoder)
889886

890887

891888
class PathEncoder(json.JSONEncoder):
@@ -897,7 +894,7 @@ def default(self, o):
897894
return super().default(o)
898895

899896

900-
def send_post_request(
897+
def send_message(
901898
payload: ExecutionPayloadDict | DiscoveryPayloadDict | CoveragePayloadDict,
902899
cls_encoder=None,
903900
):
@@ -922,8 +919,7 @@ def send_post_request(
922919

923920
if __writer is None:
924921
try:
925-
__writer = socket_manager.PipeManager(TEST_RUN_PIPE)
926-
__writer.connect()
922+
__writer = open(TEST_RUN_PIPE, "wb") # noqa: SIM115, PTH123
927923
except Exception as error:
928924
error_msg = f"Error attempting to connect to extension named pipe {TEST_RUN_PIPE}[vscode-pytest]: {error}"
929925
print(error_msg, file=sys.stderr)
@@ -941,10 +937,18 @@ def send_post_request(
941937
"params": payload,
942938
}
943939
data = json.dumps(rpc, cls=cls_encoder)
944-
945940
try:
946941
if __writer:
947-
__writer.write(data)
942+
request = (
943+
f"""content-length: {len(data)}\r\ncontent-type: application/json\r\n\r\n{data}"""
944+
)
945+
size = 4096
946+
encoded = request.encode("utf-8")
947+
bytes_written = 0
948+
while bytes_written < len(encoded):
949+
segment = encoded[bytes_written : bytes_written + size]
950+
bytes_written += __writer.write(segment)
951+
__writer.flush()
948952
else:
949953
print(
950954
f"Plugin error connection error[vscode-pytest], writer is None \n[vscode-pytest] data: \n{data} \n",

python_files/vscode_pytest/_common.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# def send_post_request():
2+
# return

0 commit comments

Comments
 (0)