huskies: merge 778

This commit is contained in:
dave
2026-04-28 09:54:51 +00:00
parent d2d5ef8afa
commit fb5a21cfbb
4 changed files with 240 additions and 7 deletions
+58
View File
@@ -58,6 +58,14 @@ pub fn build_gateway_route(state_arc: Arc<GatewayState>) -> impl poem::Endpoint
"/gateway/events/push",
poem::get(gateway_event_push_handler),
)
// Agent registration via CRDT-sync WebSocket.
.at("/crdt-sync", poem::get(gateway_crdt_sync_handler))
// Agent management REST endpoints.
.at("/gateway/agents", poem::get(gateway_list_agents_handler))
.at(
"/gateway/agents/:id/assign",
poem::post(gateway_assign_agent_handler),
)
// Serve the embedded React frontend so the gateway has a UI.
.at(
"/assets/*path",
@@ -161,6 +169,56 @@ mod tests {
// ── poem::test::TestClient and mock HTTP servers remain here since they
// ── test the combined HTTP + service interaction through real routes.
#[tokio::test]
async fn crdt_sync_handshake_then_register_writes_crdt_node() {
crate::crdt_state::init_for_test();
let state = make_test_state();
// Generate a valid join token via the tokens endpoint.
let token_app = poem::Route::new()
.at(
"/gateway/tokens",
poem::post(gateway_generate_token_handler),
)
.data(state.clone());
let cli = poem::test::TestClient::new(token_app);
let resp = cli.post("/gateway/tokens").send().await;
assert_eq!(resp.0.status(), poem::http::StatusCode::OK);
let body: serde_json::Value = resp.0.into_body().into_json().await.unwrap();
let token = body["token"].as_str().unwrap().to_string();
// Token must be pending before the upgrade.
assert!(state.pending_tokens.read().await.contains_key(&token));
// Call register_agent directly (the service function exercised by the handler).
let node = crate::service::gateway::register_agent(
&state,
&token,
"test-label".into(),
"ws://test:9000".into(),
)
.await
.unwrap();
// Token is consumed after registration.
assert!(state.pending_tokens.read().await.is_empty());
// CRDT node was written and is visible via list_agents.
let agents = crate::service::gateway::list_agents();
assert!(
agents.iter().any(|n| n.node_id == node.node_id),
"Registered node must appear in list_agents"
);
// remove_agent tombstones the node.
assert!(crate::service::gateway::remove_agent(&node.node_id));
let alive = crate::service::gateway::list_agents();
assert!(
!alive.iter().any(|n| n.node_id == node.node_id),
"Tombstoned node must not appear in list_agents"
);
}
#[tokio::test]
async fn generate_token_creates_pending_token() {
let state = make_test_state();