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