1use crate::err::{Action, ErrorSource, Resource};
4use crate::{Error, LockStatus, Result, StateMgr};
5use serde::{Serialize, de::DeserializeOwned};
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex};
8
9#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
14#[derive(Clone, Debug)]
15pub struct TestingStateMgr {
16 inner: Arc<Mutex<TestingStateMgrInner>>,
18}
19
20#[derive(Debug)]
22struct TestingStateMgrInner {
23 lock_held: bool,
26 storage: Arc<Mutex<TestingStateMgrStorage>>,
28}
29
30impl TestingStateMgrInner {
31 fn unlock(&mut self) {
33 if self.lock_held {
34 self.lock_held = false;
35 let mut storage = self.storage.lock().expect("Lock poisoned");
36 storage.lock_available = true;
37 }
38 }
39}
40
41#[derive(Debug)]
45struct TestingStateMgrStorage {
46 lock_available: bool,
48 entries: HashMap<String, String>,
54}
55
56impl Default for TestingStateMgr {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl TestingStateMgr {
63 pub fn new() -> Self {
65 let storage = TestingStateMgrStorage {
66 lock_available: true,
67 entries: HashMap::new(),
68 };
69 let inner = TestingStateMgrInner {
70 lock_held: false,
71 storage: Arc::new(Mutex::new(storage)),
72 };
73 TestingStateMgr {
74 inner: Arc::new(Mutex::new(inner)),
75 }
76 }
77
78 #[must_use]
81 pub fn new_manager(&self) -> Self {
82 let inner = self.inner.lock().expect("Lock poisoned.");
83 let new_inner = TestingStateMgrInner {
84 lock_held: false,
85 storage: Arc::clone(&inner.storage),
86 };
87 TestingStateMgr {
88 inner: Arc::new(Mutex::new(new_inner)),
89 }
90 }
91
92 fn err_resource(&self, key: &str) -> Resource {
94 Resource::Temporary {
95 key: key.to_string(),
96 }
97 }
98}
99
100impl StateMgr for TestingStateMgr {
101 fn load<D>(&self, key: &str) -> Result<Option<D>>
102 where
103 D: DeserializeOwned,
104 {
105 let inner = self.inner.lock().expect("Lock poisoned.");
106 let storage = inner.storage.lock().expect("Lock poisoned.");
107 let content = storage.entries.get(key);
108 match content {
109 Some(value) => {
110 Ok(Some(serde_json::from_str(value).map_err(|e| {
111 Error::new(e, Action::Loading, self.err_resource(key))
112 })?))
113 }
114 None => Ok(None),
115 }
116 }
117
118 fn store<S>(&self, key: &str, val: &S) -> Result<()>
119 where
120 S: Serialize,
121 {
122 let inner = self.inner.lock().expect("Lock poisoned.");
123 if !inner.lock_held {
124 return Err(Error::new(
125 ErrorSource::NoLock,
126 Action::Storing,
127 Resource::Manager,
128 ));
129 }
130 let mut storage = inner.storage.lock().expect("Lock poisoned.");
131
132 let val = serde_json::to_string_pretty(val)
133 .map_err(|e| Error::new(e, Action::Storing, self.err_resource(key)))?;
134
135 storage.entries.insert(key.to_string(), val);
136 Ok(())
137 }
138
139 fn can_store(&self) -> bool {
140 let inner = self.inner.lock().expect("Lock poisoned.");
141
142 inner.lock_held
143 }
144
145 fn try_lock(&self) -> Result<LockStatus> {
146 let mut inner = self.inner.lock().expect("Lock poisoned.");
147 if inner.lock_held {
148 return Ok(LockStatus::AlreadyHeld);
149 }
150
151 let mut storage = inner.storage.lock().expect("Lock poisoned");
152 if storage.lock_available {
153 storage.lock_available = false;
154 drop(storage); inner.lock_held = true;
156 Ok(LockStatus::NewlyAcquired)
157 } else {
158 Ok(LockStatus::NoLock)
159 }
160 }
161
162 fn unlock(&self) -> Result<()> {
163 let mut inner = self.inner.lock().expect("Lock poisoned.");
164 inner.unlock();
165 Ok(())
166 }
167}
168
169impl Drop for TestingStateMgrInner {
170 fn drop(&mut self) {
171 self.unlock();
172 }
173}
174
175#[cfg(test)]
176mod test {
177 #![allow(clippy::bool_assert_comparison)]
179 #![allow(clippy::clone_on_copy)]
180 #![allow(clippy::dbg_macro)]
181 #![allow(clippy::mixed_attributes_style)]
182 #![allow(clippy::print_stderr)]
183 #![allow(clippy::print_stdout)]
184 #![allow(clippy::single_char_pattern)]
185 #![allow(clippy::unwrap_used)]
186 #![allow(clippy::unchecked_time_subtraction)]
187 #![allow(clippy::useless_vec)]
188 #![allow(clippy::needless_pass_by_value)]
189 #![allow(clippy::string_slice)] use super::*;
192 use serde::{Deserialize, Serialize};
193
194 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
195 struct Ex1 {
196 v1: u32,
197 v2: u64,
198 }
199 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
200 struct Ex2 {
201 s1: String,
202 s2: String,
203 }
204 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
205 enum OldEnum {
206 Variant1,
207 }
208 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
209 enum NewEnum {
210 Variant1,
211 Variant2,
212 }
213
214 #[test]
215 fn basic_tests() {
216 let mgr = TestingStateMgr::new();
217 let v1 = Ex1 { v1: 8, v2: 99 };
218 let s1 = Ex2 {
219 s1: "Hello".into(),
220 s2: "World".into(),
221 };
222
223 assert_eq!(mgr.load::<Ex1>("item1").unwrap(), None);
224 assert!(matches!(
225 mgr.store("item1", &v1).unwrap_err().source(),
226 ErrorSource::NoLock
227 ));
228
229 assert!(!mgr.can_store());
230 assert_eq!(mgr.try_lock().unwrap(), LockStatus::NewlyAcquired);
231 assert!(mgr.can_store());
232
233 assert!(mgr.store("item1", &v1).is_ok());
234 assert_eq!(mgr.load::<Ex1>("item1").unwrap(), Some(v1));
235 assert!(mgr.load::<Ex2>("item1").is_err());
236
237 assert!(mgr.store("item2", &s1).is_ok());
238 assert_eq!(mgr.load::<Ex2>("item2").unwrap(), Some(s1));
239 assert!(mgr.load::<Ex1>("item2").is_err());
240
241 let v2 = Ex1 { v1: 10, v2: 12 };
242 assert!(mgr.store("item1", &v2).is_ok());
243 assert_eq!(mgr.load::<Ex1>("item1").unwrap(), Some(v2));
244 }
245
246 #[test]
247 fn lock_blocking() {
248 let mgr = TestingStateMgr::new();
249
250 assert!(!mgr.can_store());
251
252 let mgr2 = mgr.new_manager();
253
254 assert_eq!(mgr.try_lock().unwrap(), LockStatus::NewlyAcquired);
255 assert_eq!(mgr.try_lock().unwrap(), LockStatus::AlreadyHeld);
256 assert!(mgr.can_store());
257
258 assert!(!mgr2.can_store());
259 assert_eq!(mgr2.try_lock().unwrap(), LockStatus::NoLock);
260 assert!(!mgr2.can_store());
261
262 drop(mgr);
263 assert_eq!(mgr2.try_lock().unwrap(), LockStatus::NewlyAcquired);
264 assert!(mgr2.can_store());
265 }
266
267 #[test]
268 fn typesafe_handles() {
269 use crate::DynStorageHandle;
270 let mgr = TestingStateMgr::new();
271
272 let h1: DynStorageHandle<Ex1> = mgr.clone().create_handle("foo");
273 let h2: DynStorageHandle<Ex2> = mgr.clone().create_handle("bar");
274 let h3: DynStorageHandle<Ex2> = mgr.clone().create_handle("baz");
275
276 let v1 = Ex1 { v1: 1, v2: 2 };
277 let s1 = Ex2 {
278 s1: "aaa".into(),
279 s2: "bbb".into(),
280 };
281 let s2 = Ex2 {
282 s1: "jj".into(),
283 s2: "yrfmstbyes".into(),
284 };
285
286 assert!(matches!(
287 h1.store(&v1).unwrap_err().source(),
288 ErrorSource::NoLock
289 ));
290 assert!(mgr.try_lock().unwrap().held());
291 assert!(h1.can_store());
292 assert!(h1.store(&v1).is_ok());
293
294 assert!(h2.can_store());
295 assert!(h2.store(&s1).is_ok());
296 assert!(h3.load().unwrap().is_none());
297 assert!(h3.store(&s2).is_ok());
298
299 assert_eq!(h1.load().unwrap(), Some(v1));
300 assert_eq!(h2.load().unwrap(), Some(s1));
301 assert_eq!(h3.load().unwrap(), Some(s2));
302 }
303
304 #[test]
305 fn futureproof() {
306 use crate::Futureproof;
307
308 let v1 = Ex1 { v1: 8, v2: 99 };
309
310 let v1_ser = serde_json::to_string(&v1).unwrap();
311
312 let v1_as_ex1: Futureproof<Ex1> = serde_json::from_str(&v1_ser).unwrap();
313 let v1_as_ex2: Futureproof<Ex2> = serde_json::from_str(&v1_ser).unwrap();
314 assert!(v1_as_ex1.clone().into_option().is_some());
315 assert!(v1_as_ex2.into_option().is_none());
316
317 assert_eq!(serde_json::to_string(&v1_as_ex1).unwrap(), v1_ser);
318 }
319
320 #[test]
321 fn futureproof_enums() {
322 use crate::Futureproof;
323
324 let new1 = NewEnum::Variant1;
325 let new2 = NewEnum::Variant2;
326
327 let new1_ser = serde_json::to_string(&new1).unwrap();
328 let new2_ser = serde_json::to_string(&new2).unwrap();
329
330 let old1: Futureproof<OldEnum> = serde_json::from_str(&new1_ser).unwrap();
331 let old2: Futureproof<OldEnum> = serde_json::from_str(&new2_ser).unwrap();
332
333 assert!(old1.into_option().is_some());
334 assert!(old2.into_option().is_none());
335 }
336}