use serde_json::json;
use tokio::time::{Duration, timeout};
use crate::app_server::AppServerInbound;
use crate::storage::PRIMARY_RUNTIME_ID;
use super::super::events::handle_app_server_message;
use super::support::{bootstrap_test_state, primary_runtime};
#[tokio::test]
async fn app_server_starting_message_updates_status_without_deadlock() {
let state = bootstrap_test_state().await;
timeout(
Duration::from_secs(2),
handle_app_server_message(
&state,
AppServerInbound::Starting {
runtime_id: PRIMARY_RUNTIME_ID.to_string(),
},
),
)
.await
.expect("处理 Starting 消息超时")
.expect("处理 Starting 消息失败");
let runtime = primary_runtime(&state).await;
let status = runtime.status.read().await.clone();
assert_eq!(status.status, "starting");
assert_eq!(status.app_server_handshake.state, "starting");
}
#[tokio::test]
async fn permissions_server_request_is_persisted_for_clients() {
let state = bootstrap_test_state().await;
timeout(
Duration::from_secs(2),
handle_app_server_message(
&state,
AppServerInbound::ServerRequest {
runtime_id: PRIMARY_RUNTIME_ID.to_string(),
id: json!("req-permissions-1"),
method: "item/permissions/requestApproval".to_string(),
params: json!({
"threadId": "thread-1",
"turnId": "turn-1",
"itemId": "item-1",
"reason": "需要额外权限",
"permissions": {
"network": { "enabled": true },
"fileSystem": {
"read": ["/srv/workspace/docs"],
"write": ["/srv/workspace/tmp"]
}
}
}),
},
),
)
.await
.expect("处理 permissions request 超时")
.expect("处理 permissions request 失败");
let pending = state
.storage
.list_pending_requests()
.expect("读取 pending requests 失败");
assert_eq!(1, pending.len());
assert_eq!("item/permissions/requestApproval", pending[0].request_type);
assert_eq!(Some("thread-1"), pending[0].thread_id.as_deref());
assert!(pending[0].permissions.is_some());
}
#[tokio::test]
async fn legacy_server_request_is_normalized_into_pending_request() {
let state = bootstrap_test_state().await;
timeout(
Duration::from_secs(2),
handle_app_server_message(
&state,
AppServerInbound::ServerRequest {
runtime_id: PRIMARY_RUNTIME_ID.to_string(),
id: json!("req-exec-1"),
method: "execCommandApproval".to_string(),
params: json!({
"conversationId": "thread-legacy",
"callId": "call-exec-1",
"approvalId": "approval-1",
"command": ["git", "status"],
"cwd": "/srv/workspace",
"reason": "需要执行命令",
"parsedCmd": []
}),
},
),
)
.await
.expect("处理 legacy request 超时")
.expect("处理 legacy request 失败");
let pending = state
.storage
.list_pending_requests()
.expect("读取 pending requests 失败");
assert_eq!(1, pending.len());
assert_eq!("execCommandApproval", pending[0].request_type);
assert_eq!(Some("thread-legacy"), pending[0].thread_id.as_deref());
assert_eq!(Some("git status"), pending[0].command.as_deref());
assert_eq!(
vec!["approved", "approved_for_session", "denied", "abort"],
pending[0].available_decisions,
);
}