| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use { |
| anyhow::{format_err, Error}, |
| fidl::endpoints::RequestStream, |
| fidl_fuchsia_bluetooth_host::{HostControlHandle, HostMarker, HostRequest, HostRequestStream}, |
| fidl_fuchsia_bluetooth_sys::{HostInfo as FidlHostInfo, TechnologyType}, |
| fuchsia_bluetooth::{ |
| inspect::{placeholder_node, Inspectable}, |
| types::{Address, BondingData, HostInfo, Peer, PeerId}, |
| }, |
| futures::{future, join, stream::StreamExt}, |
| parking_lot::RwLock, |
| std::path::PathBuf, |
| std::sync::Arc, |
| }; |
| |
| use crate::{ |
| host_device::{refresh_host_info, HostDevice, HostListener}, |
| test::create_fidl_endpoints, |
| }; |
| |
| // An impl that ignores all events |
| impl HostListener for () { |
| fn on_peer_updated(&mut self, _peer: Peer) {} |
| fn on_peer_removed(&mut self, _id: PeerId) {} |
| type HostBondFut = future::Ready<Result<(), anyhow::Error>>; |
| fn on_new_host_bond(&mut self, _data: BondingData) -> Self::HostBondFut { |
| future::ok(()) |
| } |
| } |
| |
| // Create a HostDevice with a fake channel, set local name and check it is updated |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn host_device_set_local_name() -> Result<(), Error> { |
| let (client, server) = create_fidl_endpoints::<HostMarker>()?; |
| |
| let info = HostInfo { |
| id: fidl_fuchsia_bluetooth::Id { value: 1 }, |
| technology: TechnologyType::DualMode, |
| address: Address::Public([0, 0, 0, 0, 0, 0]), |
| local_name: None, |
| active: false, |
| discoverable: false, |
| discovering: false, |
| }; |
| let host = Arc::new(RwLock::new(HostDevice::new( |
| PathBuf::from("/dev/class/bt-host/test"), |
| client, |
| Inspectable::new(info.clone(), placeholder_node()), |
| ))); |
| let name = "EXPECTED_NAME".to_string(); |
| |
| let info = Arc::new(RwLock::new(info)); |
| let server = Arc::new(RwLock::new(server)); |
| |
| // Assign a name and verify that that it gets written to the bt-host over FIDL. |
| let set_name = host.write().set_name(name.clone()); |
| let expect_fidl = expect_call(server.clone(), |_, e| match e { |
| HostRequest::SetLocalName { local_name, responder } => { |
| info.write().local_name = Some(local_name); |
| responder.send(&mut Ok(()))?; |
| Ok(()) |
| } |
| _ => Err(format_err!("Unexpected!")), |
| }); |
| let (set_name_result, expect_result) = join!(set_name, expect_fidl); |
| let _ = set_name_result.expect("failed to set name"); |
| let _ = expect_result.expect("FIDL result unsatisfied"); |
| |
| let refresh = refresh_host_info(host.clone()); |
| let expect_fidl = expect_call(server.clone(), |_, e| match e { |
| HostRequest::WatchState { responder } => { |
| responder.send(FidlHostInfo::from(info.read().clone()))?; |
| Ok(()) |
| } |
| _ => Err(format_err!("Unexpected!")), |
| }); |
| let (refresh_result, expect_result) = join!(refresh, expect_fidl); |
| let _ = refresh_result.expect("did not receive HostInfo update"); |
| let _ = expect_result.expect("FIDL result unsatisfied"); |
| |
| let host_name = host.read().get_info().local_name.clone(); |
| println!("name: {:?}", host_name); |
| assert!(host_name == Some(name)); |
| Ok(()) |
| } |
| |
| // TODO(39373): Add host.fidl emulation to bt-fidl-mocks and use that instead. |
| async fn expect_call<F>(stream: Arc<RwLock<HostRequestStream>>, f: F) -> Result<(), Error> |
| where |
| F: FnOnce(Arc<HostControlHandle>, HostRequest) -> Result<(), Error>, |
| { |
| let control_handle = Arc::new(stream.read().control_handle()); |
| let mut stream = stream.write(); |
| if let Some(event) = stream.next().await { |
| let event = event?; |
| f(control_handle, event) |
| } else { |
| Err(format_err!("No event received")) |
| } |
| } |