#[cfg(all(feature = "client", feature = "server"))]
mod integration {
use agent_inbox_protocol::{
Body, Client, From, Mailbox, MailboxName, MailboxProvider, Message, MessageID,
QueryParameters, QueryResult, ToolCallRequest, ToolCallResponse, router,
};
use chrono::Utc;
use tokio::net::TcpListener;
use tokio::sync::oneshot;
#[derive(Clone)]
struct DummyProvider {
expected: QueryParameters,
response: QueryResult,
}
#[async_trait::async_trait]
impl MailboxProvider for DummyProvider {
type Error = std::convert::Infallible;
async fn query(&mut self, query: QueryParameters) -> Result<QueryResult, Self::Error> {
assert_eq!(query, self.expected);
Ok(self.response.clone())
}
async fn tool_call(
&mut self,
_request: ToolCallRequest,
) -> Result<ToolCallResponse, Self::Error> {
Ok(ToolCallResponse::success())
}
}
#[tokio::test]
async fn client_queries_server_over_random_socket() {
let mailbox = Mailbox {
name: MailboxName::new("inbox").expect("valid mailbox name"),
messages: vec![Message {
msg_id: MessageID::new("integration-1").expect("valid message id"),
date: Utc::now(),
from: From::new("alice@example.com").expect("valid from"),
body: Body::new("hello from the integration test").expect("valid body"),
wrap: false,
tools: Vec::new(),
}],
};
let expected = QueryResult::new(vec![mailbox]);
let query = QueryParameters {
search: Some("hello".to_string()),
keywords: Some(vec!["integration".to_string()]),
max_per_inbox: Some(10),
max_across_inboxes: Some(10),
..Default::default()
};
let provider = DummyProvider {
expected: query.clone(),
response: expected.clone(),
};
let app = router(provider);
let listener = TcpListener::bind("127.0.0.1:0")
.await
.expect("bind random port");
let addr = listener.local_addr().expect("local addr");
let (shutdown_tx, shutdown_rx) = oneshot::channel();
let server_handle = tokio::spawn(async move {
axum::serve(listener, app)
.with_graceful_shutdown(async {
let _ = shutdown_rx.await;
})
.await
.expect("server exits cleanly");
});
tokio::task::yield_now().await;
let mut client = Client::new(format!("http://{}", addr));
let response = client.query(query).await.expect("query succeeds");
assert_eq!(response, expected);
let _ = shutdown_tx.send(());
let _ = server_handle.await;
}
}