Skip to content

Commit bd70bc2

Browse files
committed
test(Timer): Stabilize tests
Switch from using system clock for delays to manually advancing clock ticks using multiple threads
1 parent c9ead9e commit bd70bc2

File tree

1 file changed

+54
-49
lines changed

1 file changed

+54
-49
lines changed

src/timer.rs

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -190,120 +190,125 @@ impl<Clock: crate::Clock, Dur: Duration> Timer<Periodic, Running, Clock, Dur> {
190190
}
191191

192192
#[cfg(test)]
193+
#[allow(unused_imports)]
194+
#[allow(unsafe_code)]
193195
mod test {
194-
#![allow(unsafe_code)]
195-
196196
use crate::{units::*, Clock as _, Duration, Instant, Period, TimeInt};
197197
use std::convert::TryFrom;
198+
use std::sync::atomic::{AtomicI64, Ordering};
199+
use std::thread;
198200

199201
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
200202
struct Clock;
201203

202-
static mut START: Option<std::time::Instant> = None;
204+
static TICKS: AtomicI64 = AtomicI64::new(0);
203205

204206
impl crate::Clock for Clock {
205207
type Rep = i64;
206-
const PERIOD: Period = Period::new(1, 64_000_000);
208+
const PERIOD: Period = Period::new(1, 1_000);
207209

208210
fn now() -> Instant<Self> {
209-
let since_start = unsafe { START.unwrap() }.elapsed();
210-
let ticks = Nanoseconds::<i64>::try_from(since_start)
211-
.unwrap()
212-
.into_ticks(Self::PERIOD)
213-
.unwrap();
214-
Instant::new(ticks)
215-
}
216-
}
217-
218-
fn init_start_time() {
219-
unsafe {
220-
START = Some(std::time::Instant::now());
211+
Instant::new(TICKS.load(Ordering::Acquire))
221212
}
222213
}
223214

224215
#[test]
225216
fn oneshot_wait() {
226-
init_start_time();
217+
init_ticks();
227218

228-
// WHEN blocking on a timer
229-
let timer = Clock::new_timer().set_duration(1.seconds()).start().wait();
219+
let timer = Clock::new_timer().set_duration(1.seconds()).start();
220+
let timer_handle = thread::spawn(move || timer.wait());
230221

231-
// THEN the block occurs for _at least_ the given duration
232-
unsafe {
233-
assert!(Seconds::<i32>::try_from(START.unwrap().elapsed()).unwrap() >= 1.seconds());
234-
}
222+
add_to_ticks(1.seconds());
235223

236-
// WHEN blocking on a timer
237-
timer.start().wait();
224+
let result = timer_handle.join();
238225

239-
// THEN the block occurs for _at least_ the given duration
240-
unsafe {
241-
assert!(Seconds::<i32>::try_from(START.unwrap().elapsed()).unwrap() >= 2.seconds());
242-
}
226+
assert!(result.is_ok());
227+
228+
let timer = result.unwrap().start();
229+
let timer_handle = thread::spawn(move || timer.wait());
230+
231+
add_to_ticks(1.seconds());
232+
233+
assert!(timer_handle.join().is_ok());
243234
}
244235

245236
#[test]
246237
fn periodic_wait() {
247-
init_start_time();
238+
init_ticks();
248239

249240
let timer = Clock::new_timer()
250241
.into_periodic()
251242
.set_duration(1.seconds())
252-
.start()
253-
.wait();
243+
.start();
244+
let timer_handle = thread::spawn(move || timer.wait());
254245

255-
unsafe {
256-
assert!(Seconds::<i32>::try_from(START.unwrap().elapsed()).unwrap() == 1.seconds());
257-
}
246+
add_to_ticks(1.seconds());
258247

259-
let timer = timer.wait();
260-
unsafe {
261-
assert!(Seconds::<i32>::try_from(START.unwrap().elapsed()).unwrap() == 2.seconds());
262-
}
248+
let result = timer_handle.join();
263249

264-
timer.wait();
265-
unsafe {
266-
assert!(Seconds::<i32>::try_from(START.unwrap().elapsed()).unwrap() == 3.seconds());
267-
}
250+
assert!(result.is_ok());
251+
252+
let timer = result.unwrap();
253+
254+
// WHEN blocking on a timer
255+
let timer_handle = thread::spawn(move || timer.wait());
256+
257+
add_to_ticks(1.seconds());
258+
259+
assert!(timer_handle.join().is_ok());
268260
}
269261

270262
#[test]
271263
fn periodic_expiration() {
272-
init_start_time();
264+
init_ticks();
273265

274266
let mut timer = Clock::new_timer()
275267
.into_periodic()
276268
.set_duration(1.seconds())
277269
.start();
278270

279-
std::thread::sleep(std::time::Duration::from_secs(2));
271+
add_to_ticks(2.seconds());
280272

281273
assert!(timer.period_complete());
282274
assert!(timer.period_complete());
283275
}
284276

285277
#[test]
286278
fn read_timer() {
287-
init_start_time();
279+
init_ticks();
288280

289281
let timer = Clock::new_timer().set_duration(2.seconds()).start();
290282

283+
add_to_ticks(1.milliseconds());
284+
291285
assert_eq!(timer.elapsed(), 0.seconds());
292286
assert_eq!(timer.remaining(), 1.seconds());
293287

294-
std::thread::sleep(std::time::Duration::from_secs(1));
288+
add_to_ticks(1.seconds());
295289

296290
assert_eq!(timer.elapsed(), 1.seconds());
297291
assert_eq!(timer.remaining(), 0.seconds());
298292

299-
std::thread::sleep(std::time::Duration::from_secs(1));
293+
add_to_ticks(1.seconds());
300294

301295
assert_eq!(timer.elapsed(), 2.seconds());
302296
assert_eq!(timer.remaining(), (0).seconds());
303297

304-
std::thread::sleep(std::time::Duration::from_secs(1));
298+
add_to_ticks(1.seconds());
305299

306300
assert_eq!(timer.elapsed(), 3.seconds());
307301
assert_eq!(timer.remaining(), (-1).seconds());
308302
}
303+
304+
fn init_ticks() {}
305+
306+
fn add_to_ticks<Dur: Duration>(duration: Dur) {
307+
let ticks = TICKS.load(Ordering::Acquire);
308+
let ticks = ticks
309+
+ duration
310+
.into_ticks::<<Clock as crate::Clock>::Rep>(Clock::PERIOD)
311+
.unwrap();
312+
TICKS.store(ticks, Ordering::Release);
313+
}
309314
}

0 commit comments

Comments
 (0)