@@ -192,19 +192,35 @@ async fn handle_client_request<
192192#[ cfg( test) ]
193193mod tests {
194194 use super :: * ;
195- use agent_client_protocol:: { RequestPermissionRequest , RequestPermissionResponse } ;
195+ use crate :: session_id:: AcpSessionId ;
196+ use agent_client_protocol:: {
197+ ContentBlock , ContentChunk , RequestPermissionRequest , RequestPermissionResponse ,
198+ SessionNotification , SessionUpdate ,
199+ } ;
196200 use async_trait:: async_trait;
201+ use std:: cell:: RefCell ;
197202 use trogon_nats:: MockNatsClient ;
198203 use trogon_std:: time:: SystemClock ;
199204
200- struct MockClient ;
205+ struct MockClient {
206+ notifications : RefCell < Vec < String > > ,
207+ }
208+
209+ impl MockClient {
210+ fn new ( ) -> Self {
211+ Self {
212+ notifications : RefCell :: new ( Vec :: new ( ) ) ,
213+ }
214+ }
215+ }
201216
202217 #[ async_trait( ?Send ) ]
203218 impl Client for MockClient {
204219 async fn session_notification (
205220 & self ,
206- _ : agent_client_protocol:: SessionNotification ,
221+ n : agent_client_protocol:: SessionNotification ,
207222 ) -> agent_client_protocol:: Result < ( ) > {
223+ self . notifications . borrow_mut ( ) . push ( format ! ( "{:?}" , n) ) ;
208224 Ok ( ( ) )
209225 }
210226
@@ -228,8 +244,79 @@ mod tests {
228244 & opentelemetry:: global:: meter ( "acp-nats-test" ) ,
229245 crate :: config:: Config :: for_test ( "acp" ) ,
230246 ) ) ;
231- let client = Rc :: new ( MockClient ) ;
247+ let client = Rc :: new ( MockClient :: new ( ) ) ;
232248
233249 run ( nats, client, bridge) . await ;
234250 }
251+
252+ #[ test]
253+ fn jsonrpc_error_response_contains_code_and_message ( ) {
254+ let bytes = jsonrpc_error_response (
255+ serde_json:: Value :: Number ( 1 . into ( ) ) ,
256+ ErrorCode :: InvalidParams ,
257+ "bad input" ,
258+ ) ;
259+ let v: serde_json:: Value = serde_json:: from_slice ( & bytes) . unwrap ( ) ;
260+ assert_eq ! ( v[ "jsonrpc" ] , "2.0" ) ;
261+ assert_eq ! ( v[ "id" ] , 1 ) ;
262+ assert_eq ! ( v[ "error" ] [ "message" ] , "bad input" ) ;
263+ assert_eq ! ( v[ "error" ] [ "code" ] , i32 :: from( ErrorCode :: InvalidParams ) ) ;
264+ }
265+
266+ #[ test]
267+ fn extract_request_id_returns_id_from_valid_payload ( ) {
268+ let payload = br#"{"jsonrpc":"2.0","id":42,"method":"foo"}"# ;
269+ let id = extract_request_id ( payload) ;
270+ assert_eq ! ( id, serde_json:: Value :: Number ( 42 . into( ) ) ) ;
271+ }
272+
273+ #[ test]
274+ fn extract_request_id_returns_null_for_missing_id ( ) {
275+ let payload = br#"{"jsonrpc":"2.0","method":"foo"}"# ;
276+ let id = extract_request_id ( payload) ;
277+ assert_eq ! ( id, serde_json:: Value :: Null ) ;
278+ }
279+
280+ #[ test]
281+ fn extract_request_id_returns_null_for_invalid_json ( ) {
282+ let id = extract_request_id ( b"not json" ) ;
283+ assert_eq ! ( id, serde_json:: Value :: Null ) ;
284+ }
285+
286+ #[ tokio:: test]
287+ async fn handle_client_request_dispatches_session_update ( ) {
288+ let nats = MockNatsClient :: new ( ) ;
289+ let bridge = Bridge :: new (
290+ nats. clone ( ) ,
291+ SystemClock ,
292+ & opentelemetry:: global:: meter ( "acp-nats-test" ) ,
293+ crate :: config:: Config :: for_test ( "acp" ) ,
294+ ) ;
295+ let client = MockClient :: new ( ) ;
296+ let session_id = AcpSessionId :: new ( "sess-1" ) . unwrap ( ) ;
297+
298+ let notification = SessionNotification :: new (
299+ "sess-1" ,
300+ SessionUpdate :: AgentMessageChunk ( ContentChunk :: new ( ContentBlock :: from ( "hi" ) ) ) ,
301+ ) ;
302+ let payload = bytes:: Bytes :: from ( serde_json:: to_vec ( & notification) . unwrap ( ) ) ;
303+
304+ let parsed = crate :: nats:: ParsedClientSubject {
305+ session_id,
306+ method : ClientMethod :: SessionUpdate ,
307+ } ;
308+
309+ handle_client_request (
310+ "acp.sess-1.client.session.update" ,
311+ parsed,
312+ payload,
313+ None ,
314+ & nats,
315+ & client,
316+ & bridge,
317+ )
318+ . await ;
319+
320+ assert_eq ! ( client. notifications. borrow( ) . len( ) , 1 ) ;
321+ }
235322}
0 commit comments