1use {
8 crate::{Mode, MINIMUM_SIGNATURE_INTERVAL_NANOS},
9 fuchsia_triage::SnapshotTrigger,
10 injectable_time::TimeSource,
11 log::warn,
12 std::collections::HashMap,
13 std::sync::Arc,
14};
15
16pub struct DelayTracker {
17 last_sent: HashMap<String, i64>,
18 time_source: Arc<dyn TimeSource + Send + Sync>,
19 program_mode: Mode,
20}
21
22impl DelayTracker {
23 pub(crate) fn new(
24 time_source: Arc<dyn TimeSource + Send + Sync>,
25 program_mode: Mode,
26 ) -> DelayTracker {
27 DelayTracker { last_sent: HashMap::new(), time_source, program_mode }
28 }
29
30 fn appropriate_report_interval(&self, desired_interval: i64) -> i64 {
31 if self.program_mode == Mode::IntegrationTest
32 || desired_interval >= MINIMUM_SIGNATURE_INTERVAL_NANOS
33 {
34 desired_interval
35 } else {
36 MINIMUM_SIGNATURE_INTERVAL_NANOS
37 }
38 }
39
40 pub(crate) fn ok_to_send(&mut self, snapshot: &SnapshotTrigger) -> bool {
42 let now = self.time_source.now();
43 let interval = self.appropriate_report_interval(snapshot.interval);
44 let should_send = match self.last_sent.get(&snapshot.signature) {
45 None => true,
46 Some(time) => time <= &(now - interval),
47 };
48 if should_send {
49 self.last_sent.insert(snapshot.signature.to_string(), now);
50 if snapshot.interval < MINIMUM_SIGNATURE_INTERVAL_NANOS {
51 warn!(
55 "Signature {} has interval {} nanos, less than minimum {}",
56 snapshot.signature, snapshot.interval, MINIMUM_SIGNATURE_INTERVAL_NANOS
57 );
58 }
59 }
60 should_send
61 }
62}
63
64#[cfg(test)]
65mod test {
66 use super::*;
67 use injectable_time::FakeTime;
68 use static_assertions::const_assert;
69
70 #[fuchsia::test]
71 fn verify_test_mode() {
72 let time = Arc::new(FakeTime::new());
73 let mut tracker = DelayTracker::new(time.clone(), Mode::IntegrationTest);
74 time.set_ticks(1);
75 let trigger_slow = SnapshotTrigger { signature: "slow".to_string(), interval: 10 };
76 let trigger_fast = SnapshotTrigger { signature: "fast".to_string(), interval: 1 };
77 let ok_slow_1 = tracker.ok_to_send(&trigger_slow);
78 let ok_fast_1 = tracker.ok_to_send(&trigger_fast);
79 time.set_ticks(3);
80 let ok_slow_2 = tracker.ok_to_send(&trigger_slow);
81 let ok_fast_2 = tracker.ok_to_send(&trigger_fast);
82 assert!(ok_slow_1);
84 assert!(ok_fast_1);
86 assert!(!ok_slow_2);
88 assert!(ok_fast_2);
90 }
91
92 #[fuchsia::test]
93 fn verify_appropriate_report_interval() {
94 const_assert!(MINIMUM_SIGNATURE_INTERVAL_NANOS > 1);
95 let time = Arc::new(FakeTime::new());
96 let test_tracker = DelayTracker::new(time.clone(), Mode::IntegrationTest);
97 let production_tracker = DelayTracker::new(time, Mode::Production);
98
99 assert_eq!(test_tracker.appropriate_report_interval(1), 1);
100 assert_eq!(
101 production_tracker.appropriate_report_interval(1),
102 MINIMUM_SIGNATURE_INTERVAL_NANOS
103 );
104 }
105}