Skip to content

Commit 0364832

Browse files
committed
util: Add mockable steady_clock
This adds a NodeSteadyClock, which is a steady_clock that can be mocked with millisecond precision.
1 parent ab1d3ec commit 0364832

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

src/util/time.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread
2121

2222
static std::atomic<std::chrono::seconds> g_mock_time{}; //!< For testing
2323
std::atomic<bool> g_used_system_time{false};
24+
static std::atomic<std::chrono::milliseconds> g_mock_steady_time{}; //!< For testing
2425

2526
NodeClock::time_point NodeClock::now() noexcept
2627
{
@@ -48,6 +49,30 @@ std::chrono::seconds GetMockTime()
4849
return g_mock_time.load(std::memory_order_relaxed);
4950
}
5051

52+
MockableSteadyClock::time_point MockableSteadyClock::now() noexcept
53+
{
54+
const auto mocktime{g_mock_steady_time.load(std::memory_order_relaxed)};
55+
if (!mocktime.count()) {
56+
g_used_system_time = true;
57+
}
58+
const auto ret{
59+
mocktime.count() ?
60+
mocktime :
61+
std::chrono::steady_clock::now().time_since_epoch()};
62+
return time_point{ret};
63+
};
64+
65+
void MockableSteadyClock::SetMockTime(std::chrono::milliseconds mock_time_in)
66+
{
67+
Assert(mock_time_in >= 0s);
68+
g_mock_steady_time.store(mock_time_in, std::memory_order_relaxed);
69+
}
70+
71+
void MockableSteadyClock::ClearMockTime()
72+
{
73+
g_mock_steady_time.store(0ms, std::memory_order_relaxed);
74+
}
75+
5176
int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); }
5277

5378
std::string FormatISO8601DateTime(int64_t nTime)

src/util/time.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,31 @@ using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, st
3131

3232
using SystemClock = std::chrono::system_clock;
3333

34+
/**
35+
* Version of SteadyClock that is mockable in the context of tests (set the
36+
* current value with SetMockTime), otherwise the system steady clock.
37+
*/
38+
struct MockableSteadyClock : public std::chrono::steady_clock {
39+
using time_point = std::chrono::time_point<MockableSteadyClock>;
40+
41+
static constexpr std::chrono::milliseconds INITIAL_MOCK_TIME{1};
42+
43+
/** Return current system time or mocked time, if set */
44+
static time_point now() noexcept;
45+
static std::time_t to_time_t(const time_point&) = delete; // unused
46+
static time_point from_time_t(std::time_t) = delete; // unused
47+
48+
/** Set mock time for testing.
49+
* When mocking the steady clock, start at INITIAL_MOCK_TIME and add durations to elapse time as necessary
50+
* for testing.
51+
* To stop mocking, call ClearMockTime().
52+
*/
53+
static void SetMockTime(std::chrono::milliseconds mock_time_in);
54+
55+
/** Clear mock time, go back to system steady clock. */
56+
static void ClearMockTime();
57+
};
58+
3459
void UninterruptibleSleep(const std::chrono::microseconds& n);
3560

3661
/**

0 commit comments

Comments
 (0)