1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use std::{
borrow::BorrowMut,
mem,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{sleep, spawn},
time::Duration,
};
use crossbeam_channel::{bounded, Receiver, Sender};
use parking_lot::Mutex;
use crate::{Installer, Status, ThreadStatuses};
const WAIT_TIME: Duration = Duration::from_millis(100);
#[derive(Debug)]
pub struct MockNotifier<'notifier> {
threadable_statuses: &'notifier ThreadStatuses,
}
impl<'notifier> MockNotifier<'notifier> {
#[inline]
#[must_use]
pub const fn new(threadable_statuses: &'notifier ThreadStatuses) -> Self {
Self { threadable_statuses }
}
#[inline]
pub fn register_thread(&mut self, thread_name: &str, status: Status) {
self.threadable_statuses.register_thread(thread_name, status);
}
}
#[derive(Clone, Debug)]
pub struct ThreadableTester {
receiver: Receiver<(String, Status)>,
sender: Sender<(String, Status)>,
statuses: Arc<Mutex<Vec<Status>>>,
ended: Arc<AtomicBool>,
}
impl ThreadableTester {
#[inline]
#[must_use]
pub fn new() -> Self {
let (sender, receiver) = bounded(0);
Self {
receiver,
sender,
statuses: Arc::new(Mutex::new(vec![Status::New])),
ended: Arc::new(AtomicBool::new(true)),
}
}
#[inline]
#[must_use]
pub fn take_statuses(&self) -> Vec<Status> {
mem::take(self.statuses.lock().borrow_mut())
}
#[inline]
pub fn start_threadable<Threadable: crate::Threadable>(&self, theadable: &Threadable, thread_name: &str) {
self.ended.store(false, Ordering::Release);
let installer = Installer::new(self.sender.clone());
theadable.install(&installer);
let mut ops = installer.into_ops();
let op = ops.remove(thread_name).expect("Expected to find thead");
let statuses = Arc::clone(&self.statuses);
let receiver = self.receiver.clone();
let _status_thread_id = spawn(move || {
for (_, status) in &receiver {
let mut statuses_lock = statuses.lock();
let last_status = statuses_lock.last().expect("Last status always exists");
if !matches!(*last_status, Status::Error(_)) && last_status != &status {
statuses_lock.push(status);
}
}
});
let _op_id = spawn(op);
self.ended.store(true, Ordering::Release);
}
#[inline]
pub fn wait_for_status(&self, status: &Status) {
let mut attempt = 0;
loop {
let statuses_lock = self.statuses.lock();
let current_status = statuses_lock.last().expect("Expected to lock");
if current_status == status {
break;
}
assert!(
attempt <= 100,
"Timeout waited for status change to '{:?}' on thread.\n Status is: {:?}",
status,
current_status,
);
sleep(WAIT_TIME);
attempt += 1;
}
}
#[inline]
pub fn wait_for_finished(&self) {
let mut attempt = 0;
loop {
if self.ended.load(Ordering::Acquire) {
break;
}
sleep(WAIT_TIME);
attempt += 1;
assert!(attempt <= 100, "Timeout waited for thread to finish");
}
}
}