| // 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:?}"), |
| }; |
| } |