serial_test/
serial_code_lock.rs1#![allow(clippy::await_holding_lock)]
2
3use crate::code_lock::{check_new_key, global_locks};
4
5#[doc(hidden)]
6macro_rules! core_internal {
7 ($names: ident) => {
8 let unlocks: Vec<_> = $names
9 .into_iter()
10 .map(|name| {
11 check_new_key(name);
12 global_locks()
13 .get(name)
14 .expect("key to be set")
15 .get()
16 .clone()
17 })
18 .collect();
19 let _guards: Vec<_> = unlocks.iter().map(|unlock| unlock.lock()).collect();
20 };
21}
22
23#[doc(hidden)]
24pub fn local_serial_core_with_return<E>(
25 names: Vec<&str>,
26 _path: Option<String>,
27 function: fn() -> Result<(), E>,
28) -> Result<(), E> {
29 core_internal!(names);
30 function()
31}
32
33#[doc(hidden)]
34pub fn local_serial_core(names: Vec<&str>, _path: Option<&str>, function: fn()) {
35 core_internal!(names);
36 function();
37}
38
39#[doc(hidden)]
40#[cfg(feature = "async")]
41pub async fn local_async_serial_core_with_return<E>(
42 names: Vec<&str>,
43 _path: Option<&str>,
44 fut: impl std::future::Future<Output = Result<(), E>> + std::marker::Send,
45) -> Result<(), E> {
46 core_internal!(names);
47 fut.await
48}
49
50#[doc(hidden)]
51#[cfg(feature = "async")]
52pub async fn local_async_serial_core(
53 names: Vec<&str>,
54 _path: Option<&str>,
55 fut: impl std::future::Future<Output = ()>,
56) {
57 core_internal!(names);
58 fut.await;
59}
60
61#[cfg(test)]
62#[allow(clippy::print_stdout)]
63mod tests {
64 use super::local_serial_core;
65 use crate::code_lock::{check_new_key, global_locks};
66 use itertools::Itertools;
67 use parking_lot::RwLock;
68 use std::{
69 sync::{Arc, Barrier},
70 thread,
71 time::Duration,
72 };
73
74 #[test]
75 fn test_hammer_check_new_key() {
76 let ptrs = Arc::new(RwLock::new(Vec::new()));
77 let mut threads = Vec::new();
78
79 let count = 100;
80 let barrier = Arc::new(Barrier::new(count));
81
82 for _ in 0..count {
83 let local_locks = global_locks();
84 let local_ptrs = ptrs.clone();
85 let c = barrier.clone();
86 threads.push(thread::spawn(move || {
87 c.wait();
88 check_new_key("foo");
89 {
90 let unlock = local_locks.get("foo").expect("read didn't work");
91 let mutex = unlock.get();
92
93 let mut ptr_guard = local_ptrs
94 .try_write_for(Duration::from_secs(1))
95 .expect("write lock didn't work");
96 ptr_guard.push(mutex.id);
97 }
98
99 c.wait();
100 }));
101 }
102 for thread in threads {
103 thread.join().expect("thread join worked");
104 }
105 let ptrs_read_lock = ptrs
106 .try_read_recursive_for(Duration::from_secs(1))
107 .expect("ptrs read work");
108 assert_eq!(ptrs_read_lock.len(), count);
109 println!("{:?}", ptrs_read_lock);
110 assert_eq!(ptrs_read_lock.iter().unique().count(), 1);
111 }
112
113 #[test]
114 fn unlock_on_assert() {
115 let _ = std::panic::catch_unwind(|| {
116 local_serial_core(vec!["assert"], None, || {
117 assert!(false);
118 })
119 });
120 assert!(!global_locks().get("assert").unwrap().get().is_locked());
121 }
122}