1mod error;
2pub use error::{Error, Result};
3
4pub(crate) mod dbus;
5pub use dbus::{
6 ConnectionCredentials, DBusProxy, NameAcquired, NameAcquiredArgs, NameAcquiredStream, NameLost,
7 NameLostArgs, NameLostStream, NameOwnerChanged, NameOwnerChangedArgs, NameOwnerChangedStream,
8 ReleaseNameReply, RequestNameFlags, RequestNameReply, StartServiceReply,
9};
10
11pub(crate) mod introspectable;
12pub(crate) use introspectable::Introspectable;
13pub use introspectable::IntrospectableProxy;
14
15pub(crate) mod monitoring;
16pub use monitoring::MonitoringProxy;
17
18pub(crate) mod object_manager;
19pub use object_manager::{
20 InterfacesAdded, InterfacesAddedArgs, InterfacesAddedStream, InterfacesRemoved,
21 InterfacesRemovedArgs, InterfacesRemovedStream, ManagedObjects, ObjectManager,
22 ObjectManagerProxy,
23};
24
25pub(crate) mod peer;
26pub(crate) use peer::Peer;
27pub use peer::PeerProxy;
28
29pub(crate) mod properties;
30pub use properties::{
31 Properties, PropertiesChanged, PropertiesChangedArgs, PropertiesChangedStream, PropertiesProxy,
32};
33
34pub(crate) mod stats;
35pub use stats::StatsProxy;
36
37#[cfg(test)]
38mod tests {
39 use crate::{DBusError, Error, fdo, interface, message::Message};
40 use futures_util::StreamExt;
41 use ntest::timeout;
42 use test_log::test;
43 use tokio::runtime;
44 use zbus_names::WellKnownName;
45
46 use super::PeerProxy;
47
48 #[test]
49 fn error_from_zerror() {
50 let m = Message::method_call("/", "foo")
51 .unwrap()
52 .destination(":1.2")
53 .unwrap()
54 .build(&())
55 .unwrap();
56 let m = Message::error(&m.header(), "org.freedesktop.DBus.Error.TimedOut")
57 .unwrap()
58 .build(&("so long"))
59 .unwrap();
60 let e: Error = m.into();
61 let e: fdo::Error = e.into();
62 assert_eq!(e, fdo::Error::TimedOut("so long".to_string()),);
63 assert_eq!(e.name(), "org.freedesktop.DBus.Error.TimedOut");
64 assert_eq!(e.description(), Some("so long"));
65 }
66
67 #[test]
68 #[timeout(15000)]
69 fn signal() {
70 runtime::Runtime::new().unwrap().block_on(test_signal());
72
73 runtime::Builder::new_current_thread()
75 .enable_io()
76 .build()
77 .unwrap()
78 .block_on(test_signal());
79 }
80
81 async fn test_signal() {
82 let conn = crate::Connection::session().await.unwrap();
83 let proxy = fdo::DBusProxy::new(&conn).await.unwrap();
84
85 let well_known = "org.freedesktop.zbus.FdoSignalStreamTest";
88 let unique_name = conn.unique_name().unwrap();
89 let owner_change_stream = proxy
90 .receive_name_owner_changed_with_args(&[(0, well_known), (2, unique_name.as_str())])
91 .await
92 .unwrap();
93
94 let name_acquired_stream = proxy
95 .receive_name_acquired_with_args(&[(0, well_known)])
96 .await
97 .unwrap();
98 let mut stream = owner_change_stream.zip(name_acquired_stream);
99
100 let well_known: WellKnownName<'static> = well_known.try_into().unwrap();
101 proxy
102 .request_name(
103 well_known.as_ref(),
104 fdo::RequestNameFlags::ReplaceExisting.into(),
105 )
106 .await
107 .unwrap();
108
109 let (name_owner_changed, name_acquired) = stream.next().await.unwrap();
110 assert_eq!(name_owner_changed.args().unwrap().name(), &well_known);
111 assert_eq!(
112 *name_owner_changed
113 .args()
114 .unwrap()
115 .new_owner()
116 .as_ref()
117 .unwrap(),
118 *unique_name
119 );
120 assert_eq!(name_acquired.args().unwrap().name(), &well_known);
121
122 let result = proxy.release_name(well_known.as_ref()).await.unwrap();
123 assert_eq!(result, fdo::ReleaseNameReply::Released);
124
125 let result = proxy.release_name(well_known).await.unwrap();
126 assert_eq!(result, fdo::ReleaseNameReply::NonExistent);
127
128 let _stream = proxy
129 .receive_features_changed()
130 .await
131 .filter_map(|changed| async move {
132 let v = changed.get().await.ok();
133 dbg!(v)
134 });
135 }
136
137 #[test]
138 #[timeout(15000)]
139 fn no_object_manager_signals_before_hello() {
140 crate::block_on(no_object_manager_signals_before_hello_async());
141 }
142
143 async fn no_object_manager_signals_before_hello_async() {
144 let conn = zbus::Connection::session().await.unwrap();
150 let mut stream = zbus::MessageStream::for_match_rule(
151 zbus::MatchRule::builder()
152 .msg_type(zbus::message::Type::Signal)
153 .interface("org.freedesktop.DBus.ObjectManager")
154 .unwrap()
155 .path("/org/zbus/NoObjectManagerSignalsBeforeHello")
156 .unwrap()
157 .build(),
158 &conn,
159 None,
160 )
161 .await
162 .unwrap();
163
164 struct TestObj;
166 #[interface(name = "org.zbus.TestObj")]
167 impl TestObj {
168 #[zbus(property)]
169 fn test(&self) -> String {
170 "test".into()
171 }
172 }
173 let _conn = zbus::conn::Builder::session()
174 .unwrap()
175 .name("org.zbus.NoObjectManagerSignalsBeforeHello")
176 .unwrap()
177 .serve_at("/org/zbus/NoObjectManagerSignalsBeforeHello/Obj", TestObj)
178 .unwrap()
179 .serve_at(
180 "/org/zbus/NoObjectManagerSignalsBeforeHello",
181 super::ObjectManager,
182 )
183 .unwrap()
184 .build()
185 .await
186 .unwrap();
187
188 let msg = stream.next().await.unwrap().unwrap();
190 let signal = super::InterfacesAdded::from_message(msg).unwrap();
191 assert_eq!(
192 signal.args().unwrap().interfaces_and_properties,
193 vec![(
194 "org.zbus.TestObj".try_into().unwrap(),
195 vec![("Test", zvariant::Value::new("test"))]
196 .into_iter()
197 .collect()
198 )]
199 .into_iter()
200 .collect()
201 );
202 }
203
204 #[test]
205 #[timeout(15000)]
206 fn peer_on_arbitrary_path() {
207 crate::block_on(peer_on_arbitrary_path_async());
208 }
209
210 async fn peer_on_arbitrary_path_async() {
220 struct TestObj;
222 #[interface(name = "org.zbus.TestObj")]
223 impl TestObj {}
224
225 let _service_conn = zbus::conn::Builder::session()
226 .unwrap()
227 .name("org.zbus.PeerArbitraryPathTest")
228 .unwrap()
229 .serve_at("/registered", TestObj)
230 .unwrap()
231 .build()
232 .await
233 .unwrap();
234
235 let client_conn = zbus::Connection::session().await.unwrap();
237
238 let proxy = PeerProxy::new(
240 &client_conn,
241 "org.zbus.PeerArbitraryPathTest",
242 "/this/path/does/not/exist",
243 )
244 .await
245 .expect("Failed to create PeerProxy");
246 let result = proxy.ping().await;
247 assert!(result.is_ok(), "Ping on unregistered path should succeed");
248
249 let proxy = PeerProxy::new(
251 &client_conn,
252 "org.zbus.PeerArbitraryPathTest",
253 "/another/unregistered/path",
254 )
255 .await
256 .expect("Failed to create PeerProxy");
257 let result = proxy.get_machine_id().await;
258 match &result {
261 Ok(id) => {
262 assert!(!id.is_empty(), "Machine ID should not be empty");
263 }
264 #[cfg(not(any(
265 target_os = "linux",
266 target_os = "macos",
267 target_os = "freebsd",
268 target_os = "dragonfly",
269 target_os = "openbsd",
270 target_os = "netbsd",
271 windows,
272 )))]
273 Err(fdo::Error::NotSupported(_)) => {
274 }
276 Err(e) => {
277 panic!("GetMachineId failed unexpectedly: {:?}", e);
278 }
279 }
280
281 let proxy = PeerProxy::new(
283 &client_conn,
284 "org.zbus.PeerArbitraryPathTest",
285 "/registered",
286 )
287 .await
288 .expect("Failed to create PeerProxy");
289 let result = proxy.ping().await;
290 assert!(result.is_ok(), "Ping on registered path should succeed");
291
292 let result = client_conn
294 .call_method(
295 Some("org.zbus.PeerArbitraryPathTest"),
296 "/unregistered",
297 Some("org.freedesktop.DBus.Peer"),
298 "UnknownMethod",
299 &(),
300 )
301 .await;
302 assert!(result.is_err(), "Unknown method should fail");
303 }
304}