fix(tests): prevent behave-parallel multiprocessing deadlock on btrfs/overlayfs #9826
@@ -23,6 +23,7 @@ import argparse
|
||||
import io
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
@@ -32,6 +33,50 @@ from typing import Any
|
||||
|
||||
DEFAULT_FEATURE_ROOT = "features/"
|
||||
|
||||
|
||||
def _is_btrfs_or_overlayfs() -> bool:
|
||||
fs_targets = {"btrfs", "overlay"}
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["stat", "-f", "-c", "%T", "."],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
pass
|
||||
else:
|
||||
fs_type = result.stdout.strip().lower()
|
||||
return fs_type in fs_targets
|
||||
|
||||
try:
|
||||
current_path = os.path.realpath(".")
|
||||
best_match_len = -1
|
||||
best_fs_type: str | None = None
|
||||
with open("/proc/mounts", encoding="utf-8") as mounts:
|
||||
for line in mounts:
|
||||
parts = line.split()
|
||||
if len(parts) < 3:
|
||||
continue
|
||||
mount_point = parts[1].replace("\\040", " ")
|
||||
mount_real = os.path.realpath(mount_point)
|
||||
if not mount_real:
|
||||
continue
|
||||
if (
|
||||
current_path == mount_real
|
||||
or current_path.startswith(mount_real.rstrip("/") + "/")
|
||||
) and len(mount_real) > best_match_len:
|
||||
best_match_len = len(mount_real)
|
||||
best_fs_type = parts[2].lower()
|
||||
if best_fs_type:
|
||||
return best_fs_type in fs_targets
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# Type alias for summary dictionaries
|
||||
Summary = dict[str, Any]
|
||||
|
||||
@@ -321,8 +366,6 @@ def main(argv: list[str] | None = None) -> None:
|
||||
|
||||
# Pass-through --help / --version to behave
|
||||
if any(flag in remaining for flag in ("-h", "--help", "--version")):
|
||||
import subprocess
|
||||
|
||||
code = subprocess.run(
|
||||
[sys.executable, "-m", "behave", *other_args, *feature_args]
|
||||
).returncode
|
||||
@@ -348,6 +391,7 @@ def main(argv: list[str] | None = None) -> None:
|
||||
or coverage_mode
|
||||
or len(feature_paths) == 1
|
||||
or len(feature_paths) <= 2
|
||||
or _is_btrfs_or_overlayfs()
|
||||
):
|
||||
# ---- sequential in-process mode ----
|
||||
_, total = _run_features_inprocess(feature_paths, other_args)
|
||||
|
||||
Reference in New Issue
Block a user