pas_external/pas_port/
memory.rs1#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
9
10use std::collections::VecDeque;
11use std::sync::Mutex;
12
13use super::port::{PasAuthPort, PasFailure};
14use crate::oauth::TokenResponse;
15
16#[derive(Debug)]
17struct RefreshExpect {
18 rt_in: String,
19 returns: Result<TokenResponse, PasFailure>,
20}
21
22#[derive(Debug, Default)]
24pub struct MemoryPasAuth {
25 refresh_script: Mutex<VecDeque<RefreshExpect>>,
26}
27
28impl MemoryPasAuth {
29 #[must_use]
30 pub fn new() -> Self {
31 Self::default()
32 }
33
34 #[must_use]
36 pub fn expect_refresh(
37 self,
38 rt: impl Into<String>,
39 returns: Result<TokenResponse, PasFailure>,
40 ) -> Self {
41 self.refresh_script
42 .lock()
43 .unwrap()
44 .push_back(RefreshExpect { rt_in: rt.into(), returns });
45 self
46 }
47}
48
49impl PasAuthPort for MemoryPasAuth {
50 async fn refresh(&self, rt: &str) -> Result<TokenResponse, PasFailure> {
51 let exp = self
52 .refresh_script
53 .lock()
54 .unwrap()
55 .pop_front()
56 .expect("MemoryPasAuth: refresh called with no expect_refresh queued");
57 assert_eq!(
58 exp.rt_in, rt,
59 "MemoryPasAuth: refresh token mismatch (expected={:?}, actual={:?})",
60 exp.rt_in, rt
61 );
62 exp.returns
63 }
64}
65
66impl Drop for MemoryPasAuth {
67 fn drop(&mut self) {
68 if std::thread::panicking() {
71 return;
72 }
73 let r = self.refresh_script.get_mut().unwrap();
74 if !r.is_empty() {
75 panic!(
76 "MemoryPasAuth dropped with {} unconsumed refresh expectation(s)",
77 r.len()
78 );
79 }
80 }
81}