use circle_ws_lib::{spawn_circle_server, ServerConfig}; use futures_util::{sink::SinkExt, stream::StreamExt}; use std::time::Duration; use tokio::time::sleep; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; // Define a simple JSON-RPC request structure for sending scripts #[derive(serde::Serialize, Debug)] struct JsonRpcRequest { jsonrpc: String, method: String, params: ScriptParams, id: u64, } #[derive(serde::Serialize, Debug)] struct ScriptParams { script: String, } // Define a simple JSON-RPC error response structure for assertion #[derive(serde::Deserialize, Debug)] #[allow(dead_code)] struct JsonRpcErrorResponse { jsonrpc: String, error: JsonRpcErrorDetails, id: Option, } #[derive(serde::Deserialize, Debug)] struct JsonRpcErrorDetails { code: i32, message: String, } const SERVER_ADDRESS: &str = "ws://127.0.0.1:8088/test_pub_key_timeout"; const TEST_CIRCLE_NAME: &str = "test_timeout_circle"; const RHAI_TIMEOUT_SECONDS: u64 = 30; // Match server's default timeout #[tokio::test] async fn test_rhai_script_timeout() { let server_config = ServerConfig::new( "127.0.0.1".to_string(), 8088, "redis://127.0.0.1:6379".to_string(), ); let (server_handle, _server_stop_handle) = spawn_circle_server(server_config).unwrap(); sleep(Duration::from_secs(2)).await; // Give server time to start let (mut ws_stream, _response) = connect_async(SERVER_ADDRESS) .await .expect("Failed to connect to WebSocket server"); let long_running_script = " let mut x = 0; for i in 0..999999999 { x = x + i; } print(x); " .to_string(); let request = JsonRpcRequest { jsonrpc: "2.0".to_string(), method: "play".to_string(), params: ScriptParams { script: long_running_script, }, id: 1, }; let request_json = serde_json::to_string(&request).expect("Failed to serialize request"); ws_stream .send(Message::Text(request_json)) .await .expect("Failed to send message"); match tokio::time::timeout( Duration::from_secs(RHAI_TIMEOUT_SECONDS + 10), ws_stream.next(), ) .await { Ok(Some(Ok(Message::Text(text)))) => { let response: Result = serde_json::from_str(&text); match response { Ok(err_resp) => { assert_eq!( err_resp.error.code, -32002, "Error code should indicate timeout." ); assert!( err_resp.error.message.contains("Timeout"), "Error message should indicate timeout." ); } Err(e) => { panic!("Failed to deserialize error response: {}. Raw: {}", e, text); } } } Ok(Some(Ok(other_msg))) => { panic!("Received unexpected message type: {:?}", other_msg); } Ok(Some(Err(e))) => { panic!("WebSocket error: {}", e); } Ok(None) => { panic!("WebSocket stream closed unexpectedly."); } Err(_) => { panic!("Test timed out waiting for server response."); } } ws_stream.close(None).await.ok(); server_handle.abort(); }