use blvm_node::module::manager::ModuleManager;
use std::path::PathBuf;
use tempfile::TempDir;
fn write_installed_module(modules_dir: &PathBuf, name: &str, version: &str, binary_bytes: &[u8]) {
let module_dir = modules_dir.join(name);
std::fs::create_dir_all(&module_dir).unwrap();
std::fs::write(
module_dir.join("module.toml"),
format!(
r#"name = "{name}"
version = "{version}"
entry_point = "{name}"
"#
),
)
.unwrap();
let binary_path = module_dir.join(name);
std::fs::write(&binary_path, binary_bytes).unwrap();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&binary_path, std::fs::Permissions::from_mode(0o755)).unwrap();
}
}
fn manager_with_module(name: &str, version: &str) -> (TempDir, ModuleManager) {
let temp_dir = TempDir::new().unwrap();
let modules_dir = temp_dir.path().join("modules");
let data_dir = temp_dir.path().join("data");
let socket_dir = temp_dir.path().join("sockets");
std::fs::create_dir_all(&modules_dir).unwrap();
write_installed_module(&modules_dir, name, version, b"#!/bin/sh\nexit 0\n");
let manager = ModuleManager::new(&modules_dir, &data_dir, &socket_dir);
(temp_dir, manager)
}
#[tokio::test]
async fn auto_load_skips_on_disk_module_when_version_does_not_match_constraint() {
let (_dir, mut manager) = manager_with_module("pin-test", "0.2.0");
manager.set_enabled_modules([("pin-test".into(), "0.1.*".into())].into_iter().collect());
manager.auto_load_modules().await.unwrap();
assert!(manager.list_modules().await.is_empty());
}
#[tokio::test]
async fn auto_load_keeps_module_not_in_enabled_allowlist_off_disk() {
let (_dir, mut manager) = manager_with_module("other", "1.0.0");
manager.set_enabled_modules([("pin-test".into(), "0.1.*".into())].into_iter().collect());
manager.auto_load_modules().await.unwrap();
assert!(manager.list_modules().await.is_empty());
}
#[tokio::test]
async fn auto_load_matching_version_without_registry_reaches_load_stage() {
let (_dir, mut manager) = manager_with_module("pin-test", "0.1.8");
manager.set_enabled_modules([("pin-test".into(), "0.1.*".into())].into_iter().collect());
let result = manager.auto_load_modules().await;
match &result {
Ok(()) => {
}
Err(e) => {
let msg = e.to_string();
assert!(
!msg.contains("No modules to load"),
"unexpected early exit before load: {msg}"
);
}
}
}
#[test]
fn module_config_enabled_modules_table_form_toml() {
use blvm_node::config::NodeConfig;
let temp_dir = TempDir::new().unwrap();
let path = temp_dir.path().join("cfg.toml");
std::fs::write(
&path,
r#"transport_preference = "tcponly"
[modules]
[modules.enabled_modules]
blvm-miniscript = "0.1.*"
blvm-zmq = "0.3.*"
"#,
)
.unwrap();
let config = NodeConfig::from_toml_file(&path).unwrap();
let modules = config.modules.as_ref().unwrap();
assert_eq!(modules.enabled_modules.len(), 2);
assert_eq!(
modules.enabled_modules.get("blvm-zmq").map(String::as_str),
Some("0.3.*")
);
}