1 //! This module mocks the behavior of le_impl in GD (excluding timers). 2 //! It tracks both the internal state of le_impl, as well as the connect list in the controller. 3 //! It also enforces all (implicit) invariants of le_impl as documented in le_manager.rs, and 4 //! asserts on violation. 5 6 use std::{cell::RefCell, collections::HashSet, fmt::Debug, rc::Rc}; 7 8 use crate::{ 9 connection::{ 10 attempt_manager::ConnectionMode, 11 le_manager::{ 12 ErrorCode, InactiveLeAclManager, LeAclManager, LeAclManagerConnectionCallbacks, 13 }, 14 LeConnection, 15 }, 16 core::address::AddressWithType, 17 }; 18 19 #[derive(Clone)] 20 pub struct MockLeAclManager { 21 active: Rc<RefCell<Option<Rc<MockActiveLeAclManager>>>>, 22 callbacks: Rc<RefCell<Option<Box<dyn LeAclManagerConnectionCallbacks>>>>, 23 } 24 25 impl MockLeAclManager { new() -> Self26 pub fn new() -> Self { 27 Self { active: Rc::new(RefCell::new(None)), callbacks: Rc::new(RefCell::new(None)) } 28 } 29 inner(&self) -> Rc<MockActiveLeAclManager>30 fn inner(&self) -> Rc<MockActiveLeAclManager> { 31 self.active.borrow().as_ref().unwrap().clone() 32 } 33 current_acceptlist(&self) -> HashSet<AddressWithType>34 pub fn current_acceptlist(&self) -> HashSet<AddressWithType> { 35 self.inner().current_acceptlist() 36 } 37 current_connection_mode(&self) -> Option<ConnectionMode>38 pub fn current_connection_mode(&self) -> Option<ConnectionMode> { 39 self.inner().current_connection_mode() 40 } 41 on_le_connect(&self, address: AddressWithType, status: ErrorCode)42 pub fn on_le_connect(&self, address: AddressWithType, status: ErrorCode) { 43 let inner = self.inner(); 44 inner.on_le_connect(address, status); 45 drop(inner); 46 47 if status == ErrorCode::SUCCESS { 48 self.callbacks 49 .borrow() 50 .as_deref() 51 .unwrap() 52 .on_le_connect(address, Ok(LeConnection { remote_address: address })); 53 } else { 54 self.callbacks.borrow().as_deref().unwrap().on_le_connect(address, Err(status)); 55 } 56 } 57 on_le_disconnect(&self, address: AddressWithType)58 pub fn on_le_disconnect(&self, address: AddressWithType) { 59 let inner = self.inner(); 60 inner.on_le_disconnect(address); 61 drop(inner); 62 63 self.callbacks.borrow().as_deref().unwrap().on_disconnect(address); 64 } 65 } 66 67 impl InactiveLeAclManager for MockLeAclManager { 68 type ActiveManager = Rc<MockActiveLeAclManager>; 69 register_callbacks( self, callbacks: impl LeAclManagerConnectionCallbacks + 'static, ) -> Self::ActiveManager70 fn register_callbacks( 71 self, 72 callbacks: impl LeAclManagerConnectionCallbacks + 'static, 73 ) -> Self::ActiveManager { 74 let out = MockActiveLeAclManager::new(); 75 *self.active.borrow_mut() = Some(out.clone()); 76 *self.callbacks.borrow_mut() = Some(Box::new(callbacks)); 77 out 78 } 79 } 80 81 #[derive(Debug)] 82 pub struct MockActiveLeAclManager { 83 state: RefCell<MockLeManagerInternalState>, 84 } 85 86 #[derive(Clone, Debug)] 87 struct MockLeManagerInternalState { 88 direct_connect_list: HashSet<AddressWithType>, 89 background_connect_list: HashSet<AddressWithType>, 90 currently_connected: HashSet<AddressWithType>, 91 } 92 93 impl MockActiveLeAclManager { new() -> Rc<Self>94 pub fn new() -> Rc<Self> { 95 Rc::new(MockActiveLeAclManager { 96 state: RefCell::new(MockLeManagerInternalState { 97 direct_connect_list: HashSet::new(), 98 background_connect_list: HashSet::new(), 99 currently_connected: HashSet::new(), 100 }), 101 }) 102 } 103 current_acceptlist(&self) -> HashSet<AddressWithType>104 pub fn current_acceptlist(&self) -> HashSet<AddressWithType> { 105 let state = self.state.borrow(); 106 &(&state.direct_connect_list | &state.background_connect_list) 107 - (&state.currently_connected) 108 } 109 current_connection_mode(&self) -> Option<ConnectionMode>110 pub fn current_connection_mode(&self) -> Option<ConnectionMode> { 111 let state = self.state.borrow(); 112 113 if !state.direct_connect_list.is_empty() { 114 Some(ConnectionMode::Direct) 115 } else if state 116 .background_connect_list 117 .difference(&state.currently_connected) 118 .next() 119 .is_some() 120 { 121 Some(ConnectionMode::Background) 122 } else { 123 None 124 } 125 } 126 on_le_connect(&self, address: AddressWithType, status: ErrorCode)127 pub fn on_le_connect(&self, address: AddressWithType, status: ErrorCode) { 128 let mut state = self.state.borrow_mut(); 129 state.direct_connect_list.remove(&address); 130 if status == ErrorCode::SUCCESS { 131 let ok = state.currently_connected.insert(address); 132 assert!(ok, "Already connected"); 133 } 134 } 135 on_le_disconnect(&self, address: AddressWithType)136 pub fn on_le_disconnect(&self, address: AddressWithType) { 137 let mut state = self.state.borrow_mut(); 138 let ok = state.currently_connected.remove(&address); 139 assert!(ok, "Not connected"); 140 } 141 } 142 143 impl LeAclManager for Rc<MockActiveLeAclManager> { add_to_direct_list(&self, address: AddressWithType)144 fn add_to_direct_list(&self, address: AddressWithType) { 145 let mut state = self.state.borrow_mut(); 146 assert!( 147 !state.currently_connected.contains(&address), 148 "Must NOT be currently connected to this address" 149 ); 150 let ok = state.direct_connect_list.insert(address); 151 assert!(ok, "Already in direct connect list"); 152 } 153 add_to_background_list(&self, address: AddressWithType)154 fn add_to_background_list(&self, address: AddressWithType) { 155 let mut state = self.state.borrow_mut(); 156 assert!( 157 !state.currently_connected.contains(&address), 158 "Must NOT be currently connected to this address" 159 ); 160 let ok = state.background_connect_list.insert(address); 161 assert!(ok, "Already in background connect list"); 162 } 163 remove_from_all_lists(&self, address: AddressWithType)164 fn remove_from_all_lists(&self, address: AddressWithType) { 165 let mut state = self.state.borrow_mut(); 166 assert!( 167 !state.currently_connected.contains(&address), 168 "Must NOT be currently connected to this address" 169 ); 170 let ok1 = state.direct_connect_list.remove(&address); 171 let ok2 = state.background_connect_list.remove(&address); 172 assert!(ok1 || ok2, "Present in neither direct nor background connect list"); 173 } 174 } 175