1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //! MockUwbAdaptation 18 19 use crate::adaptation::UwbAdaptation; 20 use crate::error::UwbErr; 21 use crate::uci::uci_hrcv; 22 use crate::uci::HalCallback; 23 use android_hardware_uwb::aidl::android::hardware::uwb::{ 24 UwbEvent::UwbEvent, UwbStatus::UwbStatus, 25 }; 26 use async_trait::async_trait; 27 use log::warn; 28 use std::collections::VecDeque; 29 use std::sync::Mutex as StdMutex; 30 use tokio::sync::mpsc; 31 use uwb_uci_packets::{Packet, UciCommandPacket}; 32 33 type Result<T> = std::result::Result<T, UwbErr>; 34 35 #[cfg(any(test, fuzzing))] 36 enum ExpectedCall { 37 Finalize { 38 expected_exit_status: bool, 39 }, 40 HalOpen { 41 out: Result<()>, 42 }, 43 HalClose { 44 out: Result<()>, 45 }, 46 CoreInitialization { 47 out: Result<()>, 48 }, 49 SessionInitialization { 50 expected_session_id: i32, 51 out: Result<()>, 52 }, 53 SendUciMessage { 54 expected_cmd: UciCommandPacket, 55 rsp: Option<uci_hrcv::UciResponse>, 56 notf: Option<uci_hrcv::UciNotification>, 57 out: Result<()>, 58 }, 59 } 60 61 #[cfg(any(test, fuzzing))] 62 pub struct MockUwbAdaptation { 63 rsp_sender: mpsc::UnboundedSender<HalCallback>, 64 expected_calls: StdMutex<VecDeque<ExpectedCall>>, 65 } 66 67 #[cfg(any(test, fuzzing))] 68 impl MockUwbAdaptation { new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self69 pub fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self { 70 Self { rsp_sender, expected_calls: StdMutex::new(VecDeque::new()) } 71 } 72 expect_finalize(&self, expected_exit_status: bool)73 pub fn expect_finalize(&self, expected_exit_status: bool) { 74 self.expected_calls 75 .lock() 76 .unwrap() 77 .push_back(ExpectedCall::Finalize { expected_exit_status }); 78 } expect_hal_open(&self, out: Result<()>)79 pub fn expect_hal_open(&self, out: Result<()>) { 80 self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalOpen { out }); 81 } expect_hal_close(&self, out: Result<()>)82 pub fn expect_hal_close(&self, out: Result<()>) { 83 self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalClose { out }); 84 } expect_core_initialization(&self, out: Result<()>)85 pub fn expect_core_initialization(&self, out: Result<()>) { 86 self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreInitialization { out }); 87 } expect_session_initialization(&self, expected_session_id: i32, out: Result<()>)88 pub fn expect_session_initialization(&self, expected_session_id: i32, out: Result<()>) { 89 self.expected_calls 90 .lock() 91 .unwrap() 92 .push_back(ExpectedCall::SessionInitialization { expected_session_id, out }); 93 } expect_send_uci_message( &self, expected_cmd: UciCommandPacket, rsp: Option<uci_hrcv::UciResponse>, notf: Option<uci_hrcv::UciNotification>, out: Result<()>, )94 pub fn expect_send_uci_message( 95 &self, 96 expected_cmd: UciCommandPacket, 97 rsp: Option<uci_hrcv::UciResponse>, 98 notf: Option<uci_hrcv::UciNotification>, 99 out: Result<()>, 100 ) { 101 self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendUciMessage { 102 expected_cmd, 103 rsp, 104 notf, 105 out, 106 }); 107 } 108 clear_expected_calls(&self)109 pub fn clear_expected_calls(&self) { 110 self.expected_calls.lock().unwrap().clear(); 111 } 112 send_hal_event(&self, event: UwbEvent, event_status: UwbStatus)113 async fn send_hal_event(&self, event: UwbEvent, event_status: UwbStatus) { 114 self.rsp_sender.send(HalCallback::Event { event, event_status }).unwrap(); 115 } 116 send_uci_response(&self, rsp: uci_hrcv::UciResponse)117 async fn send_uci_response(&self, rsp: uci_hrcv::UciResponse) { 118 self.rsp_sender.send(HalCallback::UciRsp(rsp)).unwrap(); 119 } 120 send_uci_notification(&self, ntf: uci_hrcv::UciNotification)121 async fn send_uci_notification(&self, ntf: uci_hrcv::UciNotification) { 122 self.rsp_sender.send(HalCallback::UciNtf(ntf)).unwrap(); 123 } 124 } 125 126 #[cfg(any(test, fuzzing))] 127 impl Drop for MockUwbAdaptation { drop(&mut self)128 fn drop(&mut self) { 129 assert!(self.expected_calls.lock().unwrap().is_empty()); 130 } 131 } 132 133 #[cfg(any(test, fuzzing))] 134 #[async_trait] 135 impl UwbAdaptation for MockUwbAdaptation { finalize(&mut self, exit_status: bool)136 async fn finalize(&mut self, exit_status: bool) { 137 let mut expected_calls = self.expected_calls.lock().unwrap(); 138 match expected_calls.pop_front() { 139 Some(ExpectedCall::Finalize { expected_exit_status }) 140 if expected_exit_status == exit_status => 141 { 142 return; 143 } 144 Some(call) => { 145 expected_calls.push_front(call); 146 } 147 None => {} 148 } 149 warn!("unpected finalize() called"); 150 } 151 hal_open(&self) -> Result<()>152 async fn hal_open(&self) -> Result<()> { 153 let expected_out = { 154 let mut expected_calls = self.expected_calls.lock().unwrap(); 155 match expected_calls.pop_front() { 156 Some(ExpectedCall::HalOpen { out }) => Some(out), 157 Some(call) => { 158 expected_calls.push_front(call); 159 None 160 } 161 None => None, 162 } 163 }; 164 165 match expected_out { 166 Some(out) => { 167 let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED }; 168 self.send_hal_event(UwbEvent::OPEN_CPLT, status).await; 169 out 170 } 171 None => { 172 warn!("unpected hal_open() called"); 173 Err(UwbErr::Undefined) 174 } 175 } 176 } 177 hal_close(&self) -> Result<()>178 async fn hal_close(&self) -> Result<()> { 179 let expected_out = { 180 let mut expected_calls = self.expected_calls.lock().unwrap(); 181 match expected_calls.pop_front() { 182 Some(ExpectedCall::HalClose { out }) => Some(out), 183 Some(call) => { 184 expected_calls.push_front(call); 185 None 186 } 187 None => None, 188 } 189 }; 190 191 match expected_out { 192 Some(out) => { 193 let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED }; 194 self.send_hal_event(UwbEvent::CLOSE_CPLT, status).await; 195 out 196 } 197 None => { 198 warn!("unpected hal_close() called"); 199 Err(UwbErr::Undefined) 200 } 201 } 202 } 203 core_initialization(&self) -> Result<()>204 async fn core_initialization(&self) -> Result<()> { 205 let expected_out = { 206 let mut expected_calls = self.expected_calls.lock().unwrap(); 207 match expected_calls.pop_front() { 208 Some(ExpectedCall::CoreInitialization { out }) => Some(out), 209 Some(call) => { 210 expected_calls.push_front(call); 211 None 212 } 213 None => None, 214 } 215 }; 216 217 match expected_out { 218 Some(out) => { 219 let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED }; 220 self.send_hal_event(UwbEvent::POST_INIT_CPLT, status).await; 221 out 222 } 223 None => { 224 warn!("unpected core_initialization() called"); 225 Err(UwbErr::Undefined) 226 } 227 } 228 } 229 session_initialization(&self, session_id: i32) -> Result<()>230 async fn session_initialization(&self, session_id: i32) -> Result<()> { 231 let expected_out = { 232 let mut expected_calls = self.expected_calls.lock().unwrap(); 233 match expected_calls.pop_front() { 234 Some(ExpectedCall::SessionInitialization { expected_session_id, out }) 235 if expected_session_id == session_id => 236 { 237 Some(out) 238 } 239 Some(call) => { 240 expected_calls.push_front(call); 241 None 242 } 243 None => None, 244 } 245 }; 246 247 match expected_out { 248 Some(out) => out, 249 None => { 250 warn!("unpected session_initialization() called"); 251 Err(UwbErr::Undefined) 252 } 253 } 254 } 255 send_uci_message(&self, cmd: UciCommandPacket) -> Result<()>256 async fn send_uci_message(&self, cmd: UciCommandPacket) -> Result<()> { 257 let expected_out = { 258 let mut expected_calls = self.expected_calls.lock().unwrap(); 259 match expected_calls.pop_front() { 260 Some(ExpectedCall::SendUciMessage { 261 expected_cmd, 262 rsp, 263 notf, 264 out, 265 // PDL generated packets do not implement PartialEq, so use the raw bytes for comparison. 266 }) if expected_cmd.clone().to_bytes() == cmd.to_bytes() => Some((rsp, notf, out)), 267 Some(call) => { 268 expected_calls.push_front(call); 269 None 270 } 271 None => None, 272 } 273 }; 274 275 match expected_out { 276 Some((rsp, notf, out)) => { 277 if let Some(notf) = notf { 278 self.send_uci_notification(notf).await; 279 } 280 if let Some(rsp) = rsp { 281 self.send_uci_response(rsp).await; 282 } 283 out 284 } 285 None => { 286 warn!("unpected send_uci_message() called"); 287 Err(UwbErr::Undefined) 288 } 289 } 290 } 291 } 292