From d3144f7a52608d5295dd5bf8edc4f3d76ae4ad82 Mon Sep 17 00:00:00 2001 From: Miriam Zimmerman Date: Tue, 15 Jan 2019 16:22:07 -0800 Subject: Add FakeClock and FakeTimerFd for use in tests. Together, these allow tests to create a FakeTimerFd that they can trigger at a particular point in the test code, without having to rely on sleep()s or other racy methods. BUG=None TEST=Unit tests for FakeTimerFd + dependent CL. Change-Id: I14381272a6d75bebcdedb0a329a017a2131a3482 Reviewed-on: https://chromium-review.googlesource.com/1413830 Commit-Ready: ChromeOS CL Exonerator Bot Tested-by: Miriam Zimmerman Tested-by: kokoro Reviewed-by: David Tolnay Reviewed-by: Dylan Reid --- sys_util/src/clock.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 sys_util/src/clock.rs (limited to 'sys_util/src/clock.rs') diff --git a/sys_util/src/clock.rs b/sys_util/src/clock.rs new file mode 100644 index 0000000..5f6ce0c --- /dev/null +++ b/sys_util/src/clock.rs @@ -0,0 +1,84 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Utility file to provide a fake clock object representing current time, and a timerfd driven by +// that time. + +use std::time::{Duration, Instant}; +use std::os::unix::io::AsRawFd; +use EventFd; + +#[derive(Debug, Copy, Clone)] +pub struct Clock(Instant); +impl Clock { + pub fn new() -> Self { + Clock(Instant::now()) + } + + pub fn now(&self) -> Self { + Clock(Instant::now()) + } + + pub fn duration_since(&self, earlier: &Self) -> Duration { + self.0.duration_since(earlier.0) + } +} + +const NS_PER_SEC : u64 = 1_000_000_000; +/// A fake clock that can be used in tests to give exact control over the time. +/// For a code example, see the tests in sys_util/src/timerfd.rs. +#[derive(Debug)] +pub struct FakeClock { + ns_since_epoch: u64, + deadlines: Vec<(u64, EventFd)>, +} + +impl FakeClock { + pub fn new() -> Self { + FakeClock { + ns_since_epoch: 1547163599 * NS_PER_SEC, + deadlines: Vec::new(), + } + } + + /// Get the current time, according to this clock. + pub fn now(&self) -> Self { + FakeClock { + ns_since_epoch: self.ns_since_epoch, + deadlines: Vec::new(), + } + } + + /// Get the current time in ns, according to this clock. + pub fn nanos(&self) -> u64 { + self.ns_since_epoch + } + + /// Get the duration since |earlier|, assuming that earlier < self. + pub fn duration_since(&self, earlier: &Self) -> Duration { + let ns_diff = self.ns_since_epoch - earlier.ns_since_epoch; + Duration::new(ns_diff / NS_PER_SEC, (ns_diff % NS_PER_SEC) as u32) + } + + /// Register the event fd for a notification when self's time is |deadline_ns|. + /// Drop any existing events registered to the same raw fd. + pub fn add_event_fd(&mut self, deadline_ns: u64, fd: EventFd) { + self.deadlines.retain(|&(_, ref old_fd)| { + fd.as_raw_fd() != old_fd.as_raw_fd() + }); + self.deadlines.push((deadline_ns, fd)); + } + + pub fn add_ns(&mut self, ns: u64) { + self.ns_since_epoch += ns; + let time = self.ns_since_epoch; + self.deadlines.retain(|&(ns, ref fd)| { + let expired = ns <= time; + if expired { + fd.write(1).unwrap(); + } + !expired + }); + } +} -- cgit 1.4.1