From 03648321ecb704b69e47eed7e3df6a779aee8f11 Mon Sep 17 00:00:00 2001 From: laanwj <126646+laanwj@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:24:58 +0200 Subject: [PATCH] util: Add mockable steady_clock This adds a NodeSteadyClock, which is a steady_clock that can be mocked with millisecond precision. --- src/util/time.cpp | 25 +++++++++++++++++++++++++ src/util/time.h | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/util/time.cpp b/src/util/time.cpp index 00f0f473926..cafc27e0d05 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -21,6 +21,7 @@ void UninterruptibleSleep(const std::chrono::microseconds& n) { std::this_thread static std::atomic g_mock_time{}; //!< For testing std::atomic g_used_system_time{false}; +static std::atomic g_mock_steady_time{}; //!< For testing NodeClock::time_point NodeClock::now() noexcept { @@ -48,6 +49,30 @@ std::chrono::seconds GetMockTime() return g_mock_time.load(std::memory_order_relaxed); } +MockableSteadyClock::time_point MockableSteadyClock::now() noexcept +{ + const auto mocktime{g_mock_steady_time.load(std::memory_order_relaxed)}; + if (!mocktime.count()) { + g_used_system_time = true; + } + const auto ret{ + mocktime.count() ? + mocktime : + std::chrono::steady_clock::now().time_since_epoch()}; + return time_point{ret}; +}; + +void MockableSteadyClock::SetMockTime(std::chrono::milliseconds mock_time_in) +{ + Assert(mock_time_in >= 0s); + g_mock_steady_time.store(mock_time_in, std::memory_order_relaxed); +} + +void MockableSteadyClock::ClearMockTime() +{ + g_mock_steady_time.store(0ms, std::memory_order_relaxed); +} + int64_t GetTime() { return GetTime().count(); } std::string FormatISO8601DateTime(int64_t nTime) diff --git a/src/util/time.h b/src/util/time.h index 27cbe50581f..c43b306ff24 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -31,6 +31,31 @@ using SteadyMicroseconds = std::chrono::time_point; + + static constexpr std::chrono::milliseconds INITIAL_MOCK_TIME{1}; + + /** Return current system time or mocked time, if set */ + static time_point now() noexcept; + static std::time_t to_time_t(const time_point&) = delete; // unused + static time_point from_time_t(std::time_t) = delete; // unused + + /** Set mock time for testing. + * When mocking the steady clock, start at INITIAL_MOCK_TIME and add durations to elapse time as necessary + * for testing. + * To stop mocking, call ClearMockTime(). + */ + static void SetMockTime(std::chrono::milliseconds mock_time_in); + + /** Clear mock time, go back to system steady clock. */ + static void ClearMockTime(); +}; + void UninterruptibleSleep(const std::chrono::microseconds& n); /**