From 2a7d9c8ddd08bcc205eec223a0f35730271de072 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 4 Nov 2021 13:58:11 -0500 Subject: [PATCH] Add SinceEpoch time to test Scorer hermetically In order to test Scorer hermetically, sleeps must be avoided. Add a SinceEpoch abstraction for manually advancing time. Implement the Time trait for SinceEpoch so that it can be used with ScorerUsingTime in tests. --- lightning/src/routing/scorer.rs | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/lightning/src/routing/scorer.rs b/lightning/src/routing/scorer.rs index 8b5fae70a..9df3fbec8 100644 --- a/lightning/src/routing/scorer.rs +++ b/lightning/src/routing/scorer.rs @@ -247,6 +247,7 @@ impl Time for std::time::Instant { } /// A state in which time has no meaning. +#[derive(Debug, PartialEq, Eq)] pub struct Eternity; impl Time for Eternity { @@ -320,3 +321,77 @@ impl Readable for ChannelFailure { }) } } + +#[cfg(test)] +mod tests { + use super::{Eternity, ScoringParameters, ScorerUsingTime, Time}; + + use routing::Score; + use routing::network_graph::NodeId; + + use bitcoin::secp256k1::PublicKey; + use core::cell::Cell; + use core::ops::Sub; + use core::time::Duration; + + /// Time that can be advanced manually in tests. + #[derive(Debug, PartialEq, Eq)] + struct SinceEpoch(Duration); + + impl SinceEpoch { + thread_local! { + static ELAPSED: Cell = core::cell::Cell::new(Duration::from_secs(0)); + } + + fn advance(duration: Duration) { + Self::ELAPSED.with(|elapsed| elapsed.set(elapsed.get() + duration)) + } + } + + impl Time for SinceEpoch { + fn now() -> Self { + Self(Self::duration_since_epoch()) + } + + fn duration_since_epoch() -> Duration { + Self::ELAPSED.with(|elapsed| elapsed.get()) + } + + fn elapsed(&self) -> Duration { + Self::duration_since_epoch() - self.0 + } + } + + impl Sub for SinceEpoch { + type Output = Self; + + fn sub(self, other: Duration) -> Self { + Self(self.0 - other) + } + } + + #[test] + fn time_passes_when_advanced() { + let now = SinceEpoch::now(); + assert_eq!(now.elapsed(), Duration::from_secs(0)); + + SinceEpoch::advance(Duration::from_secs(1)); + SinceEpoch::advance(Duration::from_secs(1)); + + let elapsed = now.elapsed(); + let later = SinceEpoch::now(); + + assert_eq!(elapsed, Duration::from_secs(2)); + assert_eq!(later - elapsed, now); + } + + #[test] + fn time_never_passes_in_an_eternity() { + let now = Eternity::now(); + let elapsed = now.elapsed(); + let later = Eternity::now(); + + assert_eq!(now.elapsed(), Duration::from_secs(0)); + assert_eq!(later - elapsed, now); + } +} -- 2.39.5