use super::*;
#[test]
fn present_non_empty_auth_token_passes_validation() -> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
config.auth = Some(AuthConfig {
pass: None,
token: "s3cr3t".to_owned(),
require_verified_worker: false,
lys: None,
});
validate(&mut config, None)?;
Ok(())
}
#[test]
fn empty_auth_token_is_rejected() -> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
config.auth = Some(AuthConfig {
pass: None,
token: String::new(),
require_verified_worker: false,
lys: None,
});
let message = config_validation_message(validate(&mut config, None));
assert!(message.contains("auth.token"));
assert!(message.contains("must not be empty"));
Ok(())
}
#[test]
fn requiring_a_verified_worker_without_a_pass_verifier_is_rejected()
-> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
config.auth = Some(AuthConfig {
pass: None,
token: "s3cr3t".to_owned(),
require_verified_worker: true,
lys: None,
});
let message = config_validation_message(validate(&mut config, None));
assert!(
message.contains("auth.require_verified_worker") && message.contains("auth.pass"),
"the refusal must name the flag and the missing section: {message}"
);
Ok(())
}
#[test]
fn auth_token_longer_than_a_connect_can_carry_is_rejected() -> Result<(), Box<dyn std::error::Error>>
{
let max = crate::server::connection::pre_admission::MAX_CONNECT_AUTH_TOKEN_BYTES;
let mut config = sample_config()?;
config.auth = Some(AuthConfig {
pass: None,
token: "t".repeat(max),
require_verified_worker: false,
lys: None,
});
validate(&mut config, None)?;
config.auth = Some(AuthConfig {
pass: None,
token: "t".repeat(max + 1),
require_verified_worker: false,
lys: None,
});
let message = config_validation_message(validate(&mut config, None));
assert!(message.contains("auth.token"));
assert!(message.contains(&format!("at most {max}")));
Ok(())
}
#[test]
fn absent_auth_section_passes_validation() -> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
config.auth = None;
validate(&mut config, None)?;
Ok(())
}
#[test]
fn default_profile_is_full_and_passes_validation() -> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
assert_eq!(
config.services.profile()?,
crate::config::types::ServiceProfile::Full
);
validate(&mut config, None)?;
Ok(())
}
#[test]
fn unknown_profile_is_a_validation_error() -> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
config.services = ServicesConfig {
profile: "banana".to_owned(),
..ServicesConfig::default()
};
let message = config_validation_message(validate(&mut config, None));
assert!(message.contains("services.profile"));
assert!(message.contains("banana"));
assert!(message.contains("worker-front-door"));
Ok(())
}
#[test]
fn worker_front_door_profile_with_empty_topology_passes() -> Result<(), Box<dyn std::error::Error>>
{
let mut config = worker_front_door_config()?;
assert_eq!(
config.services.profile()?,
crate::config::types::ServiceProfile::WorkerFrontDoor
);
validate(&mut config, None)?;
Ok(())
}
#[test]
fn worker_front_door_profile_rejects_channels_persistence_and_cluster()
-> Result<(), Box<dyn std::error::Error>> {
let mut config = sample_config()?;
config.services = ServicesConfig {
profile: "worker-front-door".to_owned(),
..ServicesConfig::default()
};
config.persistence_path = Some(PathBuf::from("/tmp"));
let message = config_validation_message(validate(&mut config, None));
assert!(message.contains("builds no channels"));
assert!(message.contains("builds no durable store"));
assert!(message.contains("builds no channel cluster"));
Ok(())
}
fn lys_table(decisions: Option<&str>) -> String {
let decisions = decisions.map_or(String::new(), |word| format!("decisions = \"{word}\"\n"));
format!("issuer = \"https://lys.test\"\nnetwork_id = \"n\"\nkeys_path = \"/k\"\n{decisions}")
}
#[test]
fn access011_decisions_is_enforce_by_default_or_the_written_word()
-> Result<(), Box<dyn std::error::Error>> {
use crate::config::types::{Decisions, LysConfig};
for (word, expected) in [
(None, Decisions::Enforce),
(Some("enforce"), Decisions::Enforce),
(Some("advise"), Decisions::Advise),
] {
let config: LysConfig = toml::from_str(&lys_table(word))?;
assert_eq!(config.decisions, expected, "{word:?}");
}
Ok(())
}
#[test]
fn access011_an_unknown_decisions_word_is_refused_naming_the_member_and_both_words()
-> Result<(), Box<dyn std::error::Error>> {
let refusal = toml::from_str::<crate::config::types::LysConfig>(&lys_table(Some("sometimes")))
.err()
.map(|error| error.to_string())
.ok_or("decisions = \"sometimes\" was accepted")?;
for word in ["sometimes", "enforce", "advise", "decisions"] {
assert!(refusal.contains(word), "{word}: {refusal}");
}
Ok(())
}