use crate::Result;
use crate::credentials::CacheableResource;
use http::Extensions;
use std::collections::HashMap;
use tokio::time::Instant;
#[derive(Clone, PartialEq)]
pub struct Token {
pub token: String,
pub token_type: String,
pub expires_at: Option<Instant>,
pub metadata: Option<HashMap<String, String>>,
}
impl std::fmt::Debug for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Token")
.field("token", &"[censored]")
.field("token_type", &self.token_type)
.field("expires_at", &self.expires_at)
.field("metadata", &self.metadata)
.finish()
}
}
#[async_trait::async_trait]
pub(crate) trait TokenProvider: std::fmt::Debug + Send + Sync {
async fn token(&self) -> Result<Token>;
}
#[async_trait::async_trait]
pub(crate) trait CachedTokenProvider: std::fmt::Debug + Send + Sync {
async fn token(&self, extensions: Extensions) -> Result<CacheableResource<Token>>;
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use std::time::Duration;
mockall::mock! {
#[derive(Debug)]
pub TokenProvider { }
#[async_trait::async_trait]
impl TokenProvider for TokenProvider {
async fn token(&self) -> Result<Token>;
}
}
#[test]
fn debug() {
let expires_at = Instant::now() + Duration::from_secs(3600);
let metadata =
HashMap::from([("a", "test-only")].map(|(k, v)| (k.to_string(), v.to_string())));
let token = Token {
token: "token-test-only".into(),
token_type: "token-type-test-only".into(),
expires_at: Some(expires_at),
metadata: Some(metadata.clone()),
};
let got = format!("{token:?}");
assert!(!got.contains("token-test-only"), "{got}");
assert!(got.contains("token: \"[censored]\""), "{got}");
assert!(got.contains("token_type: \"token-type-test-only"), "{got}");
assert!(
got.contains(&format!("expires_at: Some({expires_at:?}")),
"{got}"
);
assert!(
got.contains(&format!("metadata: Some({metadata:?}")),
"{got}"
);
}
}