feat(console): expose component capabilities

- project structured capability package, name, version, and interface fields
- derive capabilities during registration and artifact restoration
- keep Component imports as the source of truth without changing .wasmpkg
- verify empty and Clock capability responses through the management API
This commit is contained in:
Maofeng
2026-07-29 19:13:41 +08:00
parent 5b32886efe
commit 72a264e0d1
2 changed files with 83 additions and 3 deletions
+39
View File
@@ -40,6 +40,7 @@ async fn manages_a_resident_component_over_http() {
assert_eq!(status, StatusCode::CREATED, "{registered}");
assert_eq!(registered["id"], "echo");
assert_eq!(registered["status"], "stopped");
assert_eq!(registered["capabilities"], json!([]));
let response = application
.clone()
@@ -89,6 +90,41 @@ async fn manages_a_resident_component_over_http() {
assert!(events["events"].as_array().unwrap().len() >= 5);
}
#[tokio::test]
async fn reports_exact_component_host_capabilities() {
let artifact_dir = TempDir::new().expect("temporary artifact directory");
let application = test_app(artifact_dir.path()).await;
let component = fs::read(component_artifact("clock_probe_component.wasm"))
.expect("clock probe component should be readable");
let response = application
.clone()
.oneshot(package_request("clock-probe", "0.1.0", &component))
.await
.expect("register request should complete");
assert_eq!(response.status(), StatusCode::CREATED);
let registered = response_json(response).await;
assert_eq!(
registered["capabilities"],
json!([{
"interface": "wasmeld:clock/monotonic-clock@0.1.0",
"package": "wasmeld:clock",
"name": "monotonic-clock",
"version": "0.1.0"
}])
);
let response = application
.oneshot(get_request("/api/v1/services"))
.await
.expect("service list request should complete");
let services = response_json(response).await;
assert_eq!(
services["services"][0]["capabilities"],
registered["capabilities"]
);
}
#[tokio::test]
async fn routes_raw_gateway_calls_through_the_active_deployment() {
let artifact_dir = TempDir::new().expect("temporary artifact directory");
@@ -686,6 +722,8 @@ fn package_request(id: &str, revision: &str, component: &[u8]) -> Request<Body>
let mut package = Cursor::new(Vec::new());
let world = if id == "counter" {
"component:counter/counter-component@0.1.0"
} else if id == "clock-probe" {
"component:clock-probe/clock-probe-component@0.1.0"
} else {
"component:echo/echo-component@0.1.0"
};
@@ -787,6 +825,7 @@ fn component_artifact(name: &str) -> PathBuf {
for manifest in [
"components/echo/Cargo.toml",
"components/counter/Cargo.toml",
"components/clock-probe/Cargo.toml",
] {
let status = Command::new("rustup")
.args([