blob: 7dd7a308865d01310b81810f996f63e13eccbfb2 [file]
// Copyright 2024 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 bt_common::{PeerId, Uuid};
use bt_gatt::test_utils::{FakeServer, FakeServerEvent, FakeTypes};
use bt_gatt::types::Handle;
use futures::channel::mpsc::UnboundedReceiver;
use futures::{Stream, StreamExt};
use std::pin::Pin;
use std::task::{Context, Poll};
use crate::server::AudioStreamControlServiceServer;
use crate::server::ServiceEvent;
use crate::server::{ASCS_SERVICE_ID, ASCS_UUID};
use crate::*;
#[track_caller]
fn expect_service_event(events: &mut UnboundedReceiver<FakeServerEvent>) -> FakeServerEvent {
match events.poll_next_unpin(&mut futures_test::task::noop_context()) {
Poll::Ready(Some(event)) => event,
x => panic!("Expected fake server event, got {x:?}"),
}
}
#[test]
fn publishes() {
let mut ascs_server = std::pin::pin!(AudioStreamControlServiceServer::<FakeTypes>::new(1, 1));
let (count_waker, woken_count) = futures_test::task::new_count_waker();
// Polling the server before it's published should result in Poll::Pending
let poll_result = ascs_server.as_mut().poll_next(&mut Context::from_waker(&count_waker));
assert!(poll_result.is_pending());
assert_eq!(woken_count.get(), 0);
let (fake_server, mut events) = FakeServer::new();
let result = ascs_server.publish(&fake_server);
assert!(result.is_ok());
let already_published = ascs_server.publish(&fake_server);
assert!(already_published.is_err());
assert_eq!(woken_count.get(), 1);
let poll_result = ascs_server.poll_next(&mut Context::from_waker(&count_waker));
match expect_service_event(&mut events) {
FakeServerEvent::Published { id: _, definition } => {
assert_eq!(definition.uuid(), ASCS_UUID);
assert_eq!(
definition.characteristics().filter(|c| c.uuid == Uuid::from_u16(0x2BC4)).count(),
1
);
assert_eq!(
definition.characteristics().filter(|c| c.uuid == Uuid::from_u16(0x2BC5)).count(),
1
);
}
x => panic!("Expected published event, got {x:?}"),
};
// Should still be pending, even though we had some work to do.
assert!(poll_result.is_pending());
}
fn register_for_notification(fake_server: &mut FakeServer, peer_id: PeerId, handle: Handle) {
fake_server.incoming_client_configuration(
peer_id,
ASCS_SERVICE_ID,
handle,
bt_gatt::server::NotificationType::Notify,
);
}
// A published server with one sink and one source.
fn published_server() -> (
Pin<Box<AudioStreamControlServiceServer<FakeTypes>>>,
FakeServer,
UnboundedReceiver<FakeServerEvent>,
) {
let mut ascs_server = Box::pin(AudioStreamControlServiceServer::<FakeTypes>::new(1, 1));
let (mut fake_server, mut events) = FakeServer::new();
let result = ascs_server.publish(&fake_server);
assert!(result.is_ok());
assert!(ascs_server.poll_next_unpin(&mut futures_test::task::noop_context()).is_pending());
assert!(matches!(expect_service_event(&mut events), FakeServerEvent::Published { .. }));
for peer_id in [PeerId(1), PeerId(2)] {
for handle in [Handle(1), Handle(2), Handle(3)] {
register_for_notification(&mut fake_server, peer_id, handle);
}
}
(ascs_server, fake_server, events)
}
fn poll_server(
server: &mut Pin<Box<AudioStreamControlServiceServer<FakeTypes>>>,
) -> Poll<Option<core::result::Result<ServiceEvent, Error>>> {
server.poll_next_unpin(&mut futures_test::task::noop_context())
}
#[test]
fn peers_are_separated() {
let (mut ascs_server, fake_server, mut server_events) = published_server();
// Read the sink uuid
fake_server.incoming_read(PeerId(1), ASCS_SERVICE_ID, Handle(3), 0);
// Poll the ascs server, should not result in an ASCS event
assert!(poll_server(&mut ascs_server).is_pending());
// Should have the response
let mut peer_one_value;
match server_events.poll_next_unpin(&mut futures_test::task::noop_context()) {
Poll::Ready(Some(FakeServerEvent::ReadResponded { service_id, handle: _, value })) => {
assert_eq!(service_id, ASCS_SERVICE_ID);
peer_one_value = value.unwrap();
}
x => panic!("Expected the read to be responded to got {x:?}"),
};
let ase_id = peer_one_value[0];
// Codec Configure the first peer ase_id
fake_server.incoming_write(
PeerId(1),
ASCS_SERVICE_ID,
Handle(1),
0,
vec![0x01, 0x01, ase_id, 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00],
);
use crate::server::ServiceEvent;
use crate::types::*;
// Should have a codec configure event to respond to
match poll_server(&mut ascs_server) {
Poll::Ready(Some(Ok(ServiceEvent::CodecConfigure { responder, .. }))) => {
responder.accept(
Framing::Unframed,
vec![Phy::Le1MPhy],
5,
std::time::Duration::from_millis(20).try_into().unwrap(),
PresentationDelayRange::build(0, 500).unwrap(),
);
}
x => panic!("Expected a CodecConfigure, got {x:?}"),
};
// Expect the write to be responded to / acknowledged and a notification from
// the CP handle and the Source ASE
match expect_service_event(&mut server_events) {
FakeServerEvent::WriteResponded { value, .. } => assert!(value.is_ok()),
x => panic!("Expected acknowledge of write, got {x:?}"),
};
assert!(poll_server(&mut ascs_server).is_pending());
match expect_service_event(&mut server_events) {
FakeServerEvent::Notified { handle, .. } => assert_eq!(Handle(1), handle),
x => panic!("Expected acknowledge of write, got {x:?}"),
};
match expect_service_event(&mut server_events) {
FakeServerEvent::Notified { peers, handle, value, .. } => {
assert!(peers.contains(&PeerId(1)));
assert_eq!(Handle(3), handle);
// Should be the same ASE_ID
assert_eq!(value[0], ase_id);
assert_eq!(value[1], 0x01); // State is CodecConfigured
peer_one_value = value;
}
x => panic!("Expected acknowledge of write, got {x:?}"),
};
// Read the sink id from another peer
fake_server.incoming_read(PeerId(2), ASCS_SERVICE_ID, Handle(3), 0);
assert!(poll_server(&mut ascs_server).is_pending());
assert!(poll_server(&mut ascs_server).is_pending());
let peer_two_value;
match expect_service_event(&mut server_events) {
FakeServerEvent::ReadResponded { service_id, handle: _, value } => {
assert_eq!(service_id, ASCS_SERVICE_ID);
peer_two_value = value.unwrap();
}
x => panic!("Expected the read to be responded to got {x:?}"),
};
assert!(peer_one_value[1] != peer_two_value[1]);
}
#[test]
fn invalid_operation() {
let (mut ascs_server, fake_server, mut server_events) = published_server();
// Read the sink uuid
fake_server.incoming_read(PeerId(1), ASCS_SERVICE_ID, Handle(3), 0);
// Poll the ascs server, should not result in an ASCS event
assert!(poll_server(&mut ascs_server).is_pending());
// Should have the response
let sink_value;
match server_events.poll_next_unpin(&mut futures_test::task::noop_context()) {
Poll::Ready(Some(FakeServerEvent::ReadResponded { service_id, handle: _, value })) => {
assert_eq!(service_id, ASCS_SERVICE_ID);
sink_value = value.unwrap();
}
x => panic!("Expected the read to be responded to got {x:?}"),
};
let ase_id = sink_value[0];
// Write an operation that is unknown.
fake_server.incoming_write(
PeerId(1),
ASCS_SERVICE_ID,
Handle(1),
0,
vec![0x1f, 0x01, ase_id, 0xC0, 0xDE],
);
// Should have nothing to respond to
match poll_server(&mut ascs_server) {
Poll::Pending => {}
x => panic!("Expected to still be pending, got {x:?}"),
};
// Expect the write to be responded to / acknowledged and a notification from
// the CP handle and the Source ASE
match expect_service_event(&mut server_events) {
FakeServerEvent::WriteResponded { value, .. } => assert!(value.is_ok()),
x => panic!("Expected acknowledge of write, got {x:?}"),
};
assert!(poll_server(&mut ascs_server).is_pending());
match expect_service_event(&mut server_events) {
FakeServerEvent::Notified { handle, value, peers, .. } => {
assert!(peers.contains(&PeerId(1)));
assert_eq!(Handle(1), handle);
// Opcode should match
// Number_of_ASEs should be 0xFF (Table 4.7)
// ASE_ID is 0x00, and Reason should be 0x00
assert_eq!(value, &[0x1f, 0xFF, 0x00, 0x01, 0x00]);
}
x => panic!("Expected acknowledge of write, got {x:?}"),
};
}
#[test]
fn invalid_length() {
let (mut ascs_server, fake_server, mut server_events) = published_server();
// Read the sink uuid
fake_server.incoming_read(PeerId(1), ASCS_SERVICE_ID, Handle(3), 0);
// Poll the ascs server, should not result in an ASCS event
assert!(poll_server(&mut ascs_server).is_pending());
// Should have the response
let sink_value;
match server_events.poll_next_unpin(&mut futures_test::task::noop_context()) {
Poll::Ready(Some(FakeServerEvent::ReadResponded { service_id, handle: _, value })) => {
assert_eq!(service_id, ASCS_SERVICE_ID);
sink_value = value.unwrap();
}
x => panic!("Expected the read to be responded to got {x:?}"),
};
let ase_id = sink_value[0];
// Write an operation that is the wrong length (too short)
fake_server.incoming_write(
PeerId(1),
ASCS_SERVICE_ID,
Handle(1),
0,
vec![0x01, 0x01, ase_id, 0xC0, 0xDE],
);
// Should have nothing to respond to
match poll_server(&mut ascs_server) {
Poll::Pending => {}
x => panic!("Expected to still be pending, got {x:?}"),
};
// Expect the write to be responded to / acknowledged and a notification from
// the CP handle and the Source ASE
match expect_service_event(&mut server_events) {
FakeServerEvent::WriteResponded { value, .. } => assert!(value.is_ok()),
x => panic!("Expected acknowledge of write, got {x:?}"),
};
assert!(poll_server(&mut ascs_server).is_pending());
match expect_service_event(&mut server_events) {
FakeServerEvent::Notified { handle, value, peers, .. } => {
assert!(peers.contains(&PeerId(1)));
assert_eq!(Handle(1), handle);
// Opcode should match
// Number_of_ASEs should be 0xFF (Table 4.7)
// ASE_ID is 0x00, and Reason should be 0x00
assert_eq!(value, &[0x01, 0xFF, 0x00, 0x02, 0x00]);
}
x => panic!("Expected acknowledge of write, got {x:?}"),
};
}