use super::*;
use crate::{
SystemdUnitFile,
enums::{DependencyType, StartStopMode},
};
use test_base::{TEST_SERVICE, init_logs};
use zvariant::Value;
#[ignore = "need a connection to a service"]
#[test]
fn stop_service_test() -> Result<(), SystemdErrors> {
crate::stop_unit(UnitDBusLevel::System, TEST_SERVICE, StartStopMode::Fail)?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_get_unit_file_state() {
init_logs();
let file1: &str = TEST_SERVICE;
let status = get_unit_file_state(UnitDBusLevel::System, file1);
debug!("Status: {status:?}");
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_list_unit_files_system() -> Result<(), SystemdErrors> {
init_logs();
let level = UnitDBusLevel::System;
let unit_files = fill_list_unit_files(level).await?;
info!("Unit file returned {}", unit_files.len());
for (idx, unit_file) in unit_files.iter().enumerate() {
debug!("{idx} - {}", unit_file.full_name);
debug!("{}", unit_file.file_path);
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_list_unit_files_remote() -> Result<(), SystemdErrors> {
init_logs();
let level = UnitDBusLevel::System;
let unit_files = fill_list_unit_files(level).await?;
info!("Unit file returned {}", unit_files.len());
for (idx, unit_file) in unit_files.iter().enumerate() {
debug!("{idx} - {}", unit_file.full_name);
debug!("{}", unit_file.file_path);
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_list_unit_files_system_raw() -> Result<(), SystemdErrors> {
init_logs();
let level = UnitDBusLevel::System;
let array: Vec<ListedUnitFile> = systemd_manager_async(level)
.await?
.list_unit_files()
.await?;
for (idx, unit_file) in array.iter().enumerate() {
debug!(
"{idx} - {} - {}",
unit_file.enablement_status, unit_file.unit_file_path
);
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_list_units_by_patterns() -> Result<(), SystemdErrors> {
init_logs();
let array: Vec<ListedLoadedUnit> = systemd_manager_async(UnitDBusLevel::System)
.await?
.list_units_by_patterns(&["active", "inactive"], &["*.timer"])
.await?;
for (idx, loaded_unit) in array.iter().enumerate() {
debug!(
"{idx} - {} - {}",
loaded_unit.primary_unit_name, loaded_unit.load_state
);
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_list_units_late_filter_timer() -> Result<(), SystemdErrors> {
init_logs();
let array: Vec<ListedLoadedUnit> = systemd_manager_async(UnitDBusLevel::System)
.await?
.list_units()
.await?;
for (idx, loaded_unit) in array
.iter()
.filter(|lunit| lunit.primary_unit_name.ends_with("timer"))
.enumerate()
{
debug!(
"{idx} - {} - {}",
loaded_unit.primary_unit_name, loaded_unit.active_state
);
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
pub fn test_get_unit_path() -> Result<(), SystemdErrors> {
init_logs();
let unit_file: &str = "tiny_daemon.service";
let connection = get_blocking_connection(UnitDBusLevel::System)?;
let message = connection.call_method(
Some(DESTINATION_SYSTEMD),
PATH_SYSTEMD,
Some(INTERFACE_SYSTEMD_MANAGER),
"GetUnit",
&(unit_file),
)?;
info!("message {message:?}");
let body = message.body();
let z: zvariant::ObjectPath = body.deserialize()?;
info!("obj {:?}", z.as_str());
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
pub fn test_fetch_system_unit_info() -> Result<(), SystemdErrors> {
init_logs();
let btree_map = fetch_system_unit_info(
UnitDBusLevel::System,
"/org/freedesktop/systemd1/unit/tiny_5fdaemon_2eservice",
UnitType::Service,
)?;
debug!("ALL PARAM: {btree_map:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_info() -> Result<(), SystemdErrors> {
init_logs();
let path = unit_dbus_path_from_name(TEST_SERVICE);
println!("unit {TEST_SERVICE} Path {path}");
let map = fetch_system_unit_info(UnitDBusLevel::System, &path, UnitType::Service)?;
println!("{map:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_system_info() -> Result<(), SystemdErrors> {
init_logs();
let map = fetch_system_info(UnitDBusLevel::System)?;
info!("{map:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_unit() -> Result<(), SystemdErrors> {
init_logs();
let unit = fetch_unit(UnitDBusLevel::System, TEST_SERVICE)?;
info!("{unit:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_unit_user_session() -> Result<(), SystemdErrors> {
init_logs();
let unit = fetch_unit(UnitDBusLevel::UserSession, TEST_SERVICE)?;
info!("{unit:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_unit_wrong_bus() -> Result<(), SystemdErrors> {
init_logs();
let unit = fetch_unit(UnitDBusLevel::UserSession, TEST_SERVICE)?;
info!("{}", unit.debug());
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_unit_dependencies() -> Result<(), SystemdErrors> {
init_logs();
let path = unit_dbus_path_from_name(TEST_SERVICE);
let res = unit_get_dependencies(
UnitDBusLevel::System,
TEST_SERVICE,
&path,
DependencyType::Forward,
false,
);
info!("{:#?}", res.unwrap());
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_unit_reverse_dependencies() -> Result<(), SystemdErrors> {
init_logs();
let path = unit_dbus_path_from_name(TEST_SERVICE);
let res = unit_get_dependencies(
UnitDBusLevel::System,
TEST_SERVICE,
&path,
DependencyType::Reverse,
false,
);
info!("{res:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_fetch_unit_fail_wrong_name() -> Result<(), SystemdErrors> {
init_logs();
let fake = format!("{TEST_SERVICE}_fake");
match fetch_unit(UnitDBusLevel::System, &fake) {
Ok(_) => todo!(),
Err(e) => {
warn!("{e:?}");
if let SystemdErrors::ZNoSuchUnit(_method, _message) = e {
Ok(())
} else {
Err(SystemdErrors::Custom("Wrong expected Error".to_owned()))
}
}
}
}
#[test]
fn test_name_convertion() {
let tests = [
("tiny_daemon.service", "tiny_5fdaemon_2eservice"),
("-.mount", "_2d_2emount"),
("1first", "_31first"),
];
for (origin, expected) in tests {
let convertion = bus_label_escape(origin);
assert_eq!(convertion, expected);
}
}
#[ignore = "need a connection to a service"]
#[test]
fn test_get_unit_processes() -> Result<(), SystemdErrors> {
let unit_file: &str = "system.slice";
let list = retreive_unit_processes(UnitDBusLevel::System, unit_file)?;
for up in list {
println!("{up:#?}")
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_get_unit_active_state() -> Result<(), SystemdErrors> {
let unit_object = unit_dbus_path_from_name(TEST_SERVICE);
println!("path : {unit_object}");
let state = get_unit_active_state(UnitDBusLevel::System, &unit_object)?;
println!("state of {TEST_SERVICE} is {state:?}");
Ok(())
}
async fn get_unit_list_test(level: UnitDBusLevel) -> Result<Vec<ListedLoadedUnit>, SystemdErrors> {
let connection = get_connection(level).await?;
let r = list_units_list_async(connection).await?;
info!("Returned units count: {}", r.len());
Ok(r)
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_unit_list_system() -> Result<(), SystemdErrors> {
init_logs();
let _map = get_unit_list_test(UnitDBusLevel::System).await?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_unit_list_user() -> Result<(), SystemdErrors> {
init_logs();
let _map = get_unit_list_test(UnitDBusLevel::UserSession).await?;
Ok(())
}
async fn get_unit_file_list_test(
level: UnitDBusLevel,
) -> Result<Vec<SystemdUnitFile>, SystemdErrors> {
let r = fill_list_unit_files(level).await?;
info!("Returned units count: {}", r.len());
Ok(r)
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_unit_file_list_system() -> Result<(), SystemdErrors> {
init_logs();
let _map = get_unit_file_list_test(UnitDBusLevel::System).await?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_unit_file_list_user() -> Result<(), SystemdErrors> {
init_logs();
let _map = get_unit_list_test(UnitDBusLevel::UserSession).await?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_list() -> Result<(), SystemdErrors> {
init_logs();
let connection = get_connection(UnitDBusLevel::System).await?;
let connection2 = get_connection(UnitDBusLevel::UserSession).await?;
use std::time::Instant;
let now = Instant::now();
let t1 = tokio::spawn(list_units_list_async(connection.clone()));
let t2 = tokio::spawn(fill_list_unit_files(UnitDBusLevel::System));
let t3 = tokio::spawn(list_units_list_async(connection2.clone()));
let t4 = tokio::spawn(fill_list_unit_files(UnitDBusLevel::UserSession));
let _asdf = tokio::join!(t1, t2, t3, t4);
let elapsed = now.elapsed();
println!("Elapsed: {elapsed:.2?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_list2() -> Result<(), SystemdErrors> {
let connection = get_connection(UnitDBusLevel::System).await?;
let connection2 = get_connection(UnitDBusLevel::UserSession).await?;
use std::time::Instant;
let now = Instant::now();
let t1 = list_units_list_async(connection.clone());
let t2 = fill_list_unit_files(UnitDBusLevel::System);
let t3 = list_units_list_async(connection2.clone());
let t4 = fill_list_unit_files(UnitDBusLevel::UserSession);
let joined_result = tokio::join!(t1, t2, t3, t4);
let elapsed = now.elapsed();
println!("Elapsed: {elapsed:.2?}");
let r1 = joined_result.0.unwrap();
let r2 = joined_result.1.unwrap();
let r3 = joined_result.2.unwrap();
let r4 = joined_result.3.unwrap();
println!("System unit description size {}", r1.len());
println!("System unit file size {}", r2.len());
println!("Session unit description size {}", r3.len());
println!("Session unit file size {}", r4.len());
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_get_properties() -> Result<(), SystemdErrors> {
init_logs();
let connection = get_blocking_connection(UnitDBusLevel::System)?;
let object_path = unit_dbus_path_from_name(TEST_SERVICE);
debug!("Unit path: {object_path}");
let properties_proxy: zbus::blocking::fdo::PropertiesProxy =
fdo::PropertiesProxy::builder(&connection)
.destination(DESTINATION_SYSTEMD)?
.path(object_path)?
.build()?;
let unit_type = UnitType::Service;
let unit_interface = unit_type.interface();
let unit_interface_name = InterfaceName::try_from(INTERFACE_SYSTEMD_UNIT).unwrap();
let mut unit_properties: HashMap<String, OwnedValue> =
properties_proxy.get_all(unit_interface_name)?;
let interface_name = InterfaceName::try_from(unit_interface).unwrap();
let properties: HashMap<String, OwnedValue> = properties_proxy.get_all(interface_name)?;
info!("Properties size {}", properties.len());
info!("Unit Properties size {}", unit_properties.len());
for k in properties.into_keys() {
unit_properties.remove(&k);
}
info!("Unit Properties size {}", unit_properties.len());
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_kill_unit() -> Result<(), SystemdErrors> {
init_logs();
let unit_name: &str = TEST_SERVICE;
kill_unit(UnitDBusLevel::System, unit_name, KillWho::Main, 1)
}
#[ignore = "need a connection to a service"]
#[test]
fn test_queue_signal_unit() -> Result<(), SystemdErrors> {
init_logs();
let unit_name: &str = TEST_SERVICE;
let val: i32 = libc::SIGRTMIN();
let val2 = libc::SIGRTMAX();
println!("{val} {val2}");
queue_signal_unit(UnitDBusLevel::System, unit_name, KillWho::Main, 9, 0)
}
#[ignore = "need a connection to a service"]
#[test]
pub(super) fn test_unit_clean() -> Result<(), SystemdErrors> {
init_logs();
let handle_answer = |_method: &str, _return_message: &Message| {
info!("Clean Unit SUCCESS");
Ok(())
};
let path = unit_dbus_path_from_name(TEST_SERVICE);
let what = ["logs"];
let r = send_unit_message(
UnitDBusLevel::System,
"Clean",
&(&what),
handle_answer,
&path,
);
if let Err(ref e) = r {
error!("{e:?}");
}
r
}
fn send_unit_message<T, U>(
level: UnitDBusLevel,
method: &str,
body: &T,
handler: impl Fn(&str, &Message) -> Result<U, SystemdErrors>,
path: &str,
) -> Result<U, SystemdErrors>
where
T: serde::ser::Serialize + DynamicType,
U: std::fmt::Debug,
{
let message = Message::method_call(path, method)?
.with_flags(Flags::AllowInteractiveAuth)?
.destination(DESTINATION_SYSTEMD)?
.interface(INTERFACE_SYSTEMD_UNIT)?
.build(body)?;
let connection = get_blocking_connection(level)?;
connection.send(&message)?;
let message_it = MessageIterator::from(connection);
for message_res in message_it {
debug!("Message response {message_res:?}");
let return_message = message_res?;
match return_message.message_type() {
zbus::message::Type::MethodReturn => {
info!("{method} Response");
let result = handler(method, &return_message);
return result;
}
zbus::message::Type::MethodCall => {
warn!("Not supposed to happen: {return_message:?}");
break;
}
zbus::message::Type::Error => {
let error = zbus::Error::from(return_message);
{
match error {
zbus::Error::MethodError(
ref owned_error_name,
ref details,
ref message,
) => {
warn!(
"Method error: {}\nDetails: {}\n{:?}",
owned_error_name.as_str(),
details.as_ref().map(|s| s.as_str()).unwrap_or_default(),
message
)
}
_ => warn!("Bus error: {error:?}"),
}
}
return Err(SystemdErrors::from(error));
}
zbus::message::Type::Signal => {
info!("Signal: {return_message:?}");
continue;
}
}
}
let msg = format!("{method:?} ????, response supposed to be Unreachable");
warn!("{msg}");
Err(SystemdErrors::Malformed(
msg,
"sequences of messages".to_owned(),
))
}
#[ignore = "need a connection to a service"]
#[test]
fn test_mask_unit_file() -> Result<(), SystemdErrors> {
init_logs();
let unit_name: &str = TEST_SERVICE;
mask_unit_files(UnitDBusLevel::System, &[unit_name], false, false)?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_mask_unit_file2() -> Result<(), SystemdErrors> {
init_logs();
let unit_file_name: &str = "/etc/systemd/system/tiny_daemon.service";
mask_unit_files(UnitDBusLevel::System, &[unit_file_name], false, false)?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_unmask_unit_file() -> Result<(), SystemdErrors> {
init_logs();
let unit_name: &str = TEST_SERVICE;
unmask_unit_files(UnitDBusLevel::System, &[unit_name], false)?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[test]
fn test_introspect() -> Result<(), SystemdErrors> {
init_logs();
let result: Result<(), SystemdErrors> = {
let connection = get_blocking_connection(UnitDBusLevel::System)?;
info!("Connect");
let message = connection.call_method(
Some(DESTINATION_SYSTEMD),
"/org/freedesktop/systemd1/archlinux_2dkeyring_2dwkd_2dsync_2etimer",
Some("org.freedesktop.DBus.Introspectable"),
"Introspect",
&(),
)?;
info!("message {message:?}");
let body = message.body();
info!("signature {:?}", body.signature());
let z: String = body.deserialize()?;
info!("obj {:?}", z);
Ok(())
};
if let Err(ref e) = result {
warn!("ASTFGSDFGD {e:?}");
}
result
}
#[ignore = "need a connection to a service"]
#[test]
fn test_introspect2() -> Result<(), SystemdErrors> {
init_logs();
fn sub() -> Result<(), SystemdErrors> {
let connection = get_blocking_connection(UnitDBusLevel::System)?;
let proxy = Proxy::new(
&connection,
DESTINATION_SYSTEMD,
"/org/freedesktop/systemd1/unit/archlinux_2dkeyring_2dwkd_2dsync_2etimer",
"org.freedesktop.DBus.Introspectable",
)?;
info!("Proxy {proxy:?}");
let xml = proxy.introspect()?;
let root_node = zbus_xml::Node::from_reader(xml.as_bytes())?;
for int in root_node.interfaces() {
info!("Interface {}", int.name());
for prop in int.properties() {
info!("\tProp {} {:?}", prop.name(), prop.ty().to_string());
}
}
Ok(())
}
sub().map_err(|e| {
warn!("ASTFGSDFGD {e:?}");
e
})
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_introspect3() -> Result<(), SystemdErrors> {
init_logs();
let map = fetch_unit_interface_properties().await?;
for (k, v) in map.iter() {
info!("{k}\t{}", v.len());
}
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_introspect_types() -> Result<(), SystemdErrors> {
init_logs();
let map = fetch_unit_interface_properties().await?;
let signatures = map
.values()
.flatten()
.fold(BTreeMap::new(), |mut acc, unit_property| {
*acc.entry(&unit_property.signature).or_insert(1) += 1;
acc
});
println!("{signatures:#?}");
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_get_properties2() -> Result<(), SystemdErrors> {
init_logs();
let connection = get_connection(UnitDBusLevel::System).await?;
let object_path = unit_dbus_path_from_name(TEST_SERVICE);
let message = connection
.call_method(
Some(DESTINATION_SYSTEMD),
object_path,
Some("org.freedesktop.DBus.Properties"),
"Get",
&("org.freedesktop.systemd1.Unit", "ConditionTimestamp"),
)
.await?;
let body = message.body();
info!("signature {:?}", body.signature().to_string());
let z: Value = body.deserialize()?;
info!("obj {:?}", z);
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_reboot() -> Result<(), SystemdErrors> {
let connection = get_connection(UnitDBusLevel::System).await?;
reboot_async(connection, true).await?;
Ok(())
}
#[ignore = "need a connection to a service"]
#[tokio::test]
async fn test_power_off() -> Result<(), SystemdErrors> {
let connection = get_connection(UnitDBusLevel::System).await?;
power_off_async(connection).await?;
Ok(())
}
#[test]
fn test_bytes_msg() {
init_logs();
let bytes: [u8; 80] = [
108, 2, 1, 1, 0, 0, 0, 0, 255, 255, 255, 255, 62, 0, 0, 0, 5, 1, 117, 0, 8, 0, 0, 0, 7, 1,
115, 0, 20, 0, 0, 0, 111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111,
112, 46, 68, 66, 117, 115, 0, 0, 0, 0, 6, 1, 115, 0, 6, 0, 0, 0, 58, 49, 46, 51, 52, 53, 0,
0, 8, 1, 103, 0, 0, 0, 0, 0,
];
info!("String: {}", "ASDFASDFAF");
let s = String::from_utf8_lossy(&bytes);
info!("String: {}", s);
info!("String: {}", s);
info!("String: {}", s);
info!("String: {}", s);
}
#[test]
fn test_bytes_msg2() {
init_logs();
info!("String: {}", "ASDFASDFAF");
}