diff --git a/compute_endpoint/tests/conftest.py b/compute_endpoint/tests/conftest.py index 581df12e0..73df4d26d 100644 --- a/compute_endpoint/tests/conftest.py +++ b/compute_endpoint/tests/conftest.py @@ -1,9 +1,11 @@ from __future__ import annotations +import json import random import signal import string import subprocess +import sys import threading import time import typing as t @@ -239,10 +241,29 @@ def _warned(msg: str) -> bool: assert any(_warned(str(w)) for w in pyt_w.list) +def get_fds(pid): + if sys.platform == "darwin": + # Couldn't find timestamp and color equivalents for OSX + fd_args = ("/usr/sbin/lsof", "-p", str(pid)) + else: + fd_args = ( + "/bin/ls", + "-lv", + "--full-time", + "--color=always", + f"/proc/{pid}/fd/", + ) + fd_output = subprocess.run(fd_args, capture_output=True) + + # For darwin FDs we normally exclude ' txt ' see + # https://stackoverflow.com/questions/795236/in-mac-os-x-how-can-i-get-an-accurate-count-of-file-descriptor-usage # noqa E501 + # But if doing diffs, do not need to worry about unchanged FDs + return fd_output.stdout.decode().split("\n") + + @pytest.fixture(autouse=True) def resource_watcher(): p = psutil.Process() - ls_args = ("/bin/ls", "-lv", "--full-time", "--color=always", f"/proc/{p.pid}/fd/") vm_beg = psutil.virtual_memory() with p.oneshot(): mem_beg = p.memory_info() @@ -250,8 +271,7 @@ def resource_watcher(): thread_beg = p.num_threads() ctx_beg = p.num_ctx_switches() io_beg = getattr(p, "io_counters", lambda: "(not supported on this system)")() - ls_fds = subprocess.run(ls_args, capture_output=True) - os_fds_view_beg = ls_fds.stdout.decode() + os_fds_view_beg = get_fds(p.pid) yield @@ -262,13 +282,14 @@ def resource_watcher(): thread_end = p.num_threads() ctx_end = p.num_ctx_switches() io_end = getattr(p, "io_counters", lambda: "(not supported on this system)")() - ls_fds = subprocess.run(ls_args, capture_output=True) - os_fds_view_end = ls_fds.stdout.decode() + os_fds_view_end = get_fds(p.pid) if fds_end > fds_beg: thread_list = "\n ".join( f"{i:>3}: {repr(t)}" for i, t in enumerate(threading.enumerate(), start=1) ) + fd_af = [line for line in os_fds_view_end if line not in os_fds_view_beg] + fd_be = [line for line in os_fds_view_beg if line not in os_fds_view_end] msg = ( f"\nSystem Virtual Memory:\n {vm_beg=}\n {vm_end=}" f"\n\nProcess Memory:\n {mem_beg=}\n {mem_end=}" @@ -277,8 +298,8 @@ def resource_watcher(): f"\n\nI/O Counters:\n {io_beg=}\n {io_end=}" f"\n\nFile Descriptors:\n {fds_beg=}\n {fds_end=}" f"\n\nThreads (count: {p.num_threads()}):\n {thread_list}" - f"\n\nOpen files (Before): {os_fds_view_beg}" - f"\nOpen files (After): {os_fds_view_end}" + f"\n\nOpen files diff before and after: \n" + f"{json.dumps(fd_be, indent=2)}\n ->\n{json.dumps(fd_af, indent=2)}" ) msg = msg.replace("\n", "\n | ") assert fds_end <= fds_beg, f"Left over file descriptors!!\n{msg}"