use mockforge_plugin_core::*;
use mockforge_plugin_loader::*;
use std::fs;
use tempfile::TempDir;
#[cfg(test)]
mod tests {
use super::*;
fn create_test_plugin_manifest() -> PluginManifest {
let id = PluginId::new("test-plugin");
let version = PluginVersion::new(1, 0, 0);
let author = PluginAuthor::with_email("Test Author", "test@example.com");
let info = PluginInfo::new(id, version, "Test Plugin", "A test plugin", author);
PluginManifest::new(info).with_capability("template")
}
fn create_test_wasm_bytes() -> Vec<u8> {
vec![
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00,
0x00, ]
}
#[tokio::test]
async fn test_plugin_loader_initialization() {
let config = PluginLoaderConfig::default();
let _loader = PluginLoader::new(config);
}
#[tokio::test]
async fn test_plugin_validation_success() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should succeed");
let validated_manifest = result.unwrap();
assert_eq!(validated_manifest.info.id.as_str(), "test-plugin");
assert_eq!(validated_manifest.info.version.to_string(), "1.0.0");
}
#[tokio::test]
async fn test_plugin_validation_missing_manifest() {
let temp_dir = TempDir::new().unwrap();
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_err(), "Plugin validation should fail with missing manifest");
}
#[tokio::test]
async fn test_plugin_validation_invalid_manifest() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
fs::write(&manifest_path, "invalid: yaml: content: [unclosed").unwrap();
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_err(), "Plugin validation should fail with invalid manifest");
}
#[tokio::test]
async fn test_plugin_validation_missing_wasm() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_err(), "Plugin validation should fail with missing WASM");
}
#[tokio::test]
async fn test_plugin_loading_and_unloading() {
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let plugin_id = PluginId::new("test-plugin".to_string());
let _manifest = create_test_plugin_manifest();
let _wasm_bytes = create_test_wasm_bytes();
let result = loader.load_plugin(&plugin_id).await;
assert!(
result.is_err(),
"expected plugin load to fail in test environment, but got: {result:?}"
);
let unload_result = loader.unload_plugin(&plugin_id).await;
assert!(
unload_result.is_err(),
"expected NotFound error when unloading a plugin that was never loaded"
);
}
#[tokio::test]
async fn test_plugin_health_check() {
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let plugin_id = PluginId::new("nonexistent-plugin".to_string());
let result = loader.get_plugin_health(&plugin_id).await;
assert!(result.is_err(), "Health check should fail for non-existent plugin");
}
#[tokio::test]
async fn test_plugin_list_and_get() {
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let plugins = loader.list_plugins().await;
assert!(plugins.is_empty() || !plugins.is_empty());
let plugin_id = PluginId::new("nonexistent".to_string());
let result = loader.get_plugin(&plugin_id).await;
assert!(result.is_none(), "Getting non-existent plugin should return None");
}
#[tokio::test]
async fn test_plugin_reload_operations() {
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let stats = loader.reload_all_plugins().await;
let stats = stats.unwrap();
assert_eq!(stats.discovered, 0); assert_eq!(stats.loaded, 0);
assert_eq!(stats.failed, 0);
let plugin_id = PluginId::new("test-plugin".to_string());
let result = loader.reload_plugin(&plugin_id).await;
assert!(result.is_err(), "Reloading non-existent plugin should fail");
}
#[tokio::test]
async fn test_load_statistics() {
let config = PluginLoaderConfig::default();
let loader = PluginLoader::new(config);
let stats = loader.get_load_stats().await;
assert_eq!(stats.total_plugins(), 0); assert!(stats.success_rate() >= 0.0 && stats.success_rate() <= 1.0);
}
#[tokio::test]
async fn test_security_validation() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should pass even with high resource limits");
}
#[tokio::test]
async fn test_network_capability_validation() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should pass with network capabilities");
let validated_manifest = result.unwrap();
assert!(validated_manifest.capabilities.contains(&"template".to_string()));
}
#[tokio::test]
async fn test_filesystem_capability_validation() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should pass with filesystem capabilities");
let validated_manifest = result.unwrap();
assert!(validated_manifest.capabilities.contains(&"template".to_string()));
}
#[tokio::test]
async fn test_dependency_validation() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should pass with dependencies");
let validated_manifest = result.unwrap();
assert!(validated_manifest.dependencies.is_empty());
}
#[tokio::test]
async fn test_plugin_capability_validation() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should pass");
let validated_manifest = result.unwrap();
assert!(
validated_manifest.capabilities.contains(&"template".to_string()),
"Plugin should have template capability"
);
}
#[tokio::test]
async fn test_configuration_schema_validation() {
let temp_dir = TempDir::new().unwrap();
let manifest_path = temp_dir.path().join("plugin.yaml");
let wasm_path = temp_dir.path().join("plugin.wasm");
let manifest = create_test_plugin_manifest();
let yaml_content = serde_yaml::to_string(&manifest).unwrap();
fs::write(&manifest_path, yaml_content).unwrap();
let wasm_bytes = create_test_wasm_bytes();
fs::write(&wasm_path, wasm_bytes).unwrap();
let config = PluginLoaderConfig {
skip_wasm_validation: true, ..Default::default()
};
let loader = PluginLoader::new(config);
let result = loader.validate_plugin(temp_dir.path()).await;
assert!(result.is_ok(), "Plugin validation should pass with configuration schema");
let validated_manifest = result.unwrap();
assert!(validated_manifest.dependencies.is_empty());
}
}