summaryrefslogtreecommitdiff
path: root/test/hil
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-10 23:28:09 +0700
committerhathach <[email protected]>2026-07-10 23:28:09 +0700
commit0557655afbb9e608c26ac0c6cbf95c6e69138c77 (patch)
tree86d47b3a5fa8f28409bfd8312dfed9dc045d6ca6 /test/hil
parente3dd9245ef08c457d7c6e5837e3f8d41bad6fd8a (diff)
Fix review findings and add static-analyzer agent
Review-fix batch (owner-confirmed) on the multi-agent harness: - board_lock: detach holder stdio so a captured `hold` cannot hang on the daemon's inherited pipe; probe locks by holder-pid liveness instead of a momentary flock, which could spuriously fail a concurrent acquirer (storm-tested: 1 winner in 10, 0/15 acquire failures under probe storm) - hil_test: locked board renders a visible board-locked fail row so the report matches the exit code; stale marker cleared on a real re-run - pr-babysit: autoPush now opt-in (default dry run); resolve recipe paginates reviewThreads; post-push resolve gets issue-comment fallback - validate: size stage honors non-default base via --base-branch; pvs stage delegated to the new agent - new static-analyzer agent (sonnet): PVS-Studio SAST+MISRA for one board, structured findings gated on files changed vs base Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Rn1AN5DsTdFhRwhugfgKZi
Diffstat (limited to 'test/hil')
-rwxr-xr-xtest/hil/board_lock.py32
-rwxr-xr-xtest/hil/hil_test.py10
2 files changed, 30 insertions, 12 deletions
diff --git a/test/hil/board_lock.py b/test/hil/board_lock.py
index feee2b849..42df80b35 100755
--- a/test/hil/board_lock.py
+++ b/test/hil/board_lock.py
@@ -49,17 +49,22 @@ def read_info(board: str):
def is_locked(board: str) -> bool:
- """True if some live process currently holds the flock."""
- path = lock_path(board)
- if not os.path.exists(path):
+ """True if the recorded holder process is still alive.
+
+ Deliberately never touches the flock: even a momentary probe lock would
+ make a concurrent acquirer's LOCK_NB attempt fail spuriously. The flock
+ taken by acquirers themselves stays the only authority."""
+ info = read_info(board)
+ pid = info.get('pid') if isinstance(info, dict) else None
+ if not isinstance(pid, int) or pid <= 0:
return False
- with open(path) as f:
- try:
- fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
- fcntl.flock(f, fcntl.LOCK_UN)
- return False
- except OSError:
- return True
+ try:
+ os.kill(pid, 0)
+ except ProcessLookupError:
+ return False
+ except PermissionError:
+ return True # alive but owned by another user (e.g. the CI runner)
+ return True
def cmd_hold(boards, reason):
@@ -91,6 +96,13 @@ def cmd_hold(boards, reason):
os._exit(0)
# holder (grandchild): acquire all flocks, signal the parent, sleep until killed
os.close(r_fd)
+ # Detach stdio: a `hold` whose output is captured must see EOF when the
+ # front-end exits — the immortal holder must not keep that pipe open.
+ devnull = os.open(os.devnull, os.O_RDWR)
+ for std_fd in (0, 1, 2):
+ os.dup2(devnull, std_fd)
+ if devnull > 2:
+ os.close(devnull)
try:
handles = []
for b in boards:
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index 979c784ab..2e5085079 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -1704,7 +1704,9 @@ def test_board(board: Board) -> tuple[str, int, list[str], list]:
_lock_fh = acquire_board_lock(name)
except RuntimeError as e:
log_line(f'{name:25} {STATUS_FAILED}: {e}')
- return name, 1, [], []
+ # visible report row so the ❌ matches the exit code; failed-tests stays
+ # empty so a re-run repeats the whole board (no bogus -bt test filter)
+ return name, 1, [], [(name, {'board-locked': 'fail'})]
try:
# default to all tests
test_list = []
@@ -1831,7 +1833,11 @@ def accumulate_report(mret: list, report_dir: Path, fresh: bool) -> str:
pass # corrupt/old sidecar: start fresh
# merge this run: current cells override prior for boards/tests that ran
- for _, _, _, rows in mret:
+ for name, _, _, rows in mret:
+ if rows and not any('board-locked' in cells for _, cells in rows):
+ # board ran for real this time: clear a stale lock-failure cell
+ # (its row is keyed by board name; test rows may be variant names)
+ acc.get(name, {}).pop('board-locked', None)
for row_label, cells in rows:
acc.setdefault(row_label, {}).update(cells)