Separate theme rendering from client subscriptions and materials
This commit is contained in:
1 parent
ccf7497b6f
commit
cc0bddbec1
32 files changed
+428
-143
No files matched your search
@@ -6,15 +6,24 @@ import unittest
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def production_dependencies(manifest, workspace_dependencies):
|
||||
dependencies = set()
|
||||
for section in [manifest, *manifest.get("target", {}).values()]:
|
||||
for kind in ("dependencies", "build-dependencies"):
|
||||
for alias, specification in section.get(kind, {}).items():
|
||||
if isinstance(specification, dict) and specification.get("workspace"):
|
||||
specification = workspace_dependencies[alias]
|
||||
name = specification.get("package", alias) if isinstance(specification, dict) else alias
|
||||
dependencies.add(name)
|
||||
return dependencies
|
||||
|
||||
|
||||
def dependency_graph():
|
||||
workspace = tomllib.loads((ROOT / "Cargo.toml").read_text())
|
||||
workspace = tomllib.loads((ROOT / "Cargo.toml").read_text())["workspace"]
|
||||
graph = {}
|
||||
for member in workspace["workspace"]["members"]:
|
||||
for member in workspace["members"]:
|
||||
manifest = tomllib.loads((ROOT / member / "Cargo.toml").read_text())
|
||||
dependencies = set(manifest.get("dependencies", {}))
|
||||
for target in manifest.get("target", {}).values():
|
||||
dependencies.update(target.get("dependencies", {}))
|
||||
graph[manifest["package"]["name"]] = dependencies
|
||||
graph[manifest["package"]["name"]] = production_dependencies(manifest, workspace.get("dependencies", {}))
|
||||
return graph
|
||||
|
||||
|
||||
@@ -43,6 +52,26 @@ class ComponentBoundaries(unittest.TestCase):
|
||||
def test_ipc_does_not_depend_on_configuration(self):
|
||||
self.assertNotIn("ferese-config", reachable(dependency_graph(), "ferese-ipc"))
|
||||
|
||||
def test_rendering_does_not_load_configuration_or_own_clients(self):
|
||||
dependencies = reachable(dependency_graph(), "ferese-theme")
|
||||
self.assertTrue(dependencies.isdisjoint({
|
||||
"ferese-config", "ferese-ipc", "ferese-theme-client", "ferese-protocols",
|
||||
}), dependencies)
|
||||
|
||||
def test_client_integration_does_not_depend_on_rendering_or_core(self):
|
||||
dependencies = reachable(dependency_graph(), "ferese-theme-client")
|
||||
self.assertTrue(dependencies.isdisjoint({"ferese-theme", "ferese-core"}), dependencies)
|
||||
|
||||
def test_aliases_build_dependencies_and_target_dependencies_are_checked(self):
|
||||
manifest = {
|
||||
"dependencies": {"alias": {"workspace": True}},
|
||||
"build-dependencies": {"builder": {"package": "ferese-config"}},
|
||||
"target": {"cfg(unix)": {"dependencies": {"client": {"package": "ferese-theme-client"}}}},
|
||||
"dev-dependencies": {"ferese-theme": {}},
|
||||
}
|
||||
self.assertEqual(production_dependencies(manifest, {"alias": {"package": "ferese-core"}}),
|
||||
{"ferese-core", "ferese-config", "ferese-theme-client"})
|
||||
|
||||
def test_transitive_dependencies_are_checked(self):
|
||||
self.assertIn("core", reachable({"shell": {"helper"}, "helper": {"core"}}, "shell"))
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
"""Check client material lifetimes on a disposable nested compositor.
|
||||
|
||||
FERESE_TEST_MATERIAL=1 python3 scripts/tests/test_material_isolated.py
|
||||
Requires built debug compositor binaries, a Wayland host and dbus-daemon.
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
@unittest.skipUnless(os.environ.get("FERESE_TEST_MATERIAL") == "1", "requires a Wayland host")
|
||||
class MaterialLifetime(unittest.TestCase):
|
||||
def test_attachment_and_release(self):
|
||||
with tempfile.TemporaryDirectory(prefix="ferese-material-") as directory:
|
||||
root = Path(directory)
|
||||
runtime = root / "runtime"
|
||||
runtime.mkdir(mode=0o700)
|
||||
config = root / "config/ferese"
|
||||
config.mkdir(parents=True)
|
||||
(config / "config.kdl").write_text("")
|
||||
host = Path(os.environ["WAYLAND_DISPLAY"])
|
||||
if not host.is_absolute():
|
||||
host = Path(os.environ["XDG_RUNTIME_DIR"]) / host
|
||||
env = dict(os.environ, WAYLAND_DISPLAY=str(host), XDG_RUNTIME_DIR=str(runtime),
|
||||
XDG_CONFIG_HOME=str(root / "config"), XDG_DATA_HOME=str(root / "data"),
|
||||
XDG_STATE_HOME=str(root / "state"), XDG_CACHE_HOME=str(root / "cache"))
|
||||
children = []
|
||||
with (root / "compositor.log").open("w") as log:
|
||||
try:
|
||||
bus = subprocess.Popen(["dbus-daemon", "--session", "--nofork", "--print-address=1"],
|
||||
env=env, stdout=subprocess.PIPE, text=True, start_new_session=True)
|
||||
children.append(bus)
|
||||
env["DBUS_SESSION_BUS_ADDRESS"] = bus.stdout.readline().strip()
|
||||
compositor = subprocess.Popen([str(ROOT / "target/debug/ferese"), "--backend", "nested"],
|
||||
env=env, stdout=log, stderr=log, start_new_session=True)
|
||||
children.append(compositor)
|
||||
deadline = time.monotonic() + 10
|
||||
while time.monotonic() < deadline:
|
||||
self.assertIsNone(compositor.poll(), (root / "compositor.log").read_text())
|
||||
sockets = [p for p in runtime.glob("wayland-*") if p.is_socket()]
|
||||
if sockets and (runtime / "ferese/control.sock").is_socket():
|
||||
break
|
||||
time.sleep(.05)
|
||||
else:
|
||||
self.fail("Nested compositor did not become ready")
|
||||
env["WAYLAND_DISPLAY"] = str(sockets[0])
|
||||
result = subprocess.run([
|
||||
"cargo", "test", "--workspace", "--locked",
|
||||
"material::tests::attachment_acknowledgement_and_last_clone_release",
|
||||
"--", "--ignored", "--exact",
|
||||
], cwd=ROOT, env=env, capture_output=True, text=True, timeout=120)
|
||||
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
|
||||
self.assertIn("1 passed", result.stdout)
|
||||
self.assertIsNone(compositor.poll())
|
||||
finally:
|
||||
for child in reversed(children):
|
||||
if child.poll() is None:
|
||||
os.killpg(child.pid, signal.SIGTERM)
|
||||
child.wait(timeout=5)
|
||||
if child.stdout:
|
||||
child.stdout.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user