215 lines
7.3 KiB
Rust
215 lines
7.3 KiB
Rust
use rust_xmpp::config::{self, Config};
|
|
use serde_json::json;
|
|
use std::path::Path;
|
|
|
|
fn lua(text: &str) -> anyhow::Result<Config> {
|
|
let dir = tempfile::tempdir()?;
|
|
let path = dir.path().join("config.lua");
|
|
std::fs::write(&path, text)?;
|
|
config::load(&path)
|
|
}
|
|
#[test]
|
|
fn supplied_configuration_scopes_arithmetic_and_modules() {
|
|
let cfg = config::load(Path::new("tests/fixtures/prosody.cfg.lua")).unwrap();
|
|
assert_eq!(cfg.hosts.len(), 4);
|
|
assert_eq!(
|
|
cfg.option("wthome.ru", "authentication"),
|
|
Some(&json!("internal_hashed"))
|
|
);
|
|
assert_eq!(
|
|
cfg.option("upload.wthome.ru", "http_file_share_size_limit"),
|
|
Some(&json!(10737418240_u64))
|
|
);
|
|
assert_eq!(
|
|
cfg.option("upload.wthome.ru", "http_file_share_global_quota"),
|
|
Some(&json!(107374182400_u64))
|
|
);
|
|
assert!(cfg.modules("wthome.ru").unwrap().contains("sasl2"));
|
|
assert_eq!(
|
|
cfg.modules("conference.wthome.ru")
|
|
.unwrap()
|
|
.into_iter()
|
|
.collect::<Vec<_>>(),
|
|
vec!["muc", "muc_mam"]
|
|
);
|
|
assert_eq!(
|
|
cfg.modules("upload.wthome.ru")
|
|
.unwrap()
|
|
.into_iter()
|
|
.collect::<Vec<_>>(),
|
|
vec!["http_file_share"]
|
|
);
|
|
assert!(
|
|
cfg.diagnostics()
|
|
.iter()
|
|
.any(|d| d.message.contains("security_labels"))
|
|
);
|
|
}
|
|
#[test]
|
|
fn all_formats_round_trip_actual_config() {
|
|
let c = config::load(Path::new("tests/fixtures/prosody.cfg.lua")).unwrap();
|
|
let dir = tempfile::tempdir().unwrap();
|
|
for (ext, text) in [
|
|
("json", serde_json::to_string(&c).unwrap()),
|
|
("yaml", serde_yaml_ng::to_string(&c).unwrap()),
|
|
("toml", toml::to_string(&c).unwrap()),
|
|
] {
|
|
let p = dir.path().join(format!("c.{ext}"));
|
|
std::fs::write(&p, text).unwrap();
|
|
assert_eq!(
|
|
serde_json::to_value(&c).unwrap(),
|
|
serde_json::to_value(config::load(&p).unwrap()).unwrap()
|
|
);
|
|
}
|
|
}
|
|
#[test]
|
|
fn include_has_own_global_scope_and_parent_scope_is_restored() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
std::fs::write(
|
|
dir.path().join("main.lua"),
|
|
"VirtualHost 'one.test'\nInclude 'child.lua'\nname='one'",
|
|
)
|
|
.unwrap();
|
|
std::fs::write(
|
|
dir.path().join("child.lua"),
|
|
"archive_expires_after='never'\nVirtualHost 'two.test'\nname='two'",
|
|
)
|
|
.unwrap();
|
|
let c = config::load(&dir.path().join("main.lua")).unwrap();
|
|
assert_eq!(c.global["archive_expires_after"], json!("never"));
|
|
assert_eq!(c.hosts["one.test"].options["name"], json!("one"));
|
|
assert_eq!(c.hosts["two.test"].options["name"], json!("two"));
|
|
}
|
|
#[test]
|
|
fn include_cycles_rejected() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let p = dir.path().join("c.lua");
|
|
std::fs::write(&p, "Include 'c.lua'").unwrap();
|
|
assert!(config::load(&p).unwrap_err().to_string().contains("cycle"));
|
|
}
|
|
#[test]
|
|
fn declarations_and_overrides() {
|
|
let c=lua("modules_enabled={'roster','mam'}\nVirtualHost 'ONE.TEST' {modules_disabled={'mam'}}\nComponent 'muc.test' 'muc' {name='Rooms'}\nallow_registration=false").unwrap();
|
|
assert_eq!(
|
|
c.modules("one.test")
|
|
.unwrap()
|
|
.into_iter()
|
|
.collect::<Vec<_>>(),
|
|
vec!["roster"]
|
|
);
|
|
assert_eq!(c.global["allow_registration"], json!(false));
|
|
assert_eq!(c.hosts["muc.test"].component.as_deref(), Some("muc"));
|
|
}
|
|
#[test]
|
|
fn runtime_capabilities_are_unavailable() {
|
|
for source in [
|
|
"os.execute('true')",
|
|
"io.open('/etc/passwd')",
|
|
"require('socket')",
|
|
"RunScript 'x'",
|
|
"Lua.os.execute('true')",
|
|
] {
|
|
assert!(lua(source).is_err(), "{source}");
|
|
}
|
|
}
|
|
#[test]
|
|
fn loops_are_bounded() {
|
|
assert!(
|
|
lua("while true do end")
|
|
.unwrap_err()
|
|
.to_string()
|
|
.contains("budget")
|
|
);
|
|
}
|
|
#[test]
|
|
fn malformed_values_rejected() {
|
|
for text in [
|
|
"VirtualHost 'x.test'\nc2s_ports={0}",
|
|
"VirtualHost 'x.test'\nc2s_ports={65536}",
|
|
"VirtualHost 'x.test'\nc2s_ports={5222,5222}",
|
|
"VirtualHost 'x.test'\nmodules_enabled='mam'",
|
|
"VirtualHost 'x.test'\nallow_registration='false'",
|
|
"VirtualHost 'x.test'\nComponent 'x.test' 'muc'",
|
|
"VirtualHost '../x'",
|
|
"VirtualHost 'x.test'\nx={ [2]='hole' }",
|
|
"VirtualHost 'x.test'\nx={ 'item', key='value' }",
|
|
] {
|
|
assert!(lua(text).is_err(), "accepted {text}");
|
|
}
|
|
}
|
|
#[test]
|
|
fn tables_cannot_recurse_forever() {
|
|
assert!(lua("local t={}\nt.self=t\nVirtualHost 'x.test'\nx=t").is_err());
|
|
}
|
|
#[test]
|
|
fn component_can_explicitly_enable_global_modules() {
|
|
let c = lua("modules_enabled={'ping'}\nComponent 'muc.test' 'muc'\nload_global_modules=true")
|
|
.unwrap();
|
|
assert!(c.modules("muc.test").unwrap().contains("ping"));
|
|
}
|
|
#[test]
|
|
fn storage_paths_encode_like_prosody() {
|
|
use rust_xmpp::storage::encode_name;
|
|
assert_eq!(encode_name("wthome.ru"), "wthome%2eru");
|
|
assert_eq!(encode_name("../x_y"), "%2e%2e%2fx%5fy");
|
|
assert_eq!(encode_name("я"), "%d1%8f");
|
|
}
|
|
|
|
#[test]
|
|
fn supplied_config_matches_original_prosody_loader() {
|
|
// The original loader is run only as a reference in tests, with stubs for
|
|
// helpers unused by this fixture. This is not a runtime dependency.
|
|
let vm = mlua::Lua::new();
|
|
vm.load(
|
|
r#"
|
|
package.preload['prosody.util.envload'] = function()
|
|
return { envload=function(s,n,e) return load(s,n,'t',e) end }
|
|
end
|
|
package.preload['prosody.util.dependencies'] = function()
|
|
return { softreq=function() return nil end }
|
|
end
|
|
package.preload['prosody.util.iterators'] = function() return {} end
|
|
package.preload['prosody.util.paths'] = function()
|
|
return { resolve_relative_path=function(p,f) return p..f end }
|
|
end
|
|
package.preload['prosody.util.debug'] = function()
|
|
return { get_traceback_table=function() return {} end }
|
|
end
|
|
package.preload['prosody.util.error'] = function()
|
|
return { is_error=function() return false end }
|
|
end
|
|
package.preload['prosody.util.logger'] = function()
|
|
return { init=function() return function() end end }
|
|
end
|
|
"#,
|
|
)
|
|
.exec()
|
|
.unwrap();
|
|
let reference: mlua::Table = vm
|
|
.load(include_str!("reference/configmanager.lua"))
|
|
.eval()
|
|
.unwrap();
|
|
let load: mlua::Function = reference.get("load").unwrap();
|
|
let (ok, _, _): (bool, mlua::Value, mlua::Value) = load
|
|
.call(("tests/fixtures/prosody.cfg.lua", "lua"))
|
|
.unwrap();
|
|
assert!(ok);
|
|
let get: mlua::Function = reference.get("getconfig").unwrap();
|
|
let table: mlua::Table = get.call(()).unwrap();
|
|
let parsed = config::load(Path::new("tests/fixtures/prosody.cfg.lua")).unwrap();
|
|
let global: mlua::Value = table.get("*").unwrap();
|
|
assert_eq!(
|
|
rust_xmpp::lua::json_value(global, 0).unwrap(),
|
|
json!(parsed.global)
|
|
);
|
|
for (name, host) in &parsed.hosts {
|
|
let v: mlua::Value = table.get(name.as_str()).unwrap();
|
|
let mut reference = rust_xmpp::lua::json_value(v, 0).unwrap();
|
|
let object = reference.as_object_mut().unwrap();
|
|
object.remove("defined");
|
|
let component = object.remove("component_module");
|
|
assert_eq!(component, host.component.as_ref().map(|v| json!(v)));
|
|
assert_eq!(reference, json!(host.options));
|
|
}
|
|
}
|