blob: cc4c50affb32ff3860914d667f3865794733e249 [file] [log] [blame]
// Copyright 2023 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 crate::host_dispatcher::test as hd_test;
use crate::{host_dispatcher, run_receiver_server};
use assert_matches::assert_matches;
use async_helpers::hanging_get::asynchronous as hanging_get;
use fidl::endpoints::{self, Responder};
use fidl_fuchsia_bluetooth_gatt2::Server_Request;
use fidl_fuchsia_bluetooth_host::{HostMarker, HostRequest, HostRequestStream, ReceiverMarker};
use fidl_fuchsia_bluetooth_sys::{HostInfo as FidlHostInfo, TechnologyType};
use fuchsia_async as fasync;
use fuchsia_bluetooth::types::{Address, HostId, HostInfo};
use futures::future::join;
use futures::{FutureExt, StreamExt, TryStreamExt};
use std::collections::{HashMap, HashSet};
use tracing::info;
async fn handle_host_requests(id: HostId, mut stream: HostRequestStream) {
let mut first_state_req = true;
let mut first_peers_req = true;
while let Some(request) = stream.try_next().await.expect("Invalid Host request") {
match request {
HostRequest::WatchState { responder } => {
if first_state_req {
info!("WatchState request");
let id_val = id.0 as u8;
let address = Address::Public([id_val; 6]);
let info = HostInfo {
id,
technology: TechnologyType::DualMode,
active: false,
local_name: None,
discoverable: false,
discovering: false,
addresses: vec![address],
};
assert_matches::assert_matches!(
responder.send(&FidlHostInfo::from(info)),
Ok(())
);
first_state_req = false;
continue;
}
responder.drop_without_shutdown();
}
HostRequest::SetLocalData { .. } => {
info!("SetLocalData request");
}
HostRequest::EnablePrivacy { .. } => {
info!("EnablePrivacy request");
}
HostRequest::EnableBackgroundScan { .. } => {
info!("EnableBackgroundScan request");
}
HostRequest::SetBrEdrSecurityMode { .. } => {
info!("SetBrEdrSecurityMode request");
}
HostRequest::SetLeSecurityMode { .. } => {
info!("SetLeSecurityMode request");
}
HostRequest::SetConnectable { responder, .. } => {
info!("SetConnectable request");
assert_matches::assert_matches!(responder.send(Ok(())), Ok(()));
}
HostRequest::SetLocalName { responder, .. } => {
info!("SetLocalName request");
assert_matches::assert_matches!(responder.send(Ok(())), Ok(()));
}
HostRequest::RequestGatt2Server_ { server, .. } => {
info!("RequestGatt2Server request");
let mut gatt_server = server.into_stream().unwrap();
match gatt_server.next().await {
Some(Ok(Server_Request::PublishService { responder, .. })) => {
info!("PublishService request");
assert_matches::assert_matches!(responder.send(Ok(())), Ok(()));
}
x => panic!("Unexpected GATT server request: {:?}", x),
}
}
HostRequest::WatchPeers { responder, .. } => {
if first_peers_req {
info!("WatchPeers request");
assert_matches::assert_matches!(responder.send(&[], &[]), Ok(()));
first_peers_req = false;
continue;
}
responder.drop_without_shutdown();
}
x => panic!("Unexpected host server request: {:?}", x),
}
}
}
fn host_is_in_dispatcher(id: &HostId, dispatcher: &host_dispatcher::HostDispatcher) -> bool {
dispatcher.get_adapters().iter().map(|i| i.id).collect::<HashSet<_>>().contains(id)
}
#[fuchsia::test]
async fn add_component_succeeds() {
// Create mock host dispatcher
let hd = host_dispatcher::test::make_simple_test_dispatcher();
// Create the receiver server
let (receiver_client, receiver_stream) =
endpoints::create_proxy_and_stream::<ReceiverMarker>().unwrap();
let _receiver_task = fasync::Task::spawn(run_receiver_server(hd.clone(), receiver_stream));
// Mock the host server
let (host_client, host_server) = endpoints::create_request_stream::<HostMarker>().unwrap();
let _run_host_task = fasync::Task::spawn(handle_host_requests(HostId(1), host_server));
// Add a host to dispatcher using host.Receiver API
let add_host_result = receiver_client.add_host(host_client);
assert_matches!(add_host_result, Ok(()));
assert_eq!(hd.active_host().await.expect("No active host").id(), HostId(1));
assert!(host_is_in_dispatcher(&HostId(1), &hd));
}
#[fuchsia::test]
async fn add_multiple_components_succeeds() {
// Create HostDispatcher
let watch_peers_broker = hanging_get::HangingGetBroker::new(
HashMap::new(),
|_, _| true,
hanging_get::DEFAULT_CHANNEL_SIZE,
);
let watch_hosts_broker = hanging_get::HangingGetBroker::new(
Vec::new(),
crate::host_watcher::observe_hosts,
hanging_get::DEFAULT_CHANNEL_SIZE,
);
let hd = hd_test::make_test_dispatcher(
watch_peers_broker.new_publisher(),
watch_peers_broker.new_registrar(),
watch_hosts_broker.new_publisher(),
watch_hosts_broker.new_registrar(),
);
let watchers_fut = join(watch_peers_broker.run(), watch_hosts_broker.run()).map(|_| ());
fasync::Task::spawn(watchers_fut).detach();
// Start HostWatcher client/server
let (host_watcher_proxy, host_watcher_stream) =
fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_bluetooth_sys::HostWatcherMarker>()
.expect("FIDL endpoints");
let host_watcher_fut = crate::host_watcher::run(hd.clone(), host_watcher_stream);
let _host_watcher_task = fasync::Task::spawn(host_watcher_fut);
// Create Receiver client/server
let (receiver_client, receiver_stream) =
endpoints::create_proxy_and_stream::<ReceiverMarker>().unwrap();
let _receiver_task = fasync::Task::spawn(run_receiver_server(hd.clone(), receiver_stream));
// Create mock Host server
let (host_client, host_server) = endpoints::create_request_stream::<HostMarker>().unwrap();
let _run_host_task = fasync::Task::spawn(handle_host_requests(HostId(1), host_server));
// Add a host to dispatcher using host.Receiver API
let add_host_result = receiver_client.add_host(host_client);
assert_matches!(add_host_result, Ok(()));
assert_eq!(hd.active_host().await.expect("No active host").id(), HostId(1));
let mut hosts = host_watcher_proxy.watch().await.expect("Watch timed out");
assert_eq!(hosts.len(), 1);
assert_matches!(hosts[0].active, Some(true));
// Create second mock Host server
let (host_client2, host_server2) = endpoints::create_request_stream::<HostMarker>().unwrap();
let _run_host_task2 = fasync::Task::spawn(handle_host_requests(HostId(2), host_server2));
// Add another host to dispatcher using host.Receiver API
let add_host_result2 = receiver_client.add_host(host_client2);
assert_matches!(add_host_result2, Ok(()));
hosts = host_watcher_proxy.watch().await.expect("Watch timed out");
assert_eq!(hosts.len(), 2);
hosts.sort_by(|a, b| a.id.unwrap().value.cmp(&b.id.unwrap().value));
assert_eq!(hosts[0].id, Some(HostId(1).into()));
assert_eq!(hosts[0].active, Some(true));
assert_eq!(hosts[1].id, Some(HostId(2).into()));
assert_eq!(hosts[1].active, Some(false));
}