use std::time::{Duration, Instant};
use super::{AllowProbeResult, ProbeOperation, ProbingResult};
use crate::breaker::ExecutionResult;
#[derive(Debug, Clone)]
pub(crate) struct SingleProbe {
probe_cooldown: Duration,
entered_at: Option<Instant>,
}
impl SingleProbe {
pub fn new(probe_cooldown: Duration) -> Self {
Self {
probe_cooldown,
entered_at: None,
}
}
#[cfg(test)]
pub fn probe_cooldown(&self) -> Duration {
self.probe_cooldown
}
}
impl ProbeOperation for SingleProbe {
fn allow_probe(&mut self, now: Instant) -> AllowProbeResult {
match self.entered_at {
None => {
self.entered_at = Some(now);
AllowProbeResult::Accepted
}
Some(entered_at) if now.saturating_duration_since(entered_at) > self.probe_cooldown => {
self.entered_at = Some(now);
AllowProbeResult::Accepted
}
Some(_) => AllowProbeResult::Rejected,
}
}
fn record(&mut self, result: ExecutionResult, _now: Instant) -> ProbingResult {
match result {
ExecutionResult::Success => ProbingResult::Success,
ExecutionResult::Failure => ProbingResult::Failure,
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn allow_probe_accepts_single_probe() {
let mut probe = SingleProbe::new(Duration::from_secs(5));
let now = Instant::now();
assert_eq!(probe.allow_probe(now), AllowProbeResult::Accepted);
assert_eq!(probe.allow_probe(now), AllowProbeResult::Rejected);
let later = now + Duration::from_secs(3);
assert_eq!(probe.allow_probe(later), AllowProbeResult::Rejected);
let later = now + Duration::from_secs(6);
assert_eq!(probe.allow_probe(later), AllowProbeResult::Accepted);
}
#[test]
fn allow_probe_check_bounds() {
let mut probe = SingleProbe::new(Duration::from_secs(5));
let now = Instant::now();
assert_eq!(probe.allow_probe(now), AllowProbeResult::Accepted);
let later = now + Duration::from_secs(5);
assert_eq!(probe.allow_probe(later), AllowProbeResult::Rejected);
let later = now + Duration::from_secs(5) + Duration::from_micros(1);
assert_eq!(probe.allow_probe(later), AllowProbeResult::Accepted);
}
#[test]
fn record_ensure_correct_result() {
let mut probe = SingleProbe::new(Duration::from_secs(5));
let now = Instant::now();
assert_eq!(probe.record(ExecutionResult::Success, now), ProbingResult::Success);
assert_eq!(probe.record(ExecutionResult::Failure, now), ProbingResult::Failure);
}
}