1 // Copyright 2022, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use std::collections::VecDeque; 16 use std::sync::{Arc, Mutex}; 17 use std::time::Duration; 18 19 use async_trait::async_trait; 20 use tokio::sync::{mpsc, Notify}; 21 use tokio::time::timeout; 22 23 use crate::error::{Error, Result}; 24 use crate::params::uci_packets::SessionId; 25 use crate::uci::command::UciCommand; 26 use crate::uci::uci_hal::{UciHal, UciHalPacket}; 27 28 /// The mock implementation of UciHal. 29 #[derive(Default, Clone)] 30 pub struct MockUciHal { 31 packet_sender: Option<mpsc::UnboundedSender<UciHalPacket>>, 32 expected_calls: Arc<Mutex<VecDeque<ExpectedCall>>>, 33 expect_call_consumed: Arc<Notify>, 34 } 35 36 impl MockUciHal { new() -> Self37 pub fn new() -> Self { 38 Default::default() 39 } 40 expected_open(&mut self, packets: Option<Vec<UciHalPacket>>, out: Result<()>)41 pub fn expected_open(&mut self, packets: Option<Vec<UciHalPacket>>, out: Result<()>) { 42 self.expected_calls.lock().unwrap().push_back(ExpectedCall::Open { packets, out }); 43 } 44 expected_close(&mut self, out: Result<()>)45 pub fn expected_close(&mut self, out: Result<()>) { 46 self.expected_calls.lock().unwrap().push_back(ExpectedCall::Close { out }); 47 } 48 expected_send_command( &mut self, expected_cmd: UciCommand, packets: Vec<UciHalPacket>, out: Result<()>, )49 pub fn expected_send_command( 50 &mut self, 51 expected_cmd: UciCommand, 52 packets: Vec<UciHalPacket>, 53 out: Result<()>, 54 ) { 55 self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendCommand { 56 expected_cmd, 57 packets, 58 out, 59 }); 60 } 61 expected_send_packet( &mut self, expected_packet_tx: UciHalPacket, inject_packets_rx: Vec<UciHalPacket>, out: Result<()>, )62 pub fn expected_send_packet( 63 &mut self, 64 expected_packet_tx: UciHalPacket, 65 inject_packets_rx: Vec<UciHalPacket>, 66 out: Result<()>, 67 ) { 68 self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendPacket { 69 expected_packet_tx, 70 inject_packets_rx, 71 out, 72 }); 73 } 74 expected_notify_session_initialized( &mut self, expected_session_id: SessionId, out: Result<()>, )75 pub fn expected_notify_session_initialized( 76 &mut self, 77 expected_session_id: SessionId, 78 out: Result<()>, 79 ) { 80 self.expected_calls 81 .lock() 82 .unwrap() 83 .push_back(ExpectedCall::NotifySessionInitialized { expected_session_id, out }); 84 } 85 wait_expected_calls_done(&mut self) -> bool86 pub async fn wait_expected_calls_done(&mut self) -> bool { 87 while !self.expected_calls.lock().unwrap().is_empty() { 88 if timeout(Duration::from_secs(1), self.expect_call_consumed.notified()).await.is_err() 89 { 90 return false; 91 } 92 } 93 true 94 } 95 } 96 97 #[async_trait] 98 impl UciHal for MockUciHal { open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()>99 async fn open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> { 100 let mut expected_calls = self.expected_calls.lock().unwrap(); 101 match expected_calls.pop_front() { 102 Some(ExpectedCall::Open { packets, out }) => { 103 self.expect_call_consumed.notify_one(); 104 if let Some(packets) = packets { 105 for msg in packets.into_iter() { 106 let _ = packet_sender.send(msg); 107 } 108 } 109 if out.is_ok() { 110 self.packet_sender.replace(packet_sender); 111 } 112 out 113 } 114 Some(call) => { 115 expected_calls.push_front(call); 116 Err(Error::MockUndefined) 117 } 118 None => Err(Error::MockUndefined), 119 } 120 } 121 close(&mut self) -> Result<()>122 async fn close(&mut self) -> Result<()> { 123 let mut expected_calls = self.expected_calls.lock().unwrap(); 124 match expected_calls.pop_front() { 125 Some(ExpectedCall::Close { out }) => { 126 self.expect_call_consumed.notify_one(); 127 if out.is_ok() { 128 self.packet_sender = None; 129 } 130 out 131 } 132 Some(call) => { 133 expected_calls.push_front(call); 134 Err(Error::MockUndefined) 135 } 136 None => Err(Error::MockUndefined), 137 } 138 } 139 send_command(&mut self, cmd: UciCommand) -> Result<()>140 async fn send_command(&mut self, cmd: UciCommand) -> Result<()> { 141 let mut expected_calls = self.expected_calls.lock().unwrap(); 142 match expected_calls.pop_front() { 143 Some(ExpectedCall::SendCommand { expected_cmd, packets, out }) 144 if expected_cmd == cmd => 145 { 146 self.expect_call_consumed.notify_one(); 147 let packet_sender = self.packet_sender.as_mut().unwrap(); 148 for msg in packets.into_iter() { 149 let _ = packet_sender.send(msg); 150 } 151 out 152 } 153 Some(call) => { 154 expected_calls.push_front(call); 155 Err(Error::MockUndefined) 156 } 157 None => Err(Error::MockUndefined), 158 } 159 } 160 send_packet(&mut self, packet_tx: UciHalPacket) -> Result<()>161 async fn send_packet(&mut self, packet_tx: UciHalPacket) -> Result<()> { 162 // send_packet() will be directly called for sending UCI Data packets. 163 let mut expected_calls = self.expected_calls.lock().unwrap(); 164 match expected_calls.pop_front() { 165 Some(ExpectedCall::SendPacket { expected_packet_tx, inject_packets_rx, out }) 166 if expected_packet_tx == packet_tx => 167 { 168 self.expect_call_consumed.notify_one(); 169 let packet_sender = self.packet_sender.as_mut().unwrap(); 170 for msg in inject_packets_rx.into_iter() { 171 let _ = packet_sender.send(msg); 172 } 173 out 174 } 175 Some(call) => { 176 expected_calls.push_front(call); 177 Err(Error::MockUndefined) 178 } 179 None => Err(Error::MockUndefined), 180 } 181 } 182 notify_session_initialized(&mut self, session_id: SessionId) -> Result<()>183 async fn notify_session_initialized(&mut self, session_id: SessionId) -> Result<()> { 184 let mut expected_calls = self.expected_calls.lock().unwrap(); 185 match expected_calls.pop_front() { 186 Some(ExpectedCall::NotifySessionInitialized { expected_session_id, out }) 187 if expected_session_id == session_id => 188 { 189 self.expect_call_consumed.notify_one(); 190 out 191 } 192 Some(call) => { 193 expected_calls.push_front(call); 194 Err(Error::MockUndefined) 195 } 196 None => Err(Error::MockUndefined), 197 } 198 } 199 } 200 201 enum ExpectedCall { 202 Open { 203 packets: Option<Vec<UciHalPacket>>, 204 out: Result<()>, 205 }, 206 Close { 207 out: Result<()>, 208 }, 209 SendCommand { 210 expected_cmd: UciCommand, 211 packets: Vec<UciHalPacket>, 212 out: Result<()>, 213 }, 214 SendPacket { 215 expected_packet_tx: UciHalPacket, 216 inject_packets_rx: Vec<UciHalPacket>, 217 out: Result<()>, 218 }, 219 NotifySessionInitialized { 220 expected_session_id: SessionId, 221 out: Result<()>, 222 }, 223 } 224