Merge origin/testing into hunter
This commit is contained in:
commit
a4d427099e
19 files changed
+424
-35
No files matched your search
@@ -3,10 +3,12 @@
|
||||
# Authors: Storm Dragon, Angus Kola
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""Launch native tests with disposable runtime sockets and private D-Bus."""
|
||||
import errno
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
|
||||
def run_private_session(command, *, env, **kwargs):
|
||||
@@ -20,12 +22,26 @@ def run_private_session(command, *, env, **kwargs):
|
||||
|
||||
# Keep this path short: AT-SPI falls back from named sockets if its
|
||||
# generated socket path is 100 bytes or longer.
|
||||
with tempfile.TemporaryDirectory(prefix="cth-run-", dir="/tmp") as runtimeDir:
|
||||
sessionEnv = dict(env, XDG_RUNTIME_DIR=runtimeDir)
|
||||
runtime = tempfile.TemporaryDirectory(prefix="cth-run-", dir="/tmp")
|
||||
try:
|
||||
sessionEnv = dict(env, XDG_RUNTIME_DIR=runtime.name)
|
||||
for name in ("DBUS_SESSION_BUS_ADDRESS", "DBUS_STARTER_ADDRESS", "DBUS_STARTER_BUS_TYPE",
|
||||
"AT_SPI_BUS_ADDRESS", "WAYLAND_DISPLAY"):
|
||||
sessionEnv.pop(name, None)
|
||||
return subprocess.run(command, env=sessionEnv, **kwargs)
|
||||
finally:
|
||||
# Activated document portals tear down their FUSE mount after D-Bus
|
||||
# exits. Wait for that teardown instead of hiding a test's result with
|
||||
# a transient disconnected-mount error, or ignoring cleanup failures.
|
||||
deadline = time.monotonic() + 5
|
||||
while True:
|
||||
try:
|
||||
runtime.cleanup()
|
||||
break
|
||||
except OSError as error:
|
||||
if error.errno not in (errno.ENOTCONN, errno.EBUSY) or time.monotonic() >= deadline:
|
||||
raise
|
||||
time.sleep(0.05)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""Runtime isolation and real AT-SPI socket collision regressions."""
|
||||
import ast
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
@@ -55,6 +56,60 @@ print(json.dumps(dict(runtime=str(runtime), mode=stat.S_IMODE(runtime.stat().st_
|
||||
self.assertEqual(caught.exception.returncode, 7)
|
||||
self.assertFalse(Path(caught.exception.stdout.strip()).exists())
|
||||
|
||||
def test_portal_teardown_retry_preserves_child_failure(self):
|
||||
originalCleanup = tempfile.TemporaryDirectory.cleanup
|
||||
attempts = []
|
||||
|
||||
def cleanup(runtime):
|
||||
attempts.append(runtime.name)
|
||||
if len(attempts) <= 2:
|
||||
errorCode = (errno.ENOTCONN, errno.EBUSY)[len(attempts) - 1]
|
||||
raise OSError(errorCode, "Document portal is shutting down")
|
||||
originalCleanup(runtime)
|
||||
|
||||
with patch("native_test_session.tempfile.TemporaryDirectory.cleanup", cleanup), \
|
||||
patch("native_test_session.time.sleep") as pause:
|
||||
with self.assertRaises(subprocess.CalledProcessError) as caught:
|
||||
run_private_session(
|
||||
["dbus-run-session", "--", sys.executable, "-c", "raise SystemExit(7)"],
|
||||
env=os.environ, capture_output=True, check=True, timeout=15)
|
||||
self.assertEqual(caught.exception.returncode, 7)
|
||||
self.assertEqual(len(attempts), 3)
|
||||
self.assertEqual(pause.call_count, 2)
|
||||
self.assertFalse(Path(attempts[0]).exists())
|
||||
|
||||
def test_cleanup_does_not_hide_unrelated_errors(self):
|
||||
originalCleanup = tempfile.TemporaryDirectory.cleanup
|
||||
|
||||
def cleanup(runtime):
|
||||
originalCleanup(runtime)
|
||||
raise PermissionError(errno.EACCES, "Cleanup denied")
|
||||
|
||||
with patch("native_test_session.tempfile.TemporaryDirectory.cleanup", cleanup), \
|
||||
patch("native_test_session.time.sleep") as pause:
|
||||
with self.assertRaises(PermissionError):
|
||||
run_private_session(
|
||||
["dbus-run-session", "--", sys.executable, "-c", "pass"],
|
||||
env=os.environ, capture_output=True, check=True, timeout=15)
|
||||
pause.assert_not_called()
|
||||
|
||||
def test_portal_teardown_wait_is_bounded(self):
|
||||
originalCleanup = tempfile.TemporaryDirectory.cleanup
|
||||
|
||||
def cleanup(runtime):
|
||||
originalCleanup(runtime)
|
||||
raise OSError(errno.ENOTCONN, "Document portal did not unmount")
|
||||
|
||||
with patch("native_test_session.tempfile.TemporaryDirectory.cleanup", cleanup), \
|
||||
patch("native_test_session.time.monotonic", side_effect=[0, 6]), \
|
||||
patch("native_test_session.time.sleep") as pause:
|
||||
with self.assertRaises(OSError) as caught:
|
||||
run_private_session(
|
||||
["dbus-run-session", "--", sys.executable, "-c", "pass"],
|
||||
env=os.environ, capture_output=True, check=True, timeout=15)
|
||||
self.assertEqual(caught.exception.errno, errno.ENOTCONN)
|
||||
pause.assert_not_called()
|
||||
|
||||
def test_rejects_dbus_before_xvfb_without_launching(self):
|
||||
with patch("native_test_session.subprocess.run") as launch:
|
||||
with self.assertRaisesRegex(ValueError, "Start Xvfb before D-Bus"):
|
||||
|
||||
Reference in new issue
Block a user