mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-15 18:56:49 -04:00
manager/user: Add interface for remote relay interfaces
This commit is contained in:
parent
29ffb42a4e
commit
19d7e3e7c4
5 changed files with 465 additions and 18 deletions
|
@ -298,6 +298,27 @@
|
|||
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
com.steampowered.SteamOSManager1.RemoteInterface1
|
||||
@short_description: TKTK
|
||||
-->
|
||||
<interface name="com.steampowered.SteamOSManager1.RemoteInterface1">
|
||||
|
||||
<method name="RegisterInterface">
|
||||
<arg type="s" name="interface" direction="in"/>
|
||||
<arg type="o" name="object" direction="in"/>
|
||||
<arg type="b" name="registered" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="UnregisterInterface">
|
||||
<arg type="s" name="interface" direction="in"/>
|
||||
<arg type="b" name="unregistered" direction="out"/>
|
||||
</method>
|
||||
|
||||
<property name="RemoteInterfaces" type="as" access="read"/>
|
||||
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
com.steampowered.SteamOSManager1.ScreenReader1
|
||||
@short_description: Optional interface for managing a screen reader.
|
||||
|
|
|
@ -25,6 +25,7 @@ mod hdmi_cec1;
|
|||
mod low_power_mode1;
|
||||
mod manager2;
|
||||
mod performance_profile1;
|
||||
mod remote_interface1;
|
||||
mod screenreader0;
|
||||
mod storage1;
|
||||
mod tdp_limit1;
|
||||
|
@ -44,6 +45,7 @@ pub use crate::hdmi_cec1::HdmiCec1Proxy;
|
|||
pub use crate::low_power_mode1::LowPowerMode1Proxy;
|
||||
pub use crate::manager2::Manager2Proxy;
|
||||
pub use crate::performance_profile1::PerformanceProfile1Proxy;
|
||||
pub use crate::remote_interface1::RemoteInterface1Proxy;
|
||||
pub use crate::screenreader0::ScreenReader0Proxy;
|
||||
pub use crate::storage1::Storage1Proxy;
|
||||
pub use crate::tdp_limit1::TdpLimit1Proxy;
|
||||
|
|
35
steamos-manager-proxy/src/remote_interface1.rs
Normal file
35
steamos-manager-proxy/src/remote_interface1.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
//! # D-Bus interface proxy for: `com.steampowered.SteamOSManager1.RemoteInterface1`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `5.1.0` from D-Bus introspection data.
|
||||
//! Source: `com.steampowered.SteamOSManager1.xml`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the [Writing a client proxy] section of the zbus
|
||||
//! documentation.
|
||||
//!
|
||||
//!
|
||||
//! [Writing a client proxy]: https://dbus2.github.io/zbus/client.html
|
||||
//! [D-Bus standard interfaces]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces,
|
||||
use zbus::proxy;
|
||||
#[proxy(
|
||||
interface = "com.steampowered.SteamOSManager1.RemoteInterface1",
|
||||
default_service = "com.steampowered.SteamOSManager1",
|
||||
default_path = "/com/steampowered/SteamOSManager1",
|
||||
assume_defaults = true
|
||||
)]
|
||||
pub trait RemoteInterface1 {
|
||||
/// RegisterInterface method
|
||||
fn register_interface(
|
||||
&self,
|
||||
interface: &str,
|
||||
object: &zbus::zvariant::ObjectPath<'_>,
|
||||
) -> zbus::Result<bool>;
|
||||
|
||||
/// UnregisterInterface method
|
||||
fn unregister_interface(&self, interface: &str) -> zbus::Result<bool>;
|
||||
|
||||
/// RemoteInterfaces property
|
||||
#[zbus(property)]
|
||||
fn remote_interfaces(&self) -> zbus::Result<Vec<String>>;
|
||||
}
|
|
@ -11,12 +11,18 @@ use std::collections::HashMap;
|
|||
use tokio::fs::try_exists;
|
||||
use tokio::sync::mpsc::{Sender, UnboundedSender};
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::task::{spawn, JoinHandle};
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::error;
|
||||
use zbus::object_server::{Interface, SignalEmitter};
|
||||
use zbus::fdo::{self, DBusProxy};
|
||||
use zbus::message::Header;
|
||||
use zbus::names::{BusName, UniqueName};
|
||||
use zbus::object_server::{Interface, InterfaceRef, SignalEmitter};
|
||||
use zbus::proxy::{Builder, CacheProperties};
|
||||
use zbus::zvariant::Fd;
|
||||
use zbus::{fdo, interface, zvariant, Connection, ObjectServer, Proxy};
|
||||
use zbus::zvariant::{Fd, ObjectPath};
|
||||
use zbus::{interface, zvariant, Connection, ObjectServer, Proxy};
|
||||
|
||||
use steamos_manager_macros::remote;
|
||||
|
||||
use crate::cec::{HdmiCecControl, HdmiCecState};
|
||||
use crate::daemon::user::Command;
|
||||
|
@ -34,6 +40,11 @@ use crate::power::{
|
|||
get_gpu_clocks, get_gpu_clocks_range, get_gpu_performance_level, get_gpu_power_profile,
|
||||
get_max_charge_level, get_platform_profile, TdpManagerCommand,
|
||||
};
|
||||
use crate::proxy::{
|
||||
BatteryChargeLimit1Proxy, FactoryReset1Proxy, FanControl1Proxy, GpuPerformanceLevel1Proxy,
|
||||
GpuPowerProfile1Proxy, PerformanceProfile1Proxy, Storage1Proxy, UpdateBios1Proxy,
|
||||
UpdateDock1Proxy,
|
||||
};
|
||||
use crate::screenreader::{OrcaManager, ScreenReaderAction, ScreenReaderMode};
|
||||
use crate::wifi::{
|
||||
get_wifi_backend, get_wifi_power_management_state, list_wifi_interfaces, WifiBackend,
|
||||
|
@ -102,6 +113,88 @@ macro_rules! setter {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! register_interface {
|
||||
(($self:expr, $name:expr, $object:expr, $bus_name:expr, $connection:expr, $ctxt:expr); $($var:ident: $iface:ident,)*) => {
|
||||
let object_server = $connection.object_server();
|
||||
let object = $object.to_owned();
|
||||
|
||||
match $name {
|
||||
$(_ if $name == <$iface as Interface>::name().as_str() => {
|
||||
if $self.$var.is_some() {
|
||||
return Ok(false);
|
||||
}
|
||||
if object_server
|
||||
.interface::<_, $iface>(MANAGER_PATH)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
if object_server
|
||||
.interface::<_, <$iface as RemoteInterface>::Remote>(MANAGER_PATH)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let remote = <$iface as RemoteInterface>::Remote::new(
|
||||
&$bus_name.to_owned(),
|
||||
object,
|
||||
$connection,
|
||||
)
|
||||
.await?;
|
||||
object_server.at(MANAGER_PATH, remote).await?;
|
||||
let iface = object_server.interface
|
||||
::<_, <$iface as RemoteInterface>::Remote>(MANAGER_PATH).await?;
|
||||
if let Some(interlock) = iface.get_mut().await.interlock.take() {
|
||||
let _ = interlock.send(());
|
||||
}
|
||||
$self.$var = Some(iface);
|
||||
$self.remote_interfaces_changed(&$ctxt).await?;
|
||||
Ok(true)
|
||||
})*
|
||||
_ => {
|
||||
Err(fdo::Error::InvalidArgs(format!(
|
||||
"Unknown interface {}", $name
|
||||
)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! unregister_interface {
|
||||
(($self:expr, $name:expr, $sender:expr, $connection:expr, $ctxt:expr); $($var:ident: $iface:ident,)*) => {
|
||||
let object_server = $connection.object_server();
|
||||
|
||||
match $name {
|
||||
$(_ if $name == <$iface as Interface>::name().as_str() => {
|
||||
let Some(iface) = $self.$var.as_ref() else {
|
||||
return Ok(false);
|
||||
};
|
||||
if let Some(sender) = $sender {
|
||||
let iface = iface.get().await;
|
||||
let remote = iface.remote();
|
||||
if remote != sender {
|
||||
return Err(fdo::Error::AccessDenied(format!(
|
||||
"Interface {} is owned by a different remote", $name
|
||||
)));
|
||||
}
|
||||
}
|
||||
object_server.remove::<$iface, _>(MANAGER_PATH).await?;
|
||||
$self.$var = None;
|
||||
$self.remote_interfaces_changed($ctxt).await?;
|
||||
Ok(true)
|
||||
})*
|
||||
_ => {
|
||||
Err(fdo::Error::InvalidArgs(format!(
|
||||
"Unknown interface {}", $name
|
||||
)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
trait RemoteInterface {
|
||||
type Remote: Interface;
|
||||
}
|
||||
|
@ -161,6 +254,19 @@ struct PerformanceProfile1 {
|
|||
tdp_limit_manager: Option<UnboundedSender<TdpManagerCommand>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct RemoteInterface1 {
|
||||
remote_battery_charge_limit1: Option<InterfaceRef<BatteryChargeLimit1Remote>>,
|
||||
remote_factory_reset1: Option<InterfaceRef<FactoryReset1Remote>>,
|
||||
remote_fan_control1: Option<InterfaceRef<FanControl1Remote>>,
|
||||
remote_gpu_performance_level1: Option<InterfaceRef<GpuPerformanceLevel1Remote>>,
|
||||
remote_gpu_power_profile1: Option<InterfaceRef<GpuPowerProfile1Remote>>,
|
||||
remote_performance_profile1: Option<InterfaceRef<PerformanceProfile1Remote>>,
|
||||
remote_storage1: Option<InterfaceRef<Storage1Remote>>,
|
||||
remote_update_bios1: Option<InterfaceRef<UpdateBios1Remote>>,
|
||||
remote_update_dock1: Option<InterfaceRef<UpdateDock1Remote>>,
|
||||
}
|
||||
|
||||
struct ScreenReader0 {
|
||||
screen_reader: OrcaManager<'static>,
|
||||
}
|
||||
|
@ -274,7 +380,7 @@ impl BatteryChargeLimit1 {
|
|||
const DEFAULT_SUGGESTED_MINIMUM_LIMIT: i32 = 10;
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.BatteryChargeLimit1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.BatteryChargeLimit1")]
|
||||
impl BatteryChargeLimit1 {
|
||||
#[zbus(property)]
|
||||
async fn max_charge_level(&self) -> fdo::Result<i32> {
|
||||
|
@ -326,7 +432,7 @@ impl CpuScaling1 {
|
|||
#[zbus(property)]
|
||||
async fn set_cpu_scaling_governor(
|
||||
&self,
|
||||
governor: String,
|
||||
governor: &str,
|
||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||
) -> zbus::Result<()> {
|
||||
let _: () = self
|
||||
|
@ -337,14 +443,14 @@ impl CpuScaling1 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.FactoryReset1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.FactoryReset1")]
|
||||
impl FactoryReset1 {
|
||||
async fn prepare_factory_reset(&self, flags: u32) -> fdo::Result<u32> {
|
||||
method!(self, "PrepareFactoryReset", flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.FanControl1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.FanControl1")]
|
||||
impl FanControl1 {
|
||||
#[zbus(property)]
|
||||
async fn fan_control_state(&self) -> fdo::Result<u32> {
|
||||
|
@ -362,7 +468,7 @@ impl FanControl1 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.GpuPerformanceLevel1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.GpuPerformanceLevel1")]
|
||||
impl GpuPerformanceLevel1 {
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_gpu_performance_levels(&self) -> fdo::Result<Vec<String>> {
|
||||
|
@ -429,7 +535,7 @@ impl GpuPerformanceLevel1 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.GpuPowerProfile1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.GpuPowerProfile1")]
|
||||
impl GpuPowerProfile1 {
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_gpu_power_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||
|
@ -551,7 +657,7 @@ impl Manager2 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.PerformanceProfile1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.PerformanceProfile1")]
|
||||
impl PerformanceProfile1 {
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_performance_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||
|
@ -594,7 +700,7 @@ impl PerformanceProfile1 {
|
|||
if let Some(manager) = self.tdp_limit_manager.as_ref() {
|
||||
let manager = manager.clone();
|
||||
let _ = manager.send(TdpManagerCommand::UpdateDownloadMode);
|
||||
tokio::spawn(async move {
|
||||
spawn(async move {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
manager.send(TdpManagerCommand::IsActive(tx))?;
|
||||
if rx.await?? {
|
||||
|
@ -628,6 +734,122 @@ impl PerformanceProfile1 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.RemoteInterface1")]
|
||||
impl RemoteInterface1 {
|
||||
async fn register_interface(
|
||||
&mut self,
|
||||
iface: &str,
|
||||
object: ObjectPath<'_>,
|
||||
#[zbus(header)] header: Header<'_>,
|
||||
#[zbus(connection)] connection: &Connection,
|
||||
#[zbus(signal_emitter)] ctxt: SignalEmitter<'_>,
|
||||
) -> fdo::Result<bool> {
|
||||
let Some(sender) = header.sender() else {
|
||||
return Err(fdo::Error::InvalidArgs(String::from("Sender missing")));
|
||||
};
|
||||
let bus_name = BusName::Unique(sender.to_owned());
|
||||
|
||||
self.register_interface_impl(iface, object, &bus_name, connection, &ctxt)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn unregister_interface(
|
||||
&mut self,
|
||||
iface: &str,
|
||||
#[zbus(header)] header: Header<'_>,
|
||||
#[zbus(connection)] connection: &Connection,
|
||||
#[zbus(signal_emitter)] ctxt: SignalEmitter<'_>,
|
||||
) -> fdo::Result<bool> {
|
||||
let sender = header.sender();
|
||||
if sender.is_none() {
|
||||
return Err(fdo::Error::InvalidArgs(String::from("Sender missing")));
|
||||
};
|
||||
|
||||
self.unregister_interface_impl(iface, sender, connection, &ctxt)
|
||||
.await
|
||||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn remote_interfaces(&self) -> Vec<String> {
|
||||
let mut ifaces = Vec::new();
|
||||
if self.remote_battery_charge_limit1.is_some() {
|
||||
ifaces.push(BatteryChargeLimit1::name().to_string());
|
||||
}
|
||||
if self.remote_factory_reset1.is_some() {
|
||||
ifaces.push(FactoryReset1::name().to_string());
|
||||
}
|
||||
if self.remote_fan_control1.is_some() {
|
||||
ifaces.push(FanControl1::name().to_string());
|
||||
}
|
||||
if self.remote_gpu_performance_level1.is_some() {
|
||||
ifaces.push(GpuPerformanceLevel1::name().to_string());
|
||||
}
|
||||
if self.remote_gpu_power_profile1.is_some() {
|
||||
ifaces.push(GpuPowerProfile1::name().to_string());
|
||||
}
|
||||
if self.remote_performance_profile1.is_some() {
|
||||
ifaces.push(PerformanceProfile1::name().to_string());
|
||||
}
|
||||
if self.remote_storage1.is_some() {
|
||||
ifaces.push(Storage1::name().to_string());
|
||||
}
|
||||
if self.remote_update_bios1.is_some() {
|
||||
ifaces.push(UpdateBios1::name().to_string());
|
||||
}
|
||||
if self.remote_update_dock1.is_some() {
|
||||
ifaces.push(UpdateDock1::name().to_string());
|
||||
}
|
||||
ifaces
|
||||
}
|
||||
}
|
||||
|
||||
impl RemoteInterface1 {
|
||||
async fn register_interface_impl(
|
||||
&mut self,
|
||||
iface: &str,
|
||||
object: ObjectPath<'_>,
|
||||
bus_name: &BusName<'_>,
|
||||
connection: &Connection,
|
||||
ctxt: &SignalEmitter<'_>,
|
||||
) -> fdo::Result<bool> {
|
||||
register_interface! {
|
||||
(self, iface, object, bus_name, connection, ctxt);
|
||||
|
||||
remote_battery_charge_limit1: BatteryChargeLimit1,
|
||||
remote_factory_reset1: FactoryReset1,
|
||||
remote_fan_control1: FanControl1,
|
||||
remote_gpu_performance_level1: GpuPerformanceLevel1,
|
||||
remote_gpu_power_profile1: GpuPowerProfile1,
|
||||
remote_performance_profile1: PerformanceProfile1,
|
||||
remote_storage1: Storage1,
|
||||
remote_update_bios1: UpdateBios1,
|
||||
remote_update_dock1: UpdateDock1,
|
||||
}
|
||||
}
|
||||
|
||||
async fn unregister_interface_impl(
|
||||
&mut self,
|
||||
iface: &str,
|
||||
sender: Option<&UniqueName<'_>>,
|
||||
connection: &Connection,
|
||||
ctxt: &SignalEmitter<'_>,
|
||||
) -> fdo::Result<bool> {
|
||||
unregister_interface! {
|
||||
(self, iface, sender, connection, ctxt);
|
||||
|
||||
remote_battery_charge_limit1: BatteryChargeLimit1,
|
||||
remote_factory_reset1: FactoryReset1,
|
||||
remote_fan_control1: FanControl1,
|
||||
remote_gpu_performance_level1: GpuPerformanceLevel1,
|
||||
remote_gpu_power_profile1: GpuPowerProfile1,
|
||||
remote_performance_profile1: PerformanceProfile1,
|
||||
remote_storage1: Storage1,
|
||||
remote_update_bios1: UpdateBios1,
|
||||
remote_update_dock1: UpdateDock1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScreenReader0 {
|
||||
async fn new(connection: &Connection) -> Result<ScreenReader0> {
|
||||
let screen_reader = OrcaManager::new(connection).await?;
|
||||
|
@ -751,7 +973,7 @@ impl ScreenReader0 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.Storage1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.Storage1")]
|
||||
impl Storage1 {
|
||||
async fn format_device(
|
||||
&mut self,
|
||||
|
@ -824,14 +1046,14 @@ impl TdpLimit1 {
|
|||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.UpdateBios1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.UpdateBios1")]
|
||||
impl UpdateBios1 {
|
||||
async fn update_bios(&mut self) -> fdo::Result<zvariant::OwnedObjectPath> {
|
||||
job_method!(self, "UpdateBios")
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "com.steampowered.SteamOSManager1.UpdateDock1")]
|
||||
#[remote(name = "com.steampowered.SteamOSManager1.UpdateDock1")]
|
||||
impl UpdateDock1 {
|
||||
async fn update_dock(&mut self) -> fdo::Result<zvariant::OwnedObjectPath> {
|
||||
job_method!(self, "UpdateDock")
|
||||
|
@ -1053,7 +1275,7 @@ async fn create_device_interfaces(
|
|||
}
|
||||
|
||||
let object_server = object_server.clone();
|
||||
tokio::spawn(async move {
|
||||
spawn(async move {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
manager.send(TdpManagerCommand::IsActive(tx))?;
|
||||
if rx.await?? {
|
||||
|
@ -1114,6 +1336,7 @@ pub(crate) async fn create_interfaces(
|
|||
proxy: proxy.clone(),
|
||||
channel: daemon,
|
||||
};
|
||||
let remote_interface = RemoteInterface1::default();
|
||||
let screen_reader = ScreenReader0::new(&session).await?;
|
||||
let wifi_power_management = WifiPowerManagement1 {
|
||||
proxy: proxy.clone(),
|
||||
|
@ -1168,6 +1391,7 @@ pub(crate) async fn create_interfaces(
|
|||
}
|
||||
|
||||
object_server.at(MANAGER_PATH, manager2).await?;
|
||||
object_server.at(MANAGER_PATH, remote_interface).await?;
|
||||
|
||||
if try_exists(path("/usr/bin/orca")).await? {
|
||||
object_server.at(MANAGER_PATH, screen_reader).await?;
|
||||
|
@ -1196,9 +1420,11 @@ mod test {
|
|||
FormatDeviceConfig, PlatformConfig, ResetConfig, ScriptConfig, ServiceConfig, StorageConfig,
|
||||
};
|
||||
use crate::power::TdpLimitingMethod;
|
||||
use crate::proxy::RemoteInterface1Proxy;
|
||||
use crate::systemd::test::{MockManager, MockUnit};
|
||||
use crate::{path, power, testing};
|
||||
|
||||
use anyhow::{anyhow, ensure};
|
||||
use std::num::NonZeroU32;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::PathBuf;
|
||||
|
@ -1207,10 +1433,9 @@ mod test {
|
|||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
||||
use tokio::time::sleep;
|
||||
use zbus::object_server::Interface;
|
||||
use zbus::Connection;
|
||||
|
||||
struct TestHandle {
|
||||
_handle: testing::TestHandle,
|
||||
handle: testing::TestHandle,
|
||||
connection: Connection,
|
||||
_rx_job: UnboundedReceiver<JobManagerCommand>,
|
||||
rx_tdp: Option<UnboundedReceiver<TdpManagerCommand>>,
|
||||
|
@ -1328,7 +1553,7 @@ mod test {
|
|||
sleep(Duration::from_millis(1)).await;
|
||||
|
||||
Ok(TestHandle {
|
||||
_handle: handle,
|
||||
handle,
|
||||
connection,
|
||||
_rx_job: rx_job,
|
||||
rx_tdp,
|
||||
|
@ -1607,6 +1832,17 @@ mod test {
|
|||
assert!(test_interface_missing::<PerformanceProfile1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_remote_interface1() {
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<RemoteInterface1>(&test.connection)
|
||||
.await
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_storage1() {
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
|
@ -1750,4 +1986,149 @@ mod test {
|
|||
.await
|
||||
.unwrap());
|
||||
}
|
||||
|
||||
async fn test_remote_interface_added<I: RemoteInterface + Interface>(
|
||||
test: &TestHandle,
|
||||
new_conn: &Connection,
|
||||
) -> Result<()> {
|
||||
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||
.destination(
|
||||
test.connection
|
||||
.unique_name()
|
||||
.ok_or(anyhow!("no unique name"))?,
|
||||
)?
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
ensure!(test_remote_interface_missing::<I>(&proxy, test).await?);
|
||||
|
||||
proxy
|
||||
.register_interface(
|
||||
<I as Interface>::name().as_str(),
|
||||
&ObjectPath::try_from("/foo")?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
ensure!(!test_remote_interface_missing::<I>(&proxy, test).await?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn test_remote_interface_missing<I: RemoteInterface + Interface>(
|
||||
proxy: &RemoteInterface1Proxy<'_>,
|
||||
test: &TestHandle,
|
||||
) -> Result<bool> {
|
||||
Ok(!proxy
|
||||
.remote_interfaces()
|
||||
.await?
|
||||
.contains(&<I as Interface>::name().to_string())
|
||||
&& test_interface_missing::<<I as RemoteInterface>::Remote>(&test.connection).await)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_battery_charge_limit1() {
|
||||
let test = start(None, None).await.unwrap();
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||
.destination(test.connection.unique_name().unwrap())
|
||||
.unwrap()
|
||||
.build()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
!test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_battery_charge_limit1_dropped() {
|
||||
let test = start(None, None).await.unwrap();
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
drop(new_conn);
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||
.destination(test.connection.unique_name().unwrap())
|
||||
.unwrap()
|
||||
.build()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_battery_charge_limit1_removed() {
|
||||
let test = start(None, None).await.unwrap();
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||
.destination(test.connection.unique_name().unwrap())
|
||||
.unwrap()
|
||||
.build()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(proxy
|
||||
.unregister_interface(BatteryChargeLimit1::name().as_str())
|
||||
.await
|
||||
.unwrap());
|
||||
|
||||
assert!(
|
||||
test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_battery_charge_limit1_not_removed() {
|
||||
let test = start(None, None).await.unwrap();
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let new_conn = test.handle.new_connection().await.unwrap();
|
||||
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||
.destination(test.connection.unique_name().unwrap())
|
||||
.unwrap()
|
||||
.build()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(proxy
|
||||
.unregister_interface(BatteryChargeLimit1::name().as_str())
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
assert!(
|
||||
!test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,6 +185,14 @@ impl TestHandle {
|
|||
pub async fn dbus_address(&self) -> Option<Address> {
|
||||
(*self.test.dbus_address.lock().await).clone()
|
||||
}
|
||||
|
||||
pub async fn new_connection(&self) -> Result<Connection> {
|
||||
Ok(
|
||||
Builder::address(self.dbus_address().await.ok_or(anyhow!("No address"))?)?
|
||||
.build()
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestHandle {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue