Files
wehub-resource-sync 4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

158 lines
5.1 KiB
Python

"""Tests for the per-PID resource probe (issue #1489)."""
from __future__ import annotations
import os
import pathlib
import subprocess
import sys
import time
from collections.abc import Iterator
from datetime import UTC, datetime
from types import SimpleNamespace
from unittest.mock import patch
import psutil
import pytest
from tools.system.fleet_monitoring.probe import (
ProcessSnapshot,
probe,
process_has_open_codex_rollout,
)
_REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
_PROBE_MODULE = _REPO_ROOT / "tools" / "system" / "fleet_monitoring" / "probe.py"
_SOURCE_ROOTS = (
"cli",
"config",
"core",
"deployment",
"integrations",
"platform",
"services",
"tools",
)
@pytest.fixture
def busy_process() -> Iterator[int]:
"""Spawn a subprocess burning CPU in a tight loop; yields its PID.
The warmup sleep ensures the process has accumulated enough CPU time for
psutil.cpu_percent(interval>0) to measure a non-zero delta.
"""
proc = subprocess.Popen(
[sys.executable, "-c", "while True: pass"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
time.sleep(0.1)
yield proc.pid
proc.terminate()
try:
proc.wait(timeout=5)
except subprocess.TimeoutExpired:
proc.kill()
proc.wait()
def test_probe_returns_snapshot_for_self() -> None:
"""Probing the current Python process must return a populated snapshot."""
snap = probe(os.getpid(), cpu_interval=0.0)
assert snap is not None
assert isinstance(snap, ProcessSnapshot)
assert snap.pid == os.getpid()
assert snap.rss_mb > 0.0, "interpreter + pytest should occupy non-zero RSS"
assert snap.status, "status should be a non-empty string (e.g. 'running')"
assert isinstance(snap.started_at, datetime)
assert snap.started_at.tzinfo == UTC, "started_at must be tz-aware UTC"
if sys.platform != "win32":
assert snap.num_fds is not None and snap.num_fds > 0, (
"POSIX systems should always report a positive FD count"
)
def test_probe_returns_none_for_missing_pid() -> None:
"""Probing a PID that does not exist returns None, never raises."""
# 2**31 - 1 is far above any realistic allocated PID on Linux/macOS
# (kernel.pid_max is typically 32768 or 4194304).
assert probe(2**31 - 1, cpu_interval=0.0) is None
def test_probe_returns_none_for_access_denied_process() -> None:
"""``cpu_percent()`` and ``memory_info()`` raise ``psutil.AccessDenied``
for processes owned by another user on macOS and on Linux setups
with restricted ``/proc``. The wiring layer treats both that and a
truly missing PID as "no snapshot this tick" — the function must
never let ``AccessDenied`` escape.
"""
with patch.object(
psutil.Process,
"memory_info",
side_effect=psutil.AccessDenied(pid=os.getpid()),
):
assert probe(os.getpid(), cpu_interval=0.0) is None
def test_process_has_open_codex_rollout_matches_rollout_jsonl() -> None:
with patch.object(
psutil.Process,
"open_files",
return_value=[
SimpleNamespace(path="/tmp/unrelated.log"),
SimpleNamespace(path="/Users/me/.codex/rollout-2026-05-17.jsonl"),
],
):
assert process_has_open_codex_rollout(os.getpid()) is True
def test_process_has_open_codex_rollout_returns_false_when_inaccessible() -> None:
with patch.object(
psutil.Process,
"open_files",
side_effect=psutil.AccessDenied(pid=os.getpid()),
):
assert process_has_open_codex_rollout(os.getpid()) is False
def test_psutil_is_not_imported_outside_probe_module() -> None:
"""Acceptance criterion #3: ``psutil`` must stay confined to
``tools/system/fleet_monitoring/probe.py`` so the dependency surface is explicit. A
static scan over runtime package trees catches future regressions
deterministically — runtime import-graph checks would be flaky
against lazy-import patterns the codebase already uses elsewhere.
"""
leaks: list[str] = []
py_files: list[pathlib.Path] = []
for root_name in _SOURCE_ROOTS:
py_files.extend(sorted((_REPO_ROOT / root_name).rglob("*.py")))
for py_file in py_files:
if py_file == _PROBE_MODULE:
continue
text = py_file.read_text(encoding="utf-8")
for needle in ("import psutil", "from psutil"):
if needle in text:
leaks.append(f"{py_file.relative_to(_REPO_ROOT)} contains {needle!r}")
break
assert not leaks, (
"psutil leaked into modules other than tools/system/fleet_monitoring/probe.py:\n "
+ "\n ".join(leaks)
)
def test_probe_returns_nonzero_cpu_for_busy_process(busy_process: int) -> None:
"""Regression: cpu_percent(interval>0) returned 0.0 when called inside proc.oneshot()
because both internal readings hit the same cache (#1950). Probing a busy subprocess
with a positive interval must yield a non-zero value now that the call lives
outside the oneshot block.
"""
snap = probe(busy_process, cpu_interval=0.1)
assert snap is not None
assert snap.cpu_percent > 0.0