mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Chore: improve tests
This commit is contained in:
@@ -146,6 +146,14 @@ impl ArmouryAttributeRegistry {
|
||||
self.attrs.push(attr);
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.attrs.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<'_, AsusArmouryAttribute> {
|
||||
self.attrs.iter()
|
||||
}
|
||||
|
||||
pub async fn emit_limits(&self, connection: &Connection) -> Result<(), RogError> {
|
||||
let mut last_err: Option<RogError> = None;
|
||||
for attr in &self.attrs {
|
||||
@@ -517,11 +525,14 @@ impl AsusArmouryAttribute {
|
||||
}
|
||||
|
||||
pub async fn start_attributes_zbus(
|
||||
conn: &Connection,
|
||||
conn: Option<&Connection>,
|
||||
platform: RogPlatform,
|
||||
power: AsusPower,
|
||||
attributes: FirmwareAttributes,
|
||||
config: Arc<Mutex<Config>>,
|
||||
enable_zbus: bool,
|
||||
profile_override: Option<rog_platform::platform::PlatformProfile>,
|
||||
power_plugged_override: Option<bool>,
|
||||
) -> Result<ArmouryAttributeRegistry, RogError> {
|
||||
let mut registry = ArmouryAttributeRegistry::default();
|
||||
for attr in attributes.attributes() {
|
||||
@@ -534,35 +545,117 @@ pub async fn start_attributes_zbus(
|
||||
|
||||
let registry_attr = attr.clone();
|
||||
|
||||
if let Err(e) = attr.reload().await {
|
||||
error!(
|
||||
"Skipping attribute '{}' due to reload error: {e:?}",
|
||||
attr.attr.name()
|
||||
);
|
||||
// continue with others
|
||||
continue;
|
||||
// Only perform the full reload (which may query the platform/power sysfs)
|
||||
// when zbus is enabled. Tests using the no-zbus mode skip the reload and
|
||||
// emulate the reload/apply behavior to avoid depending on udev/sysfs.
|
||||
if enable_zbus {
|
||||
if let Err(e) = attr.reload().await {
|
||||
error!(
|
||||
"Skipping attribute '{}' due to reload error: {e:?}",
|
||||
attr.attr.name()
|
||||
);
|
||||
// continue with others
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let attr_name = attr.attribute_name();
|
||||
|
||||
let path = dbus_path_for_attr(attr_name.as_str());
|
||||
match zbus::object_server::SignalEmitter::new(conn, path) {
|
||||
Ok(sig) => {
|
||||
if let Err(e) = attr.watch_and_notify(sig).await {
|
||||
error!("Failed to start watcher for '{}': {e:?}", attr.attr.name());
|
||||
// If zbus is enabled and a connection is provided, create the SignalEmitter,
|
||||
// start watchers and register the object on zbus. Tests can call this function
|
||||
// with enable_zbus=false and conn=None to skip DBus registration and watchers.
|
||||
if !enable_zbus {
|
||||
// Emulate reload logic but prefer overrides when provided to avoid dependency on udev/sysfs in tests
|
||||
let name: rog_platform::asus_armoury::FirmwareAttribute = attr.attr.name().into();
|
||||
if name.is_ppt() || name.is_dgpu() {
|
||||
// determine profile
|
||||
let profile = if let Some(p) = profile_override {
|
||||
p
|
||||
} else {
|
||||
match attr.platform.get_platform_profile() {
|
||||
Ok(p) => p.into(),
|
||||
Err(_) => rog_platform::platform::PlatformProfile::Balanced,
|
||||
}
|
||||
};
|
||||
|
||||
// determine power plugged
|
||||
let power_plugged = if let Some(v) = power_plugged_override {
|
||||
v
|
||||
} else {
|
||||
match attr.power.get_online() {
|
||||
Ok(v) => v == 1,
|
||||
Err(_) => false,
|
||||
}
|
||||
};
|
||||
|
||||
let apply_value = {
|
||||
let config = attr.config.lock().await;
|
||||
config
|
||||
.select_tunings_ref(power_plugged, profile)
|
||||
.and_then(|tuning| {
|
||||
if tuning.enabled {
|
||||
tuning.group.get(&attr.name()).copied()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if let Some(tune) = apply_value {
|
||||
attr.attr
|
||||
.set_current_value(&AttrValue::Integer(tune))
|
||||
.map_err(|e| {
|
||||
error!("Could not set {} value: {e:?}", attr.attr.name());
|
||||
e
|
||||
})?;
|
||||
}
|
||||
} else {
|
||||
if let Some(saved_value) = attr.config.lock().await.armoury_settings.get(&name) {
|
||||
attr.attr
|
||||
.set_current_value(&AttrValue::Integer(*saved_value))
|
||||
.map_err(|e| {
|
||||
error!("Could not set {} value: {e:?}", attr.attr.name());
|
||||
e
|
||||
})?;
|
||||
info!(
|
||||
"Restored armoury setting {} to {:?}",
|
||||
attr.attr.name(),
|
||||
saved_value
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Failed to create SignalEmitter for '{}': {e:?}",
|
||||
attr.attr.name()
|
||||
);
|
||||
}
|
||||
|
||||
registry.push(registry_attr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Err(e) = attr.move_to_zbus(conn).await {
|
||||
error!("Failed to register attribute '{attr_name}' on zbus: {e:?}");
|
||||
continue;
|
||||
// If zbus is enabled and a connection is provided, create the SignalEmitter,
|
||||
// start watchers and register the object on zbus. Tests can call this function
|
||||
// with enable_zbus=false and conn=None to skip DBus registration and watchers.
|
||||
if enable_zbus {
|
||||
if let Some(connection) = conn {
|
||||
let path = dbus_path_for_attr(attr_name.as_str());
|
||||
match zbus::object_server::SignalEmitter::new(connection, path) {
|
||||
Ok(sig) => {
|
||||
if let Err(e) = attr.watch_and_notify(sig).await {
|
||||
error!("Failed to start watcher for '{}': {e:?}", attr.attr.name());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Failed to create SignalEmitter for '{}': {e:?}",
|
||||
attr.attr.name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = attr.move_to_zbus(connection).await {
|
||||
error!("Failed to register attribute '{attr_name}' on zbus: {e:?}");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
error!("zbus enabled but no Connection provided for attribute registration");
|
||||
}
|
||||
}
|
||||
|
||||
registry.push(registry_attr);
|
||||
|
||||
@@ -77,11 +77,14 @@ async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
let power = AsusPower::new()?; // TODO: maybe needs async mutex?
|
||||
let attributes = FirmwareAttributes::new();
|
||||
let armoury_registry = match start_attributes_zbus(
|
||||
&server,
|
||||
Some(&server),
|
||||
platform.clone(),
|
||||
power.clone(),
|
||||
attributes.clone(),
|
||||
config.clone(),
|
||||
true,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
173
asusd/tests/sysfs_full_service.rs
Normal file
173
asusd/tests/sysfs_full_service.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use tempfile::tempdir;
|
||||
|
||||
use asusd::asus_armoury::start_attributes_zbus;
|
||||
use asusd::config::Config;
|
||||
use rog_platform::asus_armoury::FirmwareAttributes;
|
||||
use rog_platform::platform::PlatformProfile;
|
||||
use rog_platform::platform::RogPlatform;
|
||||
use rog_platform::power::AsusPower;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::sync::Mutex as TokioMutex;
|
||||
|
||||
fn write_attr_dir(base: &PathBuf, name: &str, default: &str, display: &str) {
|
||||
let attr_dir = base.join(name);
|
||||
create_dir_all(&attr_dir).unwrap();
|
||||
|
||||
let mut f = File::create(attr_dir.join("default_value")).unwrap();
|
||||
write!(f, "{}", default).unwrap();
|
||||
let mut f = File::create(attr_dir.join("display_name")).unwrap();
|
||||
write!(f, "{}", display).unwrap();
|
||||
// create current_value file so set_current_value can open for write
|
||||
let mut f = File::create(attr_dir.join("current_value")).unwrap();
|
||||
write!(f, "{}", default).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_service_handles_boot_sound_and_nv_tgp() {
|
||||
let td = tempdir().unwrap();
|
||||
let base = td.path().join("attributes");
|
||||
create_dir_all(&base).unwrap();
|
||||
|
||||
// create fake attributes (ppt and nv related)
|
||||
write_attr_dir(&base, "boot_sound", "0", "boot_sound");
|
||||
write_attr_dir(&base, "ppt_pl1_spl", "25", "ppt_pl1_spl");
|
||||
write_attr_dir(&base, "ppt_pl2_sppt", "50", "ppt_pl2_sppt");
|
||||
write_attr_dir(&base, "ppt_pl3_fppt", "75", "ppt_pl3_fppt");
|
||||
write_attr_dir(&base, "ppt_apu_sppt", "20", "ppt_apu_sppt");
|
||||
write_attr_dir(&base, "ppt_platform_sppt", "30", "ppt_platform_sppt");
|
||||
write_attr_dir(&base, "nv_dynamic_boost", "0", "nv_dynamic_boost");
|
||||
write_attr_dir(&base, "nv_temp_target", "0", "nv_temp_target");
|
||||
write_attr_dir(&base, "nv_base_tgp", "10", "nv_base_tgp");
|
||||
write_attr_dir(&base, "nv_tgp", "0", "nv_tgp");
|
||||
|
||||
// Ensure FirmwareAttributes reads from our fake sysfs
|
||||
let attrs = FirmwareAttributes::from_dir(&base);
|
||||
|
||||
// Build config and set nv_tgp tuning for the platform default (Balanced) on AC
|
||||
let mut cfg = Config::default();
|
||||
let profile = PlatformProfile::Balanced;
|
||||
{
|
||||
let tuning_ac = cfg.select_tunings(true, profile);
|
||||
tuning_ac.enabled = true;
|
||||
tuning_ac
|
||||
.group
|
||||
.insert(rog_platform::asus_armoury::FirmwareAttribute::PptPl1Spl, 42);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl2Sppt,
|
||||
43,
|
||||
);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl3Fppt,
|
||||
44,
|
||||
);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptApuSppt,
|
||||
45,
|
||||
);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPlatformSppt,
|
||||
46,
|
||||
);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::NvDynamicBoost,
|
||||
11,
|
||||
);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::NvTempTarget,
|
||||
66,
|
||||
);
|
||||
tuning_ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::DgpuBaseTgp,
|
||||
12,
|
||||
);
|
||||
tuning_ac
|
||||
.group
|
||||
.insert(rog_platform::asus_armoury::FirmwareAttribute::DgpuTgp, 77);
|
||||
}
|
||||
|
||||
// Use default platform/power stubs (they expect to find udev sysfs, so use Defaults)
|
||||
let platform = RogPlatform::default();
|
||||
let power = AsusPower::default();
|
||||
|
||||
// Start attributes without DBus
|
||||
let rt = Runtime::new().unwrap();
|
||||
let cfg_arc = Arc::new(TokioMutex::new(cfg));
|
||||
let attrs_clone = attrs.clone();
|
||||
rt.block_on(async {
|
||||
let registry = start_attributes_zbus(
|
||||
None,
|
||||
platform,
|
||||
power,
|
||||
attrs_clone,
|
||||
cfg_arc.clone(),
|
||||
false,
|
||||
Some(PlatformProfile::Balanced),
|
||||
Some(true),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// registry now contains AsusArmouryAttribute objects that have been reloaded and applied
|
||||
assert!(!registry.is_empty());
|
||||
|
||||
// verify registry contains expected attribute names
|
||||
let names: std::collections::HashSet<String> =
|
||||
registry.iter().map(|a| a.attribute_name()).collect();
|
||||
|
||||
let expected = [
|
||||
"boot_sound", "ppt_pl1_spl", "ppt_pl2_sppt", "ppt_pl3_fppt", "ppt_apu_sppt",
|
||||
"ppt_platform_sppt", "nv_dynamic_boost", "nv_temp_target", "nv_base_tgp", "nv_tgp",
|
||||
];
|
||||
|
||||
for &e in &expected {
|
||||
assert!(names.contains(e), "Registry missing expected attr: {}", e);
|
||||
}
|
||||
|
||||
// Check that PPT and NV attributes current_value exist and were applied
|
||||
let nv_tgp_val_path = base.join("nv_tgp").join("current_value");
|
||||
let boot_val_path = base.join("boot_sound").join("current_value");
|
||||
let ppt1_val_path = base.join("ppt_pl1_spl").join("current_value");
|
||||
let ppt2_val_path = base.join("ppt_pl2_sppt").join("current_value");
|
||||
let ppt3_val_path = base.join("ppt_pl3_fppt").join("current_value");
|
||||
let apu_val_path = base.join("ppt_apu_sppt").join("current_value");
|
||||
let plat_val_path = base.join("ppt_platform_sppt").join("current_value");
|
||||
let nv_dyn_path = base.join("nv_dynamic_boost").join("current_value");
|
||||
let nv_temp_path = base.join("nv_temp_target").join("current_value");
|
||||
let nv_base_path = base.join("nv_base_tgp").join("current_value");
|
||||
|
||||
let nv = std::fs::read_to_string(&nv_tgp_val_path).unwrap();
|
||||
assert_eq!(nv.trim(), "77");
|
||||
|
||||
// PPTs
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(&ppt1_val_path).unwrap().trim(),
|
||||
"42"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(&ppt2_val_path).unwrap().trim(),
|
||||
"43"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(&ppt3_val_path).unwrap().trim(),
|
||||
"44"
|
||||
);
|
||||
assert_eq!(std::fs::read_to_string(&apu_val_path).unwrap().trim(), "45");
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(&plat_val_path).unwrap().trim(),
|
||||
"46"
|
||||
);
|
||||
|
||||
// NVs
|
||||
assert_eq!(std::fs::read_to_string(&nv_dyn_path).unwrap().trim(), "11");
|
||||
assert_eq!(std::fs::read_to_string(&nv_temp_path).unwrap().trim(), "66");
|
||||
assert_eq!(std::fs::read_to_string(&nv_base_path).unwrap().trim(), "12");
|
||||
|
||||
// boot_sound default was 0, it should remain 0 unless config.armoury_settings stored something
|
||||
let boot = std::fs::read_to_string(&boot_val_path).unwrap();
|
||||
assert_eq!(boot.trim(), "0");
|
||||
});
|
||||
}
|
||||
144
asusd/tests/sysfs_nv_and_ppt_acdc.rs
Normal file
144
asusd/tests/sysfs_nv_and_ppt_acdc.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tempfile::tempdir;
|
||||
|
||||
use asusd::asus_armoury::set_config_or_default;
|
||||
use asusd::config::Config;
|
||||
use rog_platform::asus_armoury::FirmwareAttributes;
|
||||
use rog_platform::platform::PlatformProfile;
|
||||
|
||||
fn write_attr_dir(base: &PathBuf, name: &str, default: &str, display: &str) {
|
||||
let attr_dir = base.join(name);
|
||||
create_dir_all(&attr_dir).unwrap();
|
||||
|
||||
let mut f = File::create(attr_dir.join("default_value")).unwrap();
|
||||
write!(f, "{}", default).unwrap();
|
||||
let mut f = File::create(attr_dir.join("display_name")).unwrap();
|
||||
write!(f, "{}", display).unwrap();
|
||||
// create current_value file so set_current_value can open for write
|
||||
let mut f = File::create(attr_dir.join("current_value")).unwrap();
|
||||
write!(f, "{}", default).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nv_dynamic_boost_and_ppt_acdc() {
|
||||
let td = tempdir().unwrap();
|
||||
let base = td.path().join("attributes");
|
||||
create_dir_all(&base).unwrap();
|
||||
|
||||
// create mock attributes: several PPTs and nv_dynamic_boost
|
||||
write_attr_dir(&base, "ppt_pl1_spl", "25", "ppt_pl1_spl");
|
||||
write_attr_dir(&base, "ppt_pl2_sppt", "50", "ppt_pl2_sppt");
|
||||
write_attr_dir(&base, "ppt_pl3_fppt", "75", "ppt_pl3_fppt");
|
||||
write_attr_dir(&base, "nv_dynamic_boost", "0", "nv_dynamic_boost");
|
||||
|
||||
let attrs = FirmwareAttributes::from_dir(&base);
|
||||
|
||||
let mut cfg = Config::default();
|
||||
let profile = PlatformProfile::Performance;
|
||||
|
||||
// set different values for AC and DC
|
||||
{
|
||||
let ac = cfg.select_tunings(true, profile);
|
||||
ac.enabled = true;
|
||||
ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl1Spl,
|
||||
100,
|
||||
);
|
||||
ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl2Sppt,
|
||||
101,
|
||||
);
|
||||
ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl3Fppt,
|
||||
102,
|
||||
);
|
||||
ac.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::NvDynamicBoost,
|
||||
9,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let dc = cfg.select_tunings(false, profile);
|
||||
dc.enabled = true;
|
||||
dc.group
|
||||
.insert(rog_platform::asus_armoury::FirmwareAttribute::PptPl1Spl, 10);
|
||||
dc.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl2Sppt,
|
||||
11,
|
||||
);
|
||||
dc.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::PptPl3Fppt,
|
||||
12,
|
||||
);
|
||||
dc.group.insert(
|
||||
rog_platform::asus_armoury::FirmwareAttribute::NvDynamicBoost,
|
||||
3,
|
||||
);
|
||||
}
|
||||
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
// apply AC
|
||||
rt.block_on(async {
|
||||
set_config_or_default(&attrs, &mut cfg, true, profile).await;
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("ppt_pl1_spl").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"100"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("ppt_pl2_sppt").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"101"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("ppt_pl3_fppt").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"102"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("nv_dynamic_boost").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"9"
|
||||
);
|
||||
|
||||
// apply DC
|
||||
rt.block_on(async {
|
||||
set_config_or_default(&attrs, &mut cfg, false, profile).await;
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("ppt_pl1_spl").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"10"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("ppt_pl2_sppt").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"11"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("ppt_pl3_fppt").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"12"
|
||||
);
|
||||
assert_eq!(
|
||||
std::fs::read_to_string(base.join("nv_dynamic_boost").join("current_value"))
|
||||
.unwrap()
|
||||
.trim(),
|
||||
"3"
|
||||
);
|
||||
}
|
||||
@@ -394,6 +394,7 @@ impl FirmwareAttribute {
|
||||
self,
|
||||
FirmwareAttribute::NvDynamicBoost
|
||||
| FirmwareAttribute::NvTempTarget
|
||||
| FirmwareAttribute::DgpuBaseTgp
|
||||
| FirmwareAttribute::DgpuTgp
|
||||
)
|
||||
}
|
||||
|
||||
@@ -106,3 +106,13 @@ impl AsusPower {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AsusPower {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mains: PathBuf::from("/this_shouldNeVErr_exisid"),
|
||||
battery: PathBuf::from("/this_shouldNeVErr_exisid"),
|
||||
usb: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user