Early Platform.exit detached JavaFX while queued macOS activation callbacks still called Java. Close the owned example before terminating its JVM, make shutdown idempotent, and reject late preview work. Add real startup-cancellation regressions and native crash-report checks.
72 lines
3.5 KiB
Python
72 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Run the disposable companion checks in real isolated IntelliJ windows (macOS)."""
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import re
|
|
import shutil
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import zipfile
|
|
from native_crashes import NativeCrashGuard, descendant_workers, await_worker_exit
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
p = argparse.ArgumentParser(description=__doc__)
|
|
p.add_argument("--java-home", type=Path, required=True)
|
|
p.add_argument("--target-java-home", type=Path, required=True)
|
|
p.add_argument("--idea-home", type=Path, required=True)
|
|
args = p.parse_args()
|
|
output = ROOT / "target/ide-workflow"
|
|
output.mkdir(parents=True, exist_ok=True)
|
|
for mode in ("classpath", "modulepath"):
|
|
crashes = NativeCrashGuard(ROOT)
|
|
launch = subprocess.run([sys.executable, ROOT / "scripts/run-fixture-host.py", "intellij",
|
|
"--check", "--mode", mode, "--java-home", args.java_home,
|
|
"--target-java-home", args.target_java_home, "--idea-home", args.idea_home],
|
|
cwd=ROOT, text=True, capture_output=True, check=True, timeout=60)
|
|
(output / (mode + "-launch.log")).write_text(launch.stdout + launch.stderr)
|
|
base = Path(re.search(r"Disposable host: (.+)", launch.stdout)[1])
|
|
pid = int(re.search(r"Host PID: (\d+)", launch.stdout)[1])
|
|
try:
|
|
until = time.monotonic() + 240
|
|
while time.monotonic() < until:
|
|
if (base / "FAILURE.txt").exists():
|
|
raise RuntimeError((base / "FAILURE.txt").read_text())
|
|
if (base / "SUCCESS.txt").exists():
|
|
break
|
|
time.sleep(.25)
|
|
else:
|
|
raise RuntimeError("IDE qualification timed out: " + str(base))
|
|
natives = subprocess.run([args.java_home / "bin/jcmd", str(pid), "VM.dynlibs"],
|
|
capture_output=True, text=True, check=True, timeout=20).stdout
|
|
(output / (mode + "-natives.txt")).write_text(natives)
|
|
paths = sorted(set(re.findall(r"(/[^\r\n]*?libglass\.dylib)", natives)))
|
|
expected = {}
|
|
for artifact in (Path.home() / ".m2/repository/org/openjfx").glob("*/26/*-mac*.jar"):
|
|
with zipfile.ZipFile(artifact) as jar:
|
|
for name in jar.namelist():
|
|
if name.endswith(".dylib"):
|
|
expected.setdefault(Path(name).name, set()).add(hashlib.sha256(jar.read(name)).hexdigest())
|
|
actual = {path: hashlib.sha256(Path(path).read_bytes()).hexdigest() for path in paths}
|
|
assert len(actual) == 1 and next(iter(actual.values())) in expected["libglass.dylib"], actual
|
|
all_paths = sorted(set(re.findall(r"(/[^\r\n]*?/\.openjfx/[^\r\n]*?\.dylib)", natives)))
|
|
all_native = {path: hashlib.sha256(Path(path).read_bytes()).hexdigest() for path in all_paths}
|
|
assert all(digest in expected.get(Path(path).name, set()) for path, digest in all_native.items())
|
|
proof = {"mode": mode, "host": str(base), "glass": actual, "openjfx": all_native,
|
|
"result": (base / "SUCCESS.txt").read_text()}
|
|
(output / (mode + ".json")).write_text(json.dumps(proof, indent=2) + "\n")
|
|
shutil.copyfile(base / "intellij.png", output / (mode + ".png"))
|
|
finally:
|
|
workers = descendant_workers(pid)
|
|
try:
|
|
os.kill(pid, signal.SIGTERM)
|
|
except ProcessLookupError:
|
|
pass
|
|
await_worker_exit(workers)
|
|
crashes.check()
|
|
print("PASS registered IntelliJ " + mode + " editor, exclusive JavaFX 26 natives and worker shutdown", flush=True)
|