From 63fd9fc6d615f8ca2ebda6459c50493c192e9d66 Mon Sep 17 00:00:00 2001 From: Leonardo Forchini Date: Thu, 1 Oct 2026 09:41:09 +0100 Subject: [PATCH 1/2] Allow for per-test dbus sessions dbus sessions will be used to get controller status in component tests which means each test will have to have an independent bus. Allow for test-only non-system runs of the daemon. Signed-off-by: Leonardo Forchini --- src/daemon.rs | 3 ++- src/dbus.rs | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/daemon.rs b/src/daemon.rs index dd46083e..d6c8475c 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -92,7 +92,8 @@ pub async fn run(cfg: Config, backends: Vec>) -> Result<(), Dae tracing::info!(target: "controller", added, "initial discovery"); let (dbus_tx, mut dbus_rx) = tokio::sync::mpsc::channel(1); - let _dbus_connection = dbus::serve(dbus::Service::new(dbus_tx)).await?; + let service = dbus::Service::new(dbus_tx); + let _dbus_connection = dbus::serve(service).await?; let mut inotify_events = setup_inotify(&backends)?; let mut poll = interval(Duration::from_secs_f64(cfg.scale_poll_secs)); poll.set_missed_tick_behavior(MissedTickBehavior::Skip); diff --git a/src/dbus.rs b/src/dbus.rs index e622ca66..c35481e3 100644 --- a/src/dbus.rs +++ b/src/dbus.rs @@ -327,8 +327,22 @@ impl Service { /// Spin the D-Bus service on the well-known name / object path /// backed by `service` and drive replies from the controller mpsc. +/// +/// Component tests set `IO_THREAD_CONTROLLER_DBUS_ADDRESS` to use their +/// private bus; production leaves it unset and uses the system bus. pub async fn serve(service: Service) -> Result { - let conn = zbus::connection::Builder::system()? + let builder = match std::env::var("IO_THREAD_CONTROLLER_DBUS_ADDRESS") { + Ok(address) => zbus::connection::Builder::address(address.as_str())?, + Err(_) => zbus::connection::Builder::system()?, + }; + serve_with(builder, service).await +} + +async fn serve_with( + builder: zbus::connection::Builder<'_>, + service: Service, +) -> Result { + let conn = builder .name(DBUS_BUS_NAME)? .serve_at(DBUS_OBJECT_PATH, service)? .build() From d5ed9bc364ae307728ba34d22cd4e91f929db0b3 Mon Sep 17 00:00:00 2001 From: Leonardo Forchini Date: Fri, 23 Oct 2026 09:05:30 +0100 Subject: [PATCH 2/2] Create DBus session for each component test AI-Generated: Most of it Signed-off-by: Leonardo Forchini --- tests/component/harness/dbus.py | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/component/harness/dbus.py diff --git a/tests/component/harness/dbus.py b/tests/component/harness/dbus.py new file mode 100644 index 00000000..f348eb71 --- /dev/null +++ b/tests/component/harness/dbus.py @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2026 Nutanix, Inc. All rights reserved. +# +# Author: Leonardo Forchini + +import signal +import subprocess + +from harness.common import wait_for + + +class DBusServer: + """Test only DBus instance.""" + def __init__(self, root): + """ + Create a new DBus environment, enabling each test to have its own + bus and ensuring isolation. + """ + self._socket = root / "dbus.sock" + self._config = root / "dbus.xml" + self._config.write_text( + """ + + system + unix:path=%s + EXTERNAL + + + + + + +""" + % self._socket + ) + self._proc = None + self.address = None + + def start(self): + """Start the bus and wait for it to come up.""" + self._proc = subprocess.Popen( + [ + "dbus-daemon", + "--nofork", + "--config-file=%s" % self._config, + "--print-address", + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + assert self._proc.stdout is not None + self.address = self._proc.stdout.readline().strip() + if not self.address: + raise RuntimeError("dbus-daemon did not print an address") + wait_for(self._socket.exists, 5, "DBus to come up") + + def stop(self): + """Stop the bus.""" + if self._proc is None or self._proc.poll() is not None: + return + self._proc.send_signal(signal.SIGTERM) + try: + self._proc.wait(timeout=5) + except subprocess.TimeoutExpired: + self._proc.kill() + self._proc.wait(timeout=5)