mod error;
pub use error::{Error, Result};
pub(crate) mod dbus;
pub use dbus::{
ConnectionCredentials, ReleaseNameReply, RequestNameFlags, RequestNameReply, StartServiceReply,
};
#[cfg(feature = "proxy")]
pub use dbus::{
DBusProxy, NameAcquired, NameAcquiredArgs, NameAcquiredStream, NameLost, NameLostArgs,
NameLostStream, NameOwnerChanged, NameOwnerChangedArgs, NameOwnerChangedStream,
};
#[cfg(any(feature = "proxy", feature = "service"))]
pub(crate) mod introspectable;
#[cfg(feature = "service")]
pub(crate) use introspectable::Introspectable;
#[cfg(feature = "proxy")]
pub use introspectable::IntrospectableProxy;
#[cfg(feature = "proxy")]
pub(crate) mod monitoring;
#[cfg(feature = "proxy")]
pub use monitoring::MonitoringProxy;
pub(crate) mod object_manager;
pub use object_manager::ManagedObjects;
#[cfg(feature = "object-manager")]
pub use object_manager::ObjectManager;
#[cfg(feature = "proxy")]
pub use object_manager::{
InterfacesAdded, InterfacesAddedArgs, InterfacesAddedStream, InterfacesRemoved,
InterfacesRemovedArgs, InterfacesRemovedStream, ObjectManagerProxy,
};
#[cfg(any(feature = "proxy", feature = "service"))]
pub(crate) mod peer;
#[cfg(feature = "service")]
pub(crate) use peer::Peer;
#[cfg(feature = "proxy")]
pub use peer::PeerProxy;
#[cfg(any(feature = "proxy", feature = "service"))]
pub(crate) mod properties;
#[cfg(feature = "service")]
pub use properties::Properties;
#[cfg(feature = "proxy")]
pub use properties::{
PropertiesChanged, PropertiesChangedArgs, PropertiesChangedStream, PropertiesProxy,
};
#[cfg(feature = "proxy")]
pub(crate) mod stats;
#[cfg(feature = "proxy")]
pub use stats::StatsProxy;
#[cfg(all(test, feature = "proxy", feature = "service"))]
mod tests {
use std::sync::Arc;
use crate::{DBusError, Error, fdo, message::Message};
#[cfg(any(feature = "default-rt", feature = "tokio"))]
use crate::{interface, names::WellKnownName};
#[cfg(any(feature = "default-rt", feature = "tokio"))]
use futures_util::StreamExt;
#[cfg(any(feature = "default-rt", feature = "tokio"))]
use ntest::timeout;
use test_log::test;
#[cfg(any(feature = "default-rt", feature = "tokio"))]
use tokio::runtime;
#[cfg(any(feature = "default-rt", feature = "tokio"))]
use super::PeerProxy;
#[test]
fn error_from_zerror() {
let m = Message::method_call("/", "foo")
.destination(":1.2")
.build(&())
.unwrap();
let m = Message::error(&m.header(), "org.freedesktop.DBus.Error.TimedOut")
.build(&("so long"))
.unwrap();
let e: Error = m.into();
let e: fdo::Error = e.into();
assert_eq!(e, fdo::Error::TimedOut("so long".to_string()),);
assert_eq!(e.name(), "org.freedesktop.DBus.Error.TimedOut");
assert_eq!(e.description(), Some("so long"));
}
#[test]
fn error_from_dbus_variant() {
let e = Error::DBus(Arc::new(fdo::Error::TimedOut("so long".to_string())));
assert_eq!(
e.to_string(),
"org.freedesktop.DBus.Error.TimedOut: so long"
);
let e: fdo::Error = e.into();
assert_eq!(e, fdo::Error::TimedOut("so long".to_string()));
}
#[cfg(any(feature = "default-rt", feature = "tokio"))]
#[test]
#[timeout(15000)]
fn signal() {
runtime::Runtime::new().unwrap().block_on(test_signal());
runtime::Builder::new_current_thread()
.enable_io()
.build()
.unwrap()
.block_on(test_signal());
}
#[cfg(any(feature = "default-rt", feature = "tokio"))]
async fn test_signal() {
let conn = crate::Connection::session().await.unwrap();
let proxy = fdo::DBusProxy::new(&conn).await.unwrap();
let well_known = "org.freedesktop.zbus.FdoSignalStreamTest";
let unique_name = conn.unique_name().unwrap();
let owner_change_stream = proxy
.receive_name_owner_changed_with_args(&[(0, well_known), (2, unique_name.as_str())])
.await
.unwrap();
let name_acquired_stream = proxy
.receive_name_acquired_with_args(&[(0, well_known)])
.await
.unwrap();
let mut stream = owner_change_stream.zip(name_acquired_stream);
let well_known: WellKnownName<'static> = well_known.try_into().unwrap();
proxy
.request_name(well_known.as_ref(), fdo::RequestNameFlags::REPLACE_EXISTING)
.await
.unwrap();
let (name_owner_changed, name_acquired) = stream.next().await.unwrap();
assert_eq!(name_owner_changed.args().unwrap().name(), &well_known);
assert_eq!(
*name_owner_changed
.args()
.unwrap()
.new_owner()
.as_ref()
.unwrap(),
*unique_name
);
assert_eq!(name_acquired.args().unwrap().name(), &well_known);
let result = proxy.release_name(well_known.as_ref()).await.unwrap();
assert_eq!(result, fdo::ReleaseNameReply::Released);
let result = proxy.release_name(well_known).await.unwrap();
assert_eq!(result, fdo::ReleaseNameReply::NonExistent);
let _stream = proxy
.receive_features_changed()
.await
.filter_map(|changed| async move {
let v = changed.get().await.ok();
dbg!(v)
});
}
#[cfg(all(
feature = "object-manager",
any(feature = "default-rt", feature = "tokio")
))]
#[test]
#[timeout(15000)]
fn no_object_manager_signals_before_hello() {
crate::block_on(no_object_manager_signals_before_hello_async());
}
#[cfg(all(
feature = "object-manager",
any(feature = "default-rt", feature = "tokio")
))]
async fn no_object_manager_signals_before_hello_async() {
let conn = zbus::Connection::session().await.unwrap();
let mut stream = zbus::MessageStream::for_match_rule(
zbus::MatchRule::builder()
.msg_type(zbus::message::Type::Signal)
.interface("org.freedesktop.DBus.ObjectManager")
.path("/org/zbus/NoObjectManagerSignalsBeforeHello")
.build()
.unwrap(),
&conn,
None,
)
.await
.unwrap();
struct TestObj;
#[interface(name = "org.zbus.TestObj")]
impl TestObj {
#[zbus(property)]
fn test(&self) -> String {
"test".into()
}
}
let _conn = zbus::conn::Builder::session()
.name("org.zbus.NoObjectManagerSignalsBeforeHello")
.serve_at("/org/zbus/NoObjectManagerSignalsBeforeHello/Obj", TestObj)
.serve_at(
"/org/zbus/NoObjectManagerSignalsBeforeHello",
super::ObjectManager,
)
.build()
.await
.unwrap();
let msg = stream.next().await.unwrap().unwrap();
let signal = super::InterfacesAdded::from_message(msg).unwrap();
assert_eq!(
signal.args().unwrap().interfaces_and_properties,
vec![(
"org.zbus.TestObj".try_into().unwrap(),
vec![("Test", crate::Variant::new("test"))]
.into_iter()
.collect()
)]
.into_iter()
.collect()
);
}
#[cfg(any(feature = "default-rt", feature = "tokio"))]
#[test]
#[timeout(15000)]
fn peer_on_arbitrary_path() {
crate::block_on(peer_on_arbitrary_path_async());
}
#[cfg(any(feature = "default-rt", feature = "tokio"))]
async fn peer_on_arbitrary_path_async() {
struct TestObj;
#[interface(name = "org.zbus.TestObj")]
impl TestObj {}
let _service_conn = zbus::conn::Builder::session()
.name("org.zbus.PeerArbitraryPathTest")
.serve_at("/registered", TestObj)
.build()
.await
.unwrap();
let client_conn = zbus::Connection::session().await.unwrap();
let proxy = PeerProxy::new(
&client_conn,
"org.zbus.PeerArbitraryPathTest",
"/this/path/does/not/exist",
)
.await
.expect("Failed to create PeerProxy");
let result = proxy.ping().await;
assert!(result.is_ok(), "Ping on unregistered path should succeed");
let proxy = PeerProxy::new(
&client_conn,
"org.zbus.PeerArbitraryPathTest",
"/another/unregistered/path",
)
.await
.expect("Failed to create PeerProxy");
let result = proxy.get_machine_id().await;
match &result {
Ok(id) => {
assert!(!id.is_empty(), "Machine ID should not be empty");
}
#[cfg(not(any(
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
windows,
)))]
Err(fdo::Error::NotSupported(_)) => {
}
Err(e) => {
panic!("GetMachineId failed unexpectedly: {:?}", e);
}
}
let proxy = PeerProxy::new(
&client_conn,
"org.zbus.PeerArbitraryPathTest",
"/registered",
)
.await
.expect("Failed to create PeerProxy");
let result = proxy.ping().await;
assert!(result.is_ok(), "Ping on registered path should succeed");
let result = client_conn
.call_method(
Some("org.zbus.PeerArbitraryPathTest"),
"/unregistered",
Some("org.freedesktop.DBus.Peer"),
"UnknownMethod",
&(),
)
.await;
assert!(result.is_err(), "Unknown method should fail");
}
}