Skip to main content

bt_gatt/
test_utils.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use bt_common::core::{Address, AddressType};
6use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
7use futures::future::{ready, Ready};
8use futures::stream::{FusedStream, Stream};
9use parking_lot::Mutex;
10use std::collections::{HashMap, HashSet, VecDeque};
11use std::sync::Arc;
12use std::task::{Poll, Waker};
13
14use bt_common::{PeerId, Uuid};
15
16use crate::central::ScanResult;
17use crate::client::CharacteristicNotification;
18
19use crate::periodic_advertising::{PeriodicAdvertising, SyncReport};
20use crate::pii::GetPeerAddr;
21use crate::server::{
22    self, LocalService, NotificationType, ReadResponder, ServiceDefinition, WriteResponder,
23};
24use crate::{types::*, GattTypes, ServerTypes};
25
26#[derive(Default)]
27struct FakePeerServiceInner {
28    // Notifier that's used to send out notification.
29    notifiers: HashMap<Handle, UnboundedSender<Result<CharacteristicNotification>>>,
30
31    // Characteristics to return when `read_characteristic` and `discover_characteristics` are
32    // called.
33    characteristics: HashMap<Handle, (Characteristic, Vec<u8>)>,
34}
35
36#[derive(Clone)]
37pub struct FakePeerService {
38    inner: Arc<Mutex<FakePeerServiceInner>>,
39}
40
41impl FakePeerService {
42    pub fn new() -> Self {
43        Self { inner: Arc::new(Mutex::new(Default::default())) }
44    }
45
46    // Adds a characteristic so that it can be returned when discover/read method is
47    // called.
48    // Also triggers sending a characteristic value change notification to be sent.
49    pub fn add_characteristic(&mut self, char: Characteristic, value: Vec<u8>) {
50        let mut lock = self.inner.lock();
51        let handle = char.handle;
52        lock.characteristics.insert(handle, (char, value.clone()));
53        if let Some(notifier) = lock.notifiers.get_mut(&handle) {
54            notifier
55                .unbounded_send(Ok(CharacteristicNotification {
56                    handle,
57                    value,
58                    maybe_truncated: false,
59                }))
60                .expect("should succeed");
61        }
62    }
63
64    // Sets expected characteristic value so that it can be used for validation when
65    // write method is called.
66    pub fn expect_characteristic_value(&mut self, handle: &Handle, value: Vec<u8>) {
67        let mut lock = self.inner.lock();
68        let Some(char) = lock.characteristics.get_mut(handle) else {
69            panic!("Can't find characteristic {handle:?} to set expected value");
70        };
71        char.1 = value;
72    }
73
74    /// Sends a notification on the characteristic with the provided `handle`.
75    pub fn notify(&self, handle: &Handle, notification: Result<CharacteristicNotification>) {
76        let mut lock = self.inner.lock();
77        if let Some(notifier) = lock.notifiers.get_mut(handle) {
78            notifier.unbounded_send(notification).expect("can send notification");
79        }
80    }
81
82    /// Removes the notification subscription for the characteristic with the
83    /// provided `handle`.
84    pub fn clear_notifier(&self, handle: &Handle) {
85        let mut lock = self.inner.lock();
86        let _ = lock.notifiers.remove(handle);
87    }
88}
89
90impl crate::client::PeerService<FakeTypes> for FakePeerService {
91    fn discover_characteristics(
92        &self,
93        uuid: Option<Uuid>,
94    ) -> <FakeTypes as GattTypes>::CharacteristicDiscoveryFut {
95        let lock = self.inner.lock();
96        let mut result = Vec::new();
97        for (_handle, (char, _value)) in &lock.characteristics {
98            match uuid {
99                Some(uuid) if uuid == char.uuid => result.push(char.clone()),
100                None => result.push(char.clone()),
101                _ => {}
102            }
103        }
104        ready(Ok(result))
105    }
106
107    fn read_characteristic<'a>(
108        &self,
109        handle: &Handle,
110        _offset: u16,
111        buf: &'a mut [u8],
112    ) -> <FakeTypes as GattTypes>::ReadFut<'a> {
113        let read_characteristics = &(*self.inner.lock()).characteristics;
114        let Some((_, value)) = read_characteristics.get(handle) else {
115            return ready(Err(Error::Gatt(GattError::InvalidHandle)));
116        };
117        buf[..value.len()].copy_from_slice(value.as_slice());
118        ready(Ok((value.len(), false)))
119    }
120
121    // For testing, should call `expect_characteristic_value` with the expected
122    // value.
123    fn write_characteristic<'a>(
124        &self,
125        handle: &Handle,
126        _mode: WriteMode,
127        _offset: u16,
128        buf: &'a [u8],
129    ) -> <FakeTypes as GattTypes>::WriteFut<'a> {
130        let expected_characteristics = &(*self.inner.lock()).characteristics;
131        // The write operation was not expected.
132        let Some((_, expected)) = expected_characteristics.get(handle) else {
133            panic!("Write operation to characteristic {handle:?} was not expected");
134        };
135        // Value written was not expected.
136        if buf.len() != expected.len() || &buf[..expected.len()] != expected.as_slice() {
137            panic!("Value written to characteristic {handle:?} was not expected: {buf:?}");
138        }
139        ready(Ok(()))
140    }
141
142    fn read_descriptor<'a>(
143        &self,
144        _handle: &Handle,
145        _offset: u16,
146        _buf: &'a mut [u8],
147    ) -> <FakeTypes as GattTypes>::ReadFut<'a> {
148        todo!()
149    }
150
151    fn write_descriptor<'a>(
152        &self,
153        _handle: &Handle,
154        _offset: u16,
155        _buf: &'a [u8],
156    ) -> <FakeTypes as GattTypes>::WriteFut<'a> {
157        todo!()
158    }
159
160    fn subscribe(&self, handle: &Handle) -> <FakeTypes as GattTypes>::NotificationStream {
161        let (sender, receiver) = unbounded();
162        (*self.inner.lock()).notifiers.insert(*handle, sender);
163        receiver
164    }
165}
166
167#[derive(Clone)]
168pub struct FakeServiceHandle {
169    pub uuid: Uuid,
170    pub is_primary: bool,
171    pub fake_service: FakePeerService,
172}
173
174impl crate::client::PeerServiceHandle<FakeTypes> for FakeServiceHandle {
175    fn uuid(&self) -> Uuid {
176        self.uuid
177    }
178
179    fn is_primary(&self) -> bool {
180        self.is_primary
181    }
182
183    fn connect(&self) -> <FakeTypes as GattTypes>::ServiceConnectFut {
184        futures::future::ready(Ok(self.fake_service.clone()))
185    }
186}
187
188#[derive(Default)]
189struct FakeClientInner {
190    fake_services: Vec<FakeServiceHandle>,
191}
192
193#[derive(Clone)]
194pub struct FakeClient {
195    inner: Arc<Mutex<FakeClientInner>>,
196}
197
198impl FakeClient {
199    pub fn new() -> Self {
200        FakeClient { inner: Arc::new(Mutex::new(FakeClientInner::default())) }
201    }
202
203    /// Add a fake peer service to this client.
204    pub fn add_service(&mut self, uuid: Uuid, is_primary: bool, fake_service: FakePeerService) {
205        self.inner.lock().fake_services.push(FakeServiceHandle { uuid, is_primary, fake_service });
206    }
207}
208
209impl crate::Client<FakeTypes> for FakeClient {
210    fn peer_id(&self) -> PeerId {
211        todo!()
212    }
213
214    fn find_service(&self, uuid: Uuid) -> <FakeTypes as GattTypes>::FindServicesFut {
215        let fake_services = &self.inner.lock().fake_services;
216        let mut filtered_services = Vec::new();
217        for handle in fake_services {
218            if handle.uuid == uuid {
219                filtered_services.push(handle.clone());
220            }
221        }
222
223        futures::future::ready(Ok(filtered_services))
224    }
225}
226
227#[derive(Default, Debug)]
228struct ScannedResultStreamInner {
229    results: VecDeque<Result<ScanResult>>,
230    waker: Option<Waker>,
231}
232
233#[derive(Clone, Debug, Default)]
234pub struct ScannedResultStreamController(Arc<Mutex<ScannedResultStreamInner>>);
235
236impl ScannedResultStreamController {
237    /// Add a single scanned result item to output from the stream.
238    pub fn add_scanned_result(&self, item: Result<ScanResult>) {
239        let mut lock = self.0.lock();
240        lock.results.push_back(item);
241        if let Some(waker) = lock.waker.take() {
242            waker.wake();
243        }
244    }
245}
246
247#[derive(Debug, Default)]
248pub struct ScannedResultStream {
249    inner: Arc<Mutex<ScannedResultStreamInner>>,
250}
251
252impl ScannedResultStream {
253    /// Creates a new ScannedResultStream.
254    /// Client can get a ScannedResultStreamController using the `controller`
255    /// method.
256    pub fn new() -> Self {
257        Self::default()
258    }
259
260    pub fn controller(&self) -> ScannedResultStreamController {
261        ScannedResultStreamController(self.inner.clone())
262    }
263}
264
265impl FusedStream for ScannedResultStream {
266    fn is_terminated(&self) -> bool {
267        self.inner.lock().results.is_empty()
268    }
269}
270
271impl Stream for ScannedResultStream {
272    type Item = Result<ScanResult>;
273
274    fn poll_next(
275        self: std::pin::Pin<&mut Self>,
276        cx: &mut std::task::Context<'_>,
277    ) -> Poll<Option<Self::Item>> {
278        let mut lock = self.inner.lock();
279        match lock.results.pop_front() {
280            Some(result) => Poll::Ready(Some(result)),
281            None => {
282                lock.waker = Some(cx.waker().clone());
283                Poll::Pending
284            }
285        }
286    }
287}
288
289/// Implements a fake [`GetPeerAddr`] that just converts the peer_id into a
290/// public [`Address`] based on the given peer_id.
291pub struct FakeGetPeerAddr;
292
293impl GetPeerAddr for FakeGetPeerAddr {
294    async fn get_peer_address(&self, peer_id: PeerId) -> Result<(Address, AddressType)> {
295        Ok((
296            [
297                peer_id.0 as u8,
298                ((peer_id.0 >> 8) & 0xff) as u8,
299                ((peer_id.0 >> 16) & 0xff) as u8,
300                ((peer_id.0 >> 24) & 0xff) as u8,
301                ((peer_id.0 >> 32) & 0xff) as u8,
302                ((peer_id.0 >> 48) & 0xff) as u8,
303            ],
304            AddressType::Public,
305        ))
306    }
307}
308
309pub struct FakeTypes {}
310
311impl GattTypes for FakeTypes {
312    type Central = FakeCentral;
313    type ScanResultStream = ScannedResultStream;
314    type Client = FakeClient;
315    type ConnectFuture = Ready<Result<FakeClient>>;
316    type PeerServiceHandle = FakeServiceHandle;
317    type FindServicesFut = Ready<Result<Vec<FakeServiceHandle>>>;
318    type PeerService = FakePeerService;
319    type ServiceConnectFut = Ready<Result<FakePeerService>>;
320    type CharacteristicDiscoveryFut = Ready<Result<Vec<Characteristic>>>;
321    type NotificationStream = UnboundedReceiver<Result<CharacteristicNotification>>;
322    type ReadFut<'a> = Ready<Result<(usize, bool)>>;
323    type WriteFut<'a> = Ready<Result<()>>;
324    type PeriodicAdvertising = FakePeriodicAdvertising;
325}
326
327impl ServerTypes for FakeTypes {
328    type Server = FakeServer;
329    type LocalService = FakeLocalService;
330    type LocalServiceFut = Ready<Result<FakeLocalService>>;
331    type ServiceEventStream = UnboundedReceiver<Result<server::ServiceEvent<FakeTypes>>>;
332    type ServiceWriteType = Vec<u8>;
333    type ReadResponder = FakeResponder;
334    type WriteResponder = FakeResponder;
335    type IndicateConfirmationStream = UnboundedReceiver<Result<server::ConfirmationEvent>>;
336}
337
338#[derive(Default)]
339struct FakePeriodicAdvertisingInner {
340    sync_registry: HashMap<PeerId, UnboundedSender<Result<SyncReport>>>,
341}
342
343#[derive(Clone, Default)]
344pub struct FakePeriodicAdvertising {
345    inner: Arc<Mutex<FakePeriodicAdvertisingInner>>,
346}
347
348impl FakePeriodicAdvertising {
349    pub fn new() -> Self {
350        Self::default()
351    }
352
353    pub fn get_sender(&self, peer_id: PeerId) -> Option<UnboundedSender<Result<SyncReport>>> {
354        self.inner.lock().sync_registry.get(&peer_id).cloned()
355    }
356}
357
358impl PeriodicAdvertising for FakePeriodicAdvertising {
359    type SyncFut = Ready<Result<Self::SyncStream>>;
360    type SyncStream = UnboundedReceiver<Result<SyncReport>>;
361
362    fn sync_to_advertising_reports(
363        &self,
364        peer_id: PeerId,
365        _advertising_sid: u8,
366        _config: crate::periodic_advertising::SyncConfiguration,
367    ) -> Self::SyncFut {
368        let (tx, rx) = unbounded();
369        self.inner.lock().sync_registry.insert(peer_id, tx);
370        ready(Ok(rx))
371    }
372}
373
374#[derive(Default)]
375pub struct FakeCentralInner {
376    clients: HashMap<PeerId, FakeClient>,
377    pub(crate) periodic_advertising: FakePeriodicAdvertising,
378}
379
380#[derive(Clone)]
381pub struct FakeCentral {
382    inner: Arc<Mutex<FakeCentralInner>>,
383}
384
385impl FakeCentral {
386    pub fn new() -> Self {
387        Self { inner: Arc::new(Mutex::new(FakeCentralInner::default())) }
388    }
389
390    pub fn add_client(&mut self, peer_id: PeerId, client: FakeClient) {
391        let _ = self.inner.lock().clients.insert(peer_id, client);
392    }
393}
394
395impl crate::Central<FakeTypes> for FakeCentral {
396    fn scan(&self, _filters: &[crate::central::ScanFilter]) -> ScannedResultStream {
397        ScannedResultStream::default()
398    }
399
400    fn connect(&self, peer_id: PeerId) -> <FakeTypes as GattTypes>::ConnectFuture {
401        let clients = &self.inner.lock().clients;
402        let res = match clients.get(&peer_id) {
403            Some(client) => Ok(client.clone()),
404            None => Err(Error::PeerDisconnected(peer_id)),
405        };
406        futures::future::ready(res)
407    }
408
409    fn periodic_advertising(&self) -> Result<<FakeTypes as GattTypes>::PeriodicAdvertising> {
410        Ok(self.inner.lock().periodic_advertising.clone())
411    }
412}
413
414#[derive(Debug)]
415pub enum FakeServerEvent {
416    ReadResponded {
417        service_id: server::ServiceId,
418        handle: Handle,
419        value: Result<Vec<u8>>,
420    },
421    WriteResponded {
422        service_id: server::ServiceId,
423        handle: Handle,
424        value: Result<()>,
425    },
426    Notified {
427        service_id: server::ServiceId,
428        handle: Handle,
429        value: Vec<u8>,
430        peers: Vec<PeerId>,
431    },
432    Indicated {
433        service_id: server::ServiceId,
434        handle: Handle,
435        value: Vec<u8>,
436        peers: Vec<PeerId>,
437        confirmations: UnboundedSender<Result<server::ConfirmationEvent>>,
438    },
439    Unpublished {
440        id: server::ServiceId,
441    },
442    Published {
443        id: server::ServiceId,
444        definition: ServiceDefinition,
445    },
446}
447
448#[derive(Debug)]
449struct FakeServerInner {
450    services: HashMap<server::ServiceId, ServiceDefinition>,
451    service_senders:
452        HashMap<server::ServiceId, UnboundedSender<Result<server::ServiceEvent<FakeTypes>>>>,
453    sender: UnboundedSender<FakeServerEvent>,
454    notification_peers: HashSet<PeerId>,
455    indication_peers: HashSet<PeerId>,
456    next_prepare_result: Option<Result<()>>,
457}
458
459#[derive(Clone, Debug)]
460pub struct FakeServer {
461    inner: Arc<Mutex<FakeServerInner>>,
462}
463
464impl server::Server<FakeTypes> for FakeServer {
465    fn prepare(
466        &self,
467        service: server::ServiceDefinition,
468    ) -> <FakeTypes as ServerTypes>::LocalServiceFut {
469        let mut lock = self.inner.lock();
470        if let Some(Err(e)) = lock.next_prepare_result.take() {
471            return futures::future::ready(Err(e));
472        }
473        let id = service.id();
474        lock.services.insert(id, service);
475        futures::future::ready(Ok(FakeLocalService::new(id, self.inner.clone())))
476    }
477}
478
479impl FakeServer {
480    pub fn new() -> (Self, UnboundedReceiver<FakeServerEvent>) {
481        let (sender, receiver) = futures::channel::mpsc::unbounded();
482        (
483            Self {
484                inner: Arc::new(Mutex::new(FakeServerInner {
485                    services: Default::default(),
486                    service_senders: Default::default(),
487                    sender,
488                    notification_peers: HashSet::new(),
489                    indication_peers: HashSet::new(),
490                    next_prepare_result: None,
491                })),
492            },
493            receiver,
494        )
495    }
496
497    pub fn set_next_prepare_result(&self, res: Result<()>) {
498        self.inner.lock().next_prepare_result = Some(res);
499    }
500
501    pub fn service(&self, id: server::ServiceId) -> Option<ServiceDefinition> {
502        self.inner.lock().services.get(&id).cloned()
503    }
504
505    pub fn incoming_write(
506        &self,
507        peer_id: PeerId,
508        id: server::ServiceId,
509        handle: Handle,
510        offset: u32,
511        value: Vec<u8>,
512    ) {
513        // TODO: check that the write is allowed
514        let sender = self.inner.lock().sender.clone();
515        self.inner
516            .lock()
517            .service_senders
518            .get(&id)
519            .unwrap()
520            .unbounded_send(Ok(server::ServiceEvent::Write {
521                peer_id,
522                handle,
523                offset,
524                value,
525                responder: FakeResponder { sender, service_id: id, handle },
526            }))
527            .unwrap();
528    }
529
530    pub fn incoming_read(
531        &self,
532        peer_id: PeerId,
533        id: server::ServiceId,
534        handle: Handle,
535        offset: u32,
536    ) {
537        // TODO: check that the read is allowed
538        let sender = self.inner.lock().sender.clone();
539        self.inner
540            .lock()
541            .service_senders
542            .get(&id)
543            .unwrap()
544            .unbounded_send(Ok(server::ServiceEvent::Read {
545                peer_id,
546                handle,
547                offset,
548                responder: FakeResponder { sender, service_id: id, handle },
549            }))
550            .unwrap();
551    }
552
553    pub fn incoming_client_configuration(
554        &self,
555        peer_id: PeerId,
556        id: server::ServiceId,
557        handle: Handle,
558        notification_type: NotificationType,
559    ) {
560        let mut inner = self.inner.lock();
561        match notification_type {
562            NotificationType::Notify => {
563                inner.notification_peers.insert(peer_id);
564            }
565            NotificationType::Indicate => {
566                inner.indication_peers.insert(peer_id);
567            }
568            NotificationType::Disable => {
569                inner.notification_peers.remove(&peer_id);
570                inner.indication_peers.remove(&peer_id);
571            }
572        }
573        inner
574            .service_senders
575            .get(&id)
576            .unwrap()
577            .unbounded_send(Ok(server::ServiceEvent::ClientConfiguration {
578                peer_id,
579                handle,
580                notification_type,
581            }))
582            .unwrap();
583    }
584}
585
586pub struct FakeLocalService {
587    id: server::ServiceId,
588    inner: Arc<Mutex<FakeServerInner>>,
589}
590
591impl FakeLocalService {
592    fn new(id: server::ServiceId, inner: Arc<Mutex<FakeServerInner>>) -> Self {
593        Self { id, inner }
594    }
595}
596
597impl Drop for FakeLocalService {
598    fn drop(&mut self) {
599        self.inner.lock().services.remove(&self.id);
600    }
601}
602
603impl LocalService<FakeTypes> for FakeLocalService {
604    fn publish(&self) -> <FakeTypes as ServerTypes>::ServiceEventStream {
605        let (sender, receiver) = futures::channel::mpsc::unbounded();
606        let _ = self.inner.lock().service_senders.insert(self.id, sender);
607        let definition = self.inner.lock().services.get(&self.id).unwrap().clone();
608        self.inner
609            .lock()
610            .sender
611            .unbounded_send(FakeServerEvent::Published { id: self.id, definition })
612            .unwrap();
613        receiver
614    }
615
616    fn notify(&self, characteristic: &Handle, data: &[u8], peers: &[PeerId]) {
617        let inner = self.inner.lock();
618        let peers_to_notify: HashSet<_> = if peers.is_empty() {
619            inner.notification_peers.clone()
620        } else {
621            peers.iter().filter(|p| inner.notification_peers.contains(p)).cloned().collect()
622        };
623
624        if !peers_to_notify.is_empty() {
625            inner
626                .sender
627                .unbounded_send(FakeServerEvent::Notified {
628                    service_id: self.id,
629                    handle: *characteristic,
630                    value: data.into(),
631                    peers: peers_to_notify.into_iter().collect(),
632                })
633                .unwrap();
634        }
635    }
636
637    fn indicate(
638        &self,
639        characteristic: &Handle,
640        data: &[u8],
641        peers: &[PeerId],
642    ) -> <FakeTypes as ServerTypes>::IndicateConfirmationStream {
643        let (sender, receiver) = futures::channel::mpsc::unbounded();
644        let inner = self.inner.lock();
645        let peers_to_indicate: HashSet<_> = if peers.is_empty() {
646            inner.indication_peers.clone()
647        } else {
648            peers.iter().filter(|p| inner.indication_peers.contains(p)).cloned().collect()
649        };
650
651        if !peers_to_indicate.is_empty() {
652            inner
653                .sender
654                .unbounded_send(FakeServerEvent::Indicated {
655                    service_id: self.id,
656                    handle: *characteristic,
657                    value: data.into(),
658                    peers: peers_to_indicate.into_iter().collect(),
659                    confirmations: sender,
660                })
661                .unwrap();
662        }
663        receiver
664    }
665}
666
667pub struct FakeResponder {
668    sender: UnboundedSender<FakeServerEvent>,
669    service_id: server::ServiceId,
670    handle: Handle,
671}
672
673impl ReadResponder for FakeResponder {
674    fn respond(self, value: &[u8]) {
675        self.sender
676            .unbounded_send(FakeServerEvent::ReadResponded {
677                service_id: self.service_id,
678                handle: self.handle,
679                value: Ok(value.into()),
680            })
681            .unwrap();
682    }
683
684    fn error(self, error: GattError) {
685        self.sender
686            .unbounded_send(FakeServerEvent::ReadResponded {
687                service_id: self.service_id,
688                handle: self.handle,
689                value: Err(Error::Gatt(error)),
690            })
691            .unwrap();
692    }
693}
694
695impl WriteResponder for FakeResponder {
696    fn acknowledge(self) {
697        self.sender
698            .unbounded_send(FakeServerEvent::WriteResponded {
699                service_id: self.service_id,
700                handle: self.handle,
701                value: Ok(()),
702            })
703            .unwrap();
704    }
705
706    fn error(self, error: GattError) {
707        self.sender
708            .unbounded_send(FakeServerEvent::WriteResponded {
709                service_id: self.service_id,
710                handle: self.handle,
711                value: Err(Error::Gatt(error)),
712            })
713            .unwrap();
714    }
715}