use crate::door::{
assistant_test_support::{PERSON, Result},
signin::{Door, Issuer, SignedIn, Started},
};
use std::sync::atomic::{AtomicBool, Ordering};
struct Issued(AtomicBool);
impl Issuer for Issued {
fn start(&self) -> std::result::Result<Started, lys_pass::Error> {
Ok(Started {
url: "https://lys.example".into(),
state: "state".into(),
browser: "browser".into(),
verifier: "verifier".into(),
})
}
fn finish(
&self,
_: &str,
_: &str,
_: &str,
_: &Started,
) -> std::result::Result<SignedIn, lys_pass::Error> {
Ok(SignedIn {
token: "person-pass".into(),
holder: PERSON.into(),
expires_at: 0,
refresh: Some("refresh".into()),
})
}
fn refresh(&self, _: &str) -> std::result::Result<SignedIn, lys_pass::Error> {
if self.0.load(Ordering::SeqCst) {
Ok(SignedIn {
token: "renewed".into(),
holder: PERSON.into(),
expires_at: crate::serve::pass::now() + 600,
refresh: Some("refresh".into()),
})
} else {
Err(lys_pass::Error::CannotAsk("fixture transient failure"))
}
}
}
#[test]
fn r3_13_transient_lys_failure_keeps_the_stream_session_retryable() -> Result {
let door = Door::new(Issued(AtomicBool::new(false)));
let now = crate::serve::pass::now();
let begun = door.begin(now)?;
let session = door.callback("code", "state", &begun.browser, now)?;
let error = super::pass(&door, &session, PERSON)
.err()
.ok_or_else(|| anyhow::anyhow!("transient failure ignored"))?;
assert_eq!(
error.code, "lys_unavailable",
"transient failure became sign-out"
);
door.issuer().0.store(true, Ordering::SeqCst);
assert_eq!(
door.pass(&session, now + 1)?,
"renewed",
"transient failure destroyed session"
);
Ok(())
}