use serde_json::Value;
pub const SKEW_SECS: u64 = 60;
pub fn needs_refresh(value: &Value, now: u64) -> bool {
match value.get("std:expires-at").and_then(Value::as_u64) {
Some(expires_at) => expires_at.saturating_sub(SKEW_SECS) <= now,
None => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn a_value_without_an_expiry_is_never_refreshed() {
assert!(!needs_refresh(&json!({"std:access-token": "at"}), 1_000));
}
#[test]
fn expiry_is_compared_with_the_skew_that_covers_the_round_trip() {
let v = json!({"std:access-token": "at", "std:expires-at": 1_000u64});
assert!(!needs_refresh(&v, 1_000 - SKEW_SECS - 1), "plenty of life");
assert!(
needs_refresh(&v, 1_000 - SKEW_SECS),
"inside the skew is close enough: a token still valid when checked \
must still be valid when it arrives"
);
assert!(needs_refresh(&v, 1_000), "at the boundary");
assert!(needs_refresh(&v, 2_000), "long past");
}
#[test]
fn an_expiry_below_the_skew_does_not_wrap_into_the_future() {
let v = json!({"std:access-token": "at", "std:expires-at": 5u64});
assert!(needs_refresh(&v, 10), "an expiry in 1970 is long past");
}
#[test]
fn a_mistyped_expiry_is_not_an_expiry() {
for bad in [json!(1.5), json!("1000"), json!(null)] {
let v = json!({"std:access-token": "at", "std:expires-at": bad});
assert!(!needs_refresh(&v, 10_000), "{bad} is not an expiry");
}
}
}