use std::net::TcpListener;
use std::sync::mpsc::channel;
use std::time::Duration;
use super::{LysConfig, lys_gate};
use crate::serve::pass::LYS_KEYS_PENDING;
type TestResult = Result<(), Box<dyn std::error::Error>>;
fn closed_origin() -> Result<String, std::io::Error> {
let listener = TcpListener::bind("127.0.0.1:0")?;
let port = listener.local_addr()?.port();
drop(listener);
Ok(format!("http://127.0.0.1:{port}/"))
}
#[test]
fn the_lys_section_names_its_issuer_and_database_and_nothing_else() -> TestResult {
let config: LysConfig =
serde_json::from_str(r#"{"issuer": "https://lys.example", "database": "wards"}"#)?;
assert_eq!(
(config.issuer.as_str(), config.database.as_str()),
("https://lys.example", "wards")
);
assert!(
serde_json::from_str::<LysConfig>(
r#"{"issuer": "https://lys.example", "database": "wards", "writer": "everyone"}"#
)
.is_err(),
"a member granting anything was accepted"
);
Ok(())
}
#[test]
fn a_lys_that_cannot_be_asked_at_start_leaves_every_decided_act_refused_by_name() -> TestResult {
let config = LysConfig {
issuer: closed_origin()?,
database: "wards".to_owned(),
placement_credential_file: None,
};
let gate = lys_gate(&config)?;
let refused = gate
.present("a-pass", 0)
.err()
.ok_or("a pass was verified with no published keys")?;
assert_eq!(refused.code, LYS_KEYS_PENDING);
Ok(())
}
#[test]
fn start_does_not_wait_on_a_lys_that_never_answers() -> TestResult {
let silent = TcpListener::bind("127.0.0.1:0")?;
let config = LysConfig {
issuer: format!("http://{}/", silent.local_addr()?),
database: "wards".to_owned(),
placement_credential_file: None,
};
let (made, gate) = channel();
std::thread::spawn(move || drop(made.send(lys_gate(&config).map(drop))));
gate.recv_timeout(Duration::from_secs(5))
.map_err(|_| "the gate waited on a Lys that never answers")??;
drop(silent);
Ok(())
}
#[test]
fn a_database_id_that_is_empty_or_placed_is_refused_before_lys_is_asked() -> TestResult {
for database in ["", "wards/patients", "wards.patients"] {
let config = LysConfig {
issuer: closed_origin()?,
database: database.to_owned(),
placement_credential_file: None,
};
let refused = lys_gate(&config)
.err()
.ok_or("an invalid database id was served")?;
assert!(
refused.starts_with("lys database id"),
"{database:?} refused as {refused}"
);
}
Ok(())
}