From 529c6b59821b33307b867e1ae7bbb2adf304cda9 Mon Sep 17 00:00:00 2001 From: Dennis Juhler Aagaard Date: Thu, 24 Sep 2026 18:21:05 +0200 Subject: [PATCH] test: retain wrapped browser processes --- tests/test_addon_metadata.py | 54 ++++++++++++++++++++++++++++ tests/test_runtime.sh | 70 +++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 17 deletions(-) diff --git a/tests/test_addon_metadata.py b/tests/test_addon_metadata.py index 9776b15..d38aa47 100644 --- a/tests/test_addon_metadata.py +++ b/tests/test_addon_metadata.py @@ -1,7 +1,10 @@ from __future__ import annotations import hashlib +import os import re +import subprocess from pathlib import Path +import pytest import yaml ROOT = Path(__file__).parents[1] @@ -124,3 +127,54 @@ def test_runtime_requires_process_baseline_after_cdp_close_and_zero_stopped_pid( assert ready_index < baseline_index < close_index < return_index assert "{{.State.Pid}}" in runtime_test assert '[ "$state" = "exited 0 0" ]' in runtime_test + + +def test_runtime_process_normalization_retains_every_unknown_wrapped_child( + tmp_path: Path, +) -> None: + runtime_test = ROOT / "tests/test_runtime.sh" + top_file = tmp_path / "docker-top.txt" + environment = os.environ.copy() + environment.update( + { + "DOCKER_HOST": "unix:///nonexistent-runtime-normalization.sock", + "SKIP_BUILD": "1", + } + ) + service_lines = [ + "101 /run/rosetta/rosetta /usr/local/bin/python3 python3 /usr/local/bin/addon-supervisor", + "102 /run/rosetta/rosetta /usr/local/bin/python3 python3 /usr/local/bin/cloakserve --headless=true --idle-timeout=30 --data-dir=/tmp/cloakserve", + "103 /usr/bin/qemu-x86_64-static /usr/local/bin/stelloauth", + ] + + def normalize(extra_line: str | None = None) -> list[str]: + lines = ["PID COMMAND", *service_lines] + if extra_line is not None: + lines.append(extra_line) + top_file.write_text("\n".join(lines) + "\n", encoding="utf-8") + completed = subprocess.run( + [str(runtime_test), "--normalize-processes", str(top_file)], + cwd=ROOT, + env=environment, + text=True, + capture_output=True, + check=False, + ) + assert completed.returncode == 0, completed.stderr + return completed.stdout.splitlines() + + baseline = ["addon-supervisor", "cloakserve", "stelloauth"] + assert normalize() == baseline + + wrapped_children = [ + "/run/rosetta/rosetta /opt/vendor/headless-shell --user-data-dir=/tmp/profile", + "/run/rosetta/rosetta /opt/vendor/browser --profile runtime-readiness", + "/run/rosetta/rosetta /opt/vendor/crashpad_handler --database=/tmp/profile", + "/run/rosetta/rosetta /opt/vendor/opaque-child --flag", + "/run/rosetta/rosetta /opt/vendor/opaque-child --parent=/usr/local/bin/cloakserve", + "/usr/bin/qemu-x86_64-static /opt/vendor/opaque-qemu-child", + ] + for offset, child in enumerate(wrapped_children, start=104): + normalized = normalize(f"{offset} {child}") + assert normalized == sorted([*baseline, f"unexpected:{child}"]) + assert normalized != baseline diff --git a/tests/test_runtime.sh b/tests/test_runtime.sh index 19486f9..634570d 100755 --- a/tests/test_runtime.sh +++ b/tests/test_runtime.sh @@ -108,10 +108,8 @@ wait_ready() { fail "$container did not become ready within 90 seconds" } -normalized_process_commands() { - local container="$1" - local top_file="${tmp_dir}/${container}-processes.txt" - docker top "$container" -eo pid,args > "$top_file" +normalize_process_file() { + local top_file="$1" python3 - "$top_file" <<'PY' import pathlib import sys @@ -120,20 +118,44 @@ commands = [] for raw_line in pathlib.Path(sys.argv[1]).read_text(encoding="utf-8").splitlines()[1:]: fields = raw_line.split(maxsplit=1) command = " ".join(fields[1].split()) if len(fields) == 2 else "" - lowered = command.lower() - if "/usr/local/bin/addon-supervisor" in command: - commands.append("addon-supervisor") - elif "/usr/local/bin/cloakserve" in command: - commands.append("cloakserve") - elif "/usr/local/bin/stelloauth" in command: - commands.append("stelloauth") - elif ( - ("/run/rosetta/rosetta" in lowered or "qemu-" in lowered) - and "chrome" not in lowered - and "chromium" not in lowered - and "headless_shell" not in lowered + tokens = command.split() + while tokens and ( + tokens[0] == "/run/rosetta/rosetta" + or pathlib.Path(tokens[0]).name.startswith("qemu-") ): - continue + tokens = tokens[1:] + + python_prefixes = ( + [], + ["python3"], + ["/usr/local/bin/python3"], + ["/usr/local/bin/python3", "python3"], + ) + supervisor_commands = [ + [*prefix, "/usr/local/bin/addon-supervisor"] + for prefix in python_prefixes + ] + cloak_commands = [ + [ + *prefix, + "/usr/local/bin/cloakserve", + "--headless=true", + "--idle-timeout=30", + "--data-dir=/tmp/cloakserve", + ] + for prefix in python_prefixes + ] + stelloauth_commands = ( + ["/usr/local/bin/stelloauth"], + ["/usr/local/bin/stelloauth", "/usr/local/bin/stelloauth"], + ) + + if tokens in supervisor_commands: + commands.append("addon-supervisor") + elif tokens in cloak_commands: + commands.append("cloakserve") + elif tokens in stelloauth_commands: + commands.append("stelloauth") elif command: commands.append(f"unexpected:{command}") @@ -141,6 +163,13 @@ print("\n".join(sorted(commands))) PY } +normalized_process_commands() { + local container="$1" + local top_file="${tmp_dir}/${container}-processes.txt" + docker top "$container" -eo pid,args > "$top_file" + normalize_process_file "$top_file" +} + capture_process_baseline() { local container="$1" local expected current @@ -317,6 +346,13 @@ PY [ "$state" = "exited 0 0" ] || fail "$container state is $state, want exited 0 with PID 0" } +if [ "${1:-}" = "--normalize-processes" ]; then + [ "$#" -eq 2 ] || fail "--normalize-processes requires one docker top file" + normalize_process_file "$2" + exit +fi +[ "$#" -eq 0 ] || fail "unexpected runtime test arguments" + mkdir -p "$artifacts_dir" write_options