serial_test/
serial_code_lock.rs

1#![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}