//! Integration tests for the ACP JSON-RPC server. //! //! These tests verify that the server correctly handles JSON-RPC requests //! over HTTP and returns proper responses. use dirigate::acp::model::{JsonRpcError, JsonRpcRequest, JsonRpcResponse}; use dirigate::acp::server::AcpServer; use dirigate::fixture::types::*; use dirigate::{MockerConfig, MockerState}; use std::collections::HashMap; use std::sync::Arc; /// Helper to create a minimal test fixture with a template session. fn create_test_fixture_with_template() -> Fixture { Fixture { version: "0.1".to_string(), sessions: vec![Session { id: "test-template".to_string(), title: "Test Template Session".to_string(), created_at: "2025-01-01T00:00:00Z".to_string(), participants: vec![ Participant { id: "user-1".to_string(), kind: ParticipantKind::User, display_name: Some("Test User".to_string()), }, Participant { id: "assistant-1".to_string(), kind: ParticipantKind::Assistant, display_name: Some("Test Assistant".to_string()), }, ], messages: vec![], behavior: None, }], responders: Responders { keyword_map: HashMap::new(), default_strategy: ResponderStrategy::Echo, random: None, }, streaming: Streaming { enabled: true, tokens_per_chunk: 5, chunk_interval_ms: 100, jitter_ms: Some(10), }, } } #[tokio::test] async fn test_server_initialize_request() { // Create state let config = MockerConfig::default(); let fixtures = create_test_fixture_with_template(); let state = Arc::new(MockerState::new(config, fixtures)); // Create server on a random port let server = AcpServer::new(state.clone(), 0); // Start server in background tokio::spawn(async move { let _ = server.serve().await; }); // Give server time to start tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; // Note: We can't actually test the HTTP endpoint without binding to a known port // This test verifies the server compiles and runs without panicking } #[tokio::test] async fn test_jsonrpc_initialize_response_format() { // Create a mock initialize request let request = JsonRpcRequest::new( "initialize", Some(serde_json::json!({ "protocol_version": "0.1", "client_capabilities": {} })), 1, ); // Verify request serialization let json = serde_json::to_string(&request).unwrap(); assert!(json.contains("\"jsonrpc\":\"2.0\"")); assert!(json.contains("\"method\":\"initialize\"")); assert!(json.contains("\"id\":1")); // Parse it back let parsed: JsonRpcRequest = serde_json::from_str(&json).unwrap(); assert_eq!(parsed.method, "initialize"); assert_eq!(parsed.jsonrpc, "2.0"); } #[tokio::test] async fn test_jsonrpc_session_new_response_format() { // Create a mock session/new request let request = JsonRpcRequest::new( "session/new", Some(serde_json::json!({ "template_id": "test-template" })), 2, ); // Verify request serialization let json = serde_json::to_string(&request).unwrap(); assert!(json.contains("\"jsonrpc\":\"2.0\"")); assert!(json.contains("\"method\":\"session/new\"")); assert!(json.contains("\"template_id\":\"test-template\"")); assert!(json.contains("\"id\":2")); // Parse it back let parsed: JsonRpcRequest = serde_json::from_str(&json).unwrap(); assert_eq!(parsed.method, "session/new"); assert_eq!(parsed.jsonrpc, "2.0"); } #[tokio::test] async fn test_jsonrpc_error_response_format() { // Create an error response let error = JsonRpcError::method_not_found("unknown_method"); let response = JsonRpcResponse::error(error, Some(serde_json::json!(1))); // Verify response serialization let json = serde_json::to_string(&response).unwrap(); assert!(json.contains("\"jsonrpc\":\"2.0\"")); assert!(json.contains("\"error\"")); assert!(json.contains("-32601")); // Method not found code assert!(!json.contains("\"result\"")); // Should not have result field // Parse it back let parsed: JsonRpcResponse = serde_json::from_str(&json).unwrap(); assert!(parsed.error.is_some()); assert!(parsed.result.is_none()); assert_eq!(parsed.error.unwrap().code, -32601); } #[tokio::test] async fn test_jsonrpc_success_response_format() { // Create a success response let result = serde_json::json!({ "session_id": "test-session-123" }); let response = JsonRpcResponse::success(result, Some(serde_json::json!(1))); // Verify response serialization let json = serde_json::to_string(&response).unwrap(); assert!(json.contains("\"jsonrpc\":\"2.0\"")); assert!(json.contains("\"result\"")); assert!(json.contains("\"session_id\":\"test-session-123\"")); assert!(!json.contains("\"error\"")); // Should not have error field // Parse it back let parsed: JsonRpcResponse = serde_json::from_str(&json).unwrap(); assert!(parsed.result.is_some()); assert!(parsed.error.is_none()); }