blob: ce95664fe5e684d3df119d85514f9adb87703f29 [file]
// Copyright 2023 Google LLC
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use bt_common::debug_command::CommandRunner;
use bt_common::debug_command::CommandSet;
use bt_common::gen_commandset;
use bt_gatt::{
client::{PeerService, PeerServiceHandle},
Client,
};
use crate::*;
gen_commandset! {
PacsCmd {
Print = ("print", [], [], "Print the current PACS status"),
}
}
pub struct PacsDebug<T: bt_gatt::GattTypes> {
client: T::Client,
}
impl<T: bt_gatt::GattTypes> PacsDebug<T> {
pub fn new(client: T::Client) -> Self {
Self { client }
}
}
impl<T: bt_gatt::GattTypes> CommandRunner for PacsDebug<T> {
type Set = PacsCmd;
type Error = bt_gatt::types::Error;
type Event = ();
fn run_command(
&self,
_cmd: Self::Set,
_args: Vec<String>,
) -> impl futures::Future<Output = Result<(), Self::Error>> {
async {
// Since there is only one command, Print, we just print
// all the characteristics that are at the remote PACS server.
let handles = self.client.find_service(PACS_UUID).await?;
for handle in handles {
let service = handle.connect().await?;
let chrs = service.discover_characteristics(None).await?;
for chr in chrs {
match chr.uuid {
SourcePac::UUID => {
let source_pac = SourcePac::try_read::<T>(chr, &service).await?;
println!("{source_pac:?}");
}
SinkPac::UUID => {
let sink_pac = SinkPac::try_read::<T>(chr, &service).await?;
println!("{sink_pac:?}");
}
SinkAudioLocations::UUID => {
let locations =
SinkAudioLocations::try_read::<T>(chr, &service).await?;
println!("{locations:?}");
}
SourceAudioLocations::UUID => {
let locations =
SourceAudioLocations::try_read::<T>(chr, &service).await?;
println!("{locations:?}");
}
AvailableAudioContexts::UUID => {
let contexts =
AvailableAudioContexts::try_read::<T>(chr, &service).await?;
println!("{contexts:?}");
}
SupportedAudioContexts::UUID => {
let contexts =
SupportedAudioContexts::try_read::<T>(chr, &service).await?;
println!("{contexts:?}");
}
_x => println!("Unrecognized Chr {}", chr.uuid.recognize()),
}
}
}
Ok::<(), bt_gatt::types::Error>(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use bt_common::debug_command::CliCommand;
use bt_gatt::test_utils::{FakeClient, FakeTypes};
use log::LevelFilter;
fn setup_fake_pacs_debug() -> PacsDebug<FakeTypes> {
PacsDebug::new(FakeClient::new())
}
#[test]
fn verbosity_controls_and_flags() {
let debug = setup_fake_pacs_debug();
log::set_max_level(LevelFilter::Info);
// Verbose with no args displays current verbosity without changing it
let res = futures::executor::block_on(debug.run(CliCommand::Verbose, vec![]));
assert!(res.is_ok());
assert_eq!(log::max_level(), LevelFilter::Info);
// Update verbosity to Debug
let res =
futures::executor::block_on(debug.run(CliCommand::Verbose, vec!["debug".to_string()]));
assert!(res.is_ok());
assert_eq!(log::max_level(), LevelFilter::Debug);
// Update verbosity to Trace
let res =
futures::executor::block_on(debug.run(CliCommand::Verbose, vec!["trace".to_string()]));
assert!(res.is_ok());
assert_eq!(log::max_level(), LevelFilter::Trace);
// Update verbosity to Off
let res =
futures::executor::block_on(debug.run(CliCommand::Verbose, vec!["off".to_string()]));
assert!(res.is_ok());
assert_eq!(log::max_level(), LevelFilter::Off);
// Invalid level does not change verbosity
let res = futures::executor::block_on(
debug.run(CliCommand::Verbose, vec!["invalid_level".to_string()]),
);
assert!(res.is_ok());
assert_eq!(log::max_level(), LevelFilter::Off);
// Reset back to Info for scoped flags testing
log::set_max_level(LevelFilter::Info);
// Executing Print with -v flag:
// 1. debug.run() strips the flag before run_command.
// 2. Temporarily elevates max log level during execution.
// 3. Executes successfully.
let res = futures::executor::block_on(debug.run(PacsCmd::Print, vec!["-v".to_string()]));
assert!(res.is_ok());
// Persistent verbosity remains Info after scoped execution completes
assert_eq!(log::max_level(), LevelFilter::Info);
// Executing Print with -vv flag elevates to Trace
let res = futures::executor::block_on(debug.run(PacsCmd::Print, vec!["-vv".to_string()]));
assert!(res.is_ok());
assert_eq!(log::max_level(), LevelFilter::Info);
}
}