1 //! Mocked implementation of GattDatastore for use in test 2 3 use crate::{ 4 gatt::{ 5 callbacks::{GattWriteRequestType, RawGattDatastore, TransactionDecision}, 6 ffi::AttributeBackingType, 7 ids::{AttHandle, TransportIndex}, 8 }, 9 packets::att::AttErrorCode, 10 }; 11 use async_trait::async_trait; 12 use log::info; 13 use tokio::sync::{ 14 mpsc::{self, unbounded_channel, UnboundedReceiver}, 15 oneshot, 16 }; 17 18 /// Routes calls to RawGattDatastore into a channel of MockRawDatastoreEvents 19 pub struct MockRawDatastore(mpsc::UnboundedSender<MockRawDatastoreEvents>); 20 21 impl MockRawDatastore { 22 /// Constructor. Returns self and the RX side of the associated channel. new() -> (Self, UnboundedReceiver<MockRawDatastoreEvents>)23 pub fn new() -> (Self, UnboundedReceiver<MockRawDatastoreEvents>) { 24 let (tx, rx) = unbounded_channel(); 25 (Self(tx), rx) 26 } 27 } 28 29 /// Events representing calls to GattDatastore 30 #[derive(Debug)] 31 pub enum MockRawDatastoreEvents { 32 /// A characteristic was read on a given handle. The oneshot is used to 33 /// return the value read. 34 Read( 35 TransportIndex, 36 AttHandle, 37 AttributeBackingType, 38 u32, 39 oneshot::Sender<Result<Vec<u8>, AttErrorCode>>, 40 ), 41 /// A characteristic was written to on a given handle. The oneshot is used 42 /// to return whether the write succeeded. 43 Write( 44 TransportIndex, 45 AttHandle, 46 AttributeBackingType, 47 GattWriteRequestType, 48 Vec<u8>, 49 oneshot::Sender<Result<(), AttErrorCode>>, 50 ), 51 /// A characteristic was written to on a given handle, where the response was disregarded. 52 WriteNoResponse(TransportIndex, AttHandle, AttributeBackingType, Vec<u8>), 53 /// The prepared writes have been committed / aborted. The oneshot is used 54 /// to return whether this operation succeeded. 55 Execute(TransportIndex, TransactionDecision, oneshot::Sender<Result<(), AttErrorCode>>), 56 } 57 58 #[async_trait(?Send)] 59 impl RawGattDatastore for MockRawDatastore { read( &self, tcb_idx: TransportIndex, handle: AttHandle, offset: u32, attr_type: AttributeBackingType, ) -> Result<Vec<u8>, AttErrorCode>60 async fn read( 61 &self, 62 tcb_idx: TransportIndex, 63 handle: AttHandle, 64 offset: u32, 65 attr_type: AttributeBackingType, 66 ) -> Result<Vec<u8>, AttErrorCode> { 67 let (tx, rx) = oneshot::channel(); 68 self.0.send(MockRawDatastoreEvents::Read(tcb_idx, handle, attr_type, offset, tx)).unwrap(); 69 let resp = rx.await.unwrap(); 70 info!("sending {resp:?} down from upper tester"); 71 resp 72 } 73 write( &self, tcb_idx: TransportIndex, handle: AttHandle, attr_type: AttributeBackingType, write_type: GattWriteRequestType, data: &[u8], ) -> Result<(), AttErrorCode>74 async fn write( 75 &self, 76 tcb_idx: TransportIndex, 77 handle: AttHandle, 78 attr_type: AttributeBackingType, 79 write_type: GattWriteRequestType, 80 data: &[u8], 81 ) -> Result<(), AttErrorCode> { 82 let (tx, rx) = oneshot::channel(); 83 self.0 84 .send(MockRawDatastoreEvents::Write( 85 tcb_idx, 86 handle, 87 attr_type, 88 write_type, 89 data.to_vec(), 90 tx, 91 )) 92 .unwrap(); 93 rx.await.unwrap() 94 } 95 write_no_response( &self, tcb_idx: TransportIndex, handle: AttHandle, attr_type: AttributeBackingType, data: &[u8], )96 fn write_no_response( 97 &self, 98 tcb_idx: TransportIndex, 99 handle: AttHandle, 100 attr_type: AttributeBackingType, 101 data: &[u8], 102 ) { 103 self.0 104 .send(MockRawDatastoreEvents::WriteNoResponse( 105 tcb_idx, 106 handle, 107 attr_type, 108 data.to_vec(), 109 )) 110 .unwrap(); 111 } 112 execute( &self, tcb_idx: TransportIndex, decision: TransactionDecision, ) -> Result<(), AttErrorCode>113 async fn execute( 114 &self, 115 tcb_idx: TransportIndex, 116 decision: TransactionDecision, 117 ) -> Result<(), AttErrorCode> { 118 let (tx, rx) = oneshot::channel(); 119 self.0.send(MockRawDatastoreEvents::Execute(tcb_idx, decision, tx)).unwrap(); 120 rx.await.unwrap() 121 } 122 } 123