agent_tui/daemon/
sleeper.rs1use std::sync::Mutex;
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::thread;
10use std::time::Duration;
11
12pub trait Sleeper: Send + Sync {
17 fn sleep(&self, duration: Duration);
19}
20
21#[derive(Debug, Clone, Copy, Default)]
23pub struct RealSleeper;
24
25impl Sleeper for RealSleeper {
26 fn sleep(&self, duration: Duration) {
27 thread::sleep(duration);
28 }
29}
30
31#[derive(Debug, Default)]
38pub struct MockSleeper {
39 call_count: AtomicU64,
40 total_duration_ms: AtomicU64,
41 durations: Mutex<Vec<Duration>>,
42}
43
44impl MockSleeper {
45 pub fn new() -> Self {
47 Self::default()
48 }
49
50 pub fn call_count(&self) -> u64 {
52 self.call_count.load(Ordering::SeqCst)
53 }
54
55 pub fn total_duration(&self) -> Duration {
57 Duration::from_millis(self.total_duration_ms.load(Ordering::SeqCst))
58 }
59
60 pub fn durations(&self) -> Vec<Duration> {
62 self.durations.lock().unwrap().clone()
63 }
64
65 pub fn reset(&self) {
67 self.call_count.store(0, Ordering::SeqCst);
68 self.total_duration_ms.store(0, Ordering::SeqCst);
69 self.durations.lock().unwrap().clear();
70 }
71}
72
73impl Sleeper for MockSleeper {
74 fn sleep(&self, duration: Duration) {
75 self.call_count.fetch_add(1, Ordering::SeqCst);
76 self.total_duration_ms
77 .fetch_add(duration.as_millis() as u64, Ordering::SeqCst);
78 self.durations.lock().unwrap().push(duration);
79 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_real_sleeper_sleeps() {
89 let sleeper = RealSleeper;
90 let start = std::time::Instant::now();
91 sleeper.sleep(Duration::from_millis(10));
92 let elapsed = start.elapsed();
93 assert!(elapsed >= Duration::from_millis(5));
95 }
96
97 #[test]
98 fn test_mock_sleeper_does_not_sleep() {
99 let sleeper = MockSleeper::new();
100 let start = std::time::Instant::now();
101 sleeper.sleep(Duration::from_millis(1000));
102 let elapsed = start.elapsed();
103 assert!(elapsed < Duration::from_millis(5));
105 }
106
107 #[test]
108 fn test_mock_sleeper_tracks_call_count() {
109 let sleeper = MockSleeper::new();
110
111 sleeper.sleep(Duration::from_millis(10));
112 sleeper.sleep(Duration::from_millis(20));
113 sleeper.sleep(Duration::from_millis(30));
114
115 assert_eq!(sleeper.call_count(), 3);
116 }
117
118 #[test]
119 fn test_mock_sleeper_tracks_total_duration() {
120 let sleeper = MockSleeper::new();
121
122 sleeper.sleep(Duration::from_millis(10));
123 sleeper.sleep(Duration::from_millis(20));
124 sleeper.sleep(Duration::from_millis(30));
125
126 assert_eq!(sleeper.total_duration(), Duration::from_millis(60));
127 }
128
129 #[test]
130 fn test_mock_sleeper_tracks_individual_durations() {
131 let sleeper = MockSleeper::new();
132
133 sleeper.sleep(Duration::from_millis(10));
134 sleeper.sleep(Duration::from_millis(20));
135 sleeper.sleep(Duration::from_millis(30));
136
137 let durations = sleeper.durations();
138 assert_eq!(durations.len(), 3);
139 assert_eq!(durations[0], Duration::from_millis(10));
140 assert_eq!(durations[1], Duration::from_millis(20));
141 assert_eq!(durations[2], Duration::from_millis(30));
142 }
143
144 #[test]
145 fn test_mock_sleeper_reset() {
146 let sleeper = MockSleeper::new();
147
148 sleeper.sleep(Duration::from_millis(100));
149 assert_eq!(sleeper.call_count(), 1);
150
151 sleeper.reset();
152
153 assert_eq!(sleeper.call_count(), 0);
154 assert_eq!(sleeper.total_duration(), Duration::ZERO);
155 assert!(sleeper.durations().is_empty());
156 }
157}