Skip to main content

gvm_auth/
clock.rs

1// SPDX-FileCopyrightText: 2026 Greenbone AG
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5use std::fmt::Debug;
6use std::sync::Arc;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::time::{SystemTime, UNIX_EPOCH};
9
10pub trait Clock: Send + Sync + 'static + Debug {
11    fn now(&self) -> u64;
12}
13
14#[derive(Debug, Default)]
15pub struct SystemClock;
16
17impl Clock for SystemClock {
18    fn now(&self) -> u64 {
19        SystemTime::now()
20            .duration_since(UNIX_EPOCH)
21            .unwrap_or_default()
22            .as_secs()
23    }
24}
25
26impl<T: Clock> Clock for Arc<T> {
27    fn now(&self) -> u64 {
28        T::now(&**self)
29    }
30}
31
32#[derive(Debug)]
33pub struct ManualClock {
34    now: AtomicU64,
35}
36
37impl ManualClock {
38    pub fn new(init_unix: u64) -> Self {
39        Self {
40            now: AtomicU64::new(init_unix),
41        }
42    }
43
44    pub fn set(&self, unix: u64) {
45        self.now.store(unix, Ordering::Relaxed);
46    }
47
48    pub fn advance(&self, secs: u64) {
49        self.now.fetch_add(secs, Ordering::Relaxed);
50    }
51}
52
53impl Clock for ManualClock {
54    fn now(&self) -> u64 {
55        self.now.load(Ordering::Relaxed)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn manual_clock_new_returns_initial_time() {
65        let c = ManualClock::new(0);
66        assert_eq!(c.now(), 0);
67    }
68
69    #[test]
70    fn manual_clock_set_overwrites_time() {
71        let c = ManualClock::new(10);
72
73        c.set(999);
74        assert_eq!(c.now(), 999);
75
76        c.set(0);
77        assert_eq!(c.now(), 0);
78    }
79
80    #[test]
81    fn manual_clock_advance_increases_time() {
82        let c = ManualClock::new(100);
83
84        c.advance(5);
85        assert_eq!(c.now(), 105);
86
87        c.advance(10);
88        assert_eq!(c.now(), 115);
89    }
90
91    #[test]
92    fn manual_clock_advance_zero_is_noop() {
93        let c = ManualClock::new(42);
94        c.advance(0);
95        assert_eq!(c.now(), 42);
96    }
97
98    #[test]
99    fn system_clock_now_is_non_decreasing() {
100        let c = SystemClock::default();
101
102        let t1 = c.now();
103        let t2 = c.now();
104
105        assert!(t2 >= t1, "expected t2 >= t1, got t1={t1}, t2={t2}");
106    }
107
108    #[test]
109    fn arc_clock_delegates_to_inner_clock() {
110        let c: Arc<ManualClock> = Arc::new(ManualClock::new(7));
111        assert_eq!(c.now(), 7);
112    }
113
114    #[test]
115    fn clock_trait_objects_work_for_manual_clock() {
116        let c: Box<dyn Clock> = Box::new(ManualClock::new(7));
117        assert_eq!(c.now(), 7);
118    }
119}