feat: 插件自动挂载测试机制 — capabilities + self_test + 3阶段启动

- Plugin trait 增加 capabilities() 和 self_test() 方法
- PluginVTable 增加 get_capabilities 和 self_test FFI
- ServiceManager 三阶段启动: init → self_test → start
- SendCallback 改为 ctx 参数传递,消除 thread_local
- export_plugin! 宏所有 FFI 函数包裹 catch_unwind
- PluginManifest 增加 capabilities/required_capabilities/auto_test
- 新增 3 个自测相关测试用例 (共 59 测试)
This commit is contained in:
showen
2026-03-13 04:31:39 +08:00
parent 1863efb0f5
commit 99ee78984c
9 changed files with 694 additions and 123 deletions

View File

@@ -29,12 +29,28 @@ pub struct PluginManifest {
#[serde(default = "default_error_policy")]
pub error_policy: ErrorPolicy,
pub so_filename: String,
/// 插件声明支持的功能列表
#[serde(default)]
pub capabilities: Vec<String>,
/// 挂载时必须通过测试的功能capabilities 的子集)
#[serde(default)]
pub required_capabilities: Vec<String>,
/// 自测超时(毫秒),默认 5000
#[serde(default = "default_test_timeout")]
pub test_timeout_ms: u64,
/// 是否在挂载时自动运行自测,默认 true
#[serde(default = "default_true")]
pub auto_test: bool,
}
fn default_error_policy() -> ErrorPolicy {
ErrorPolicy::AutoRollback
}
fn default_test_timeout() -> u64 {
5000
}
/// 插件错误处理策略
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
@@ -250,6 +266,10 @@ mod tests {
dependencies: vec![],
error_policy: ErrorPolicy::AutoRollback,
so_filename: "libtest_plugin.so".to_string(),
capabilities: vec![],
required_capabilities: vec![],
test_timeout_ms: 5000,
auto_test: true,
};
fs::write(
@@ -333,4 +353,38 @@ mod tests {
let _ = fs::remove_dir_all(&tmp);
}
#[test]
fn manifest_parses_capabilities() {
let json = r#"{
"id": "sensor",
"version": "1.0.0",
"sdk_version": "0.2.0",
"so_filename": "libsensor.so",
"capabilities": ["temperature", "humidity"],
"required_capabilities": ["temperature"],
"test_timeout_ms": 3000,
"auto_test": true
}"#;
let manifest: PluginManifest = serde_json::from_str(json).unwrap();
assert_eq!(manifest.capabilities, vec!["temperature", "humidity"]);
assert_eq!(manifest.required_capabilities, vec!["temperature"]);
assert_eq!(manifest.test_timeout_ms, 3000);
assert!(manifest.auto_test);
}
#[test]
fn manifest_capabilities_default_empty() {
let json = r#"{
"id": "basic",
"version": "1.0.0",
"sdk_version": "0.2.0",
"so_filename": "libbasic.so"
}"#;
let manifest: PluginManifest = serde_json::from_str(json).unwrap();
assert!(manifest.capabilities.is_empty());
assert!(manifest.required_capabilities.is_empty());
assert_eq!(manifest.test_timeout_ms, 5000);
assert!(manifest.auto_test);
}
}