//! Tests for `brokerd`'s configuration. Do not edit: these define the required behaviour. use brokerd::config::{Approvals, Config, ConfigError, Sockets}; use std::path::{Path, PathBuf}; fn fixture(name: &str) -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) .join("tests/fixtures/config") .join(name) } /// What `home` must default to in this process. The test does not set the variable: changing the /// environment of a running test binary would race with the other tests. fn default_home() -> PathBuf { std::env::var_os("BOXMAKER_HOME") .map(PathBuf::from) .unwrap_or_else(|| PathBuf::from("/var/lib/boxmaker")) } #[test] fn an_empty_file_gets_every_default() { let c = Config::load(&fixture("empty.toml")).unwrap(); assert_eq!(c.paths.home, default_home()); assert_eq!(c.paths.grants, PathBuf::from("/etc/boxmaker/grants")); assert_eq!(c.sockets, Sockets::default()); assert_eq!(c.approvals, Approvals { ttl_ms: 900_000 }); assert_eq!(Approvals::default(), Approvals { ttl_ms: 900_000 }); assert_eq!(c, Config::parse("").unwrap()); assert_eq!(c, Config::default()); } #[test] fn sockets_and_directories_default_to_places_under_home() { let c = Config::load(&fixture("home_only.toml")).unwrap(); assert_eq!(c.paths.home, PathBuf::from("/srv/boxmaker")); assert_eq!( c.broker_socket(), PathBuf::from("/srv/boxmaker/run/loop-broker/broker.sock") ); assert_eq!( c.admin_socket(), PathBuf::from("/srv/boxmaker/run/owner-broker/admin.sock") ); assert_eq!(c.audit_dir(), PathBuf::from("/srv/boxmaker/audit")); assert_eq!( c.state_dir(), PathBuf::from("/srv/boxmaker/broker/sessions") ); // The grants are not under home: the owner writes them, brokerd only reads them. assert_eq!(c.paths.grants, PathBuf::from("/etc/boxmaker/grants")); } #[test] fn every_key_can_be_set() { let c = Config::load(&fixture("full.toml")).unwrap(); assert_eq!(c.paths.home, PathBuf::from("/srv/boxmaker")); assert_eq!(c.paths.grants, PathBuf::from("/srv/boxmaker-grants")); assert_eq!(c.broker_socket(), PathBuf::from("/run/bx/broker.sock")); assert_eq!(c.admin_socket(), PathBuf::from("/run/bx/admin.sock")); assert_eq!(c.approvals.ttl_ms, 60_000); // The two directories always follow home. assert_eq!(c.audit_dir(), PathBuf::from("/srv/boxmaker/audit")); assert_eq!( c.state_dir(), PathBuf::from("/srv/boxmaker/broker/sessions") ); } #[test] fn one_socket_set_leaves_the_other_at_its_default() { let c = Config::parse("[paths]\nhome = \"/h\"\n[sockets]\nadmin = \"/x/admin.sock\"\n").unwrap(); assert_eq!(c.admin_socket(), PathBuf::from("/x/admin.sock")); assert_eq!( c.broker_socket(), PathBuf::from("/h/run/loop-broker/broker.sock") ); } #[test] fn unknown_keys_and_tables_are_errors() { for name in ["unknown_key.toml", "unknown_table.toml", "wrong_type.toml"] { match Config::load(&fixture(name)) { Err(ConfigError::Parse(path, _)) => assert_eq!(path, fixture(name)), other => panic!("{name}: expected a parse error, got {other:?}"), } } // In every table, not only the one the fixture shows. for text in [ "[paths]\nhome = \"/h\"\nhouse = \"/h\"\n", "[sockets]\nbroker = \"/b.sock\"\nloop = \"/l.sock\"\n", "[approvals]\nttl_ms = 1\nttl_s = 1\n", "top = 1\n", "[approvals]\nttl_ms = -5\n", ] { assert!(Config::parse(text).is_err(), "accepted: {text}"); } } #[test] fn a_missing_file_is_a_read_error_that_names_the_file() { let path = fixture("does-not-exist.toml"); match Config::load(&path) { Err(ConfigError::Read(p, _)) => assert_eq!(p, path), other => panic!("expected a read error, got {other:?}"), } let text = Config::load(&path).unwrap_err().to_string(); assert!(text.contains("does-not-exist.toml"), "{text}"); } #[test] fn a_parse_error_names_the_file_and_the_key() { let text = Config::load(&fixture("unknown_key.toml")) .unwrap_err() .to_string(); assert!(text.contains("unknown_key.toml"), "{text}"); assert!(text.contains("ttl"), "{text}"); }