use std::sync::mpsc::{Receiver, channel};
use std::sync::{Arc, Mutex, PoisonError};
use std::time::{Duration, Instant};
use lys_pass::{Error, KeySet};
use super::tests::{ISSUER, NOW, keys, pass, role};
use super::{Gate, LYS_KEYS_PENDING, Unreachable};
type TestResult = Result<(), Box<dyn std::error::Error>>;
const ARRIVAL: Duration = Duration::from_secs(20);
fn answering(answers: Receiver<Result<KeySet, Error>>) -> impl Fn() -> Result<KeySet, Error> {
let answers = Mutex::new(answers);
move || {
answers
.lock()
.unwrap_or_else(PoisonError::into_inner)
.recv()
.unwrap_or(Err(Error::CannotAsk("the test sends no more answers")))
}
}
#[test]
fn every_decided_act_is_refused_as_pending_until_the_keys_arrive_and_decided_after() -> TestResult {
let (send, answers) = channel();
let gate = Gate::fetching(answering(answers), ISSUER, "wards", Arc::new(Unreachable))?;
let reader = pass("reader", &role(&["read"], "reader-grant"));
let pending = gate
.present(&reader, NOW)
.err()
.ok_or("a pass was verified before any keys were read")?;
assert_eq!(pending.code, LYS_KEYS_PENDING);
send.send(Err(Error::CannotAsk("Lys is not answering yet")))?;
send.send(Ok(keys()?))?;
let started = Instant::now();
let presented = loop {
match gate.present(&reader, NOW) {
Ok(presented) => break presented,
Err(failure) if failure.code == LYS_KEYS_PENDING && started.elapsed() < ARRIVAL => {
std::thread::sleep(Duration::from_millis(10));
}
Err(failure) => return Err(format!("refused as {}", failure.code).into()),
}
};
assert_eq!(presented["holder"], "reader");
Ok(())
}