initial commit
This commit is contained in:
76
interfaces/websocket/server/tests/basic_integration_test.rs
Normal file
76
interfaces/websocket/server/tests/basic_integration_test.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use circle_ws_lib::{spawn_circle_server, ServerConfig};
|
||||
use rhailib_engine::create_heromodels_engine;
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use heromodels::db::hero::OurDB;
|
||||
use rhailib_worker::spawn_rhai_worker;
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_server_startup_and_play() {
|
||||
let circle_pk = Uuid::new_v4().to_string();
|
||||
let redis_url = "redis://127.0.0.1/";
|
||||
|
||||
// --- Worker Setup ---
|
||||
let (shutdown_tx, shutdown_rx) = mpsc::channel(1);
|
||||
let db = Arc::new(OurDB::new("file:memdb_test_server?mode=memory&cache=shared", true).unwrap());
|
||||
let engine = create_heromodels_engine();
|
||||
let worker_id = Uuid::new_v4().to_string();
|
||||
let worker_handle = spawn_rhai_worker(
|
||||
worker_id,
|
||||
circle_pk.to_string(),
|
||||
engine,
|
||||
redis_url.to_string(),
|
||||
shutdown_rx,
|
||||
false,
|
||||
);
|
||||
|
||||
// --- Server Setup ---
|
||||
let config = ServerConfig::new(
|
||||
"127.0.0.1".to_string(),
|
||||
9997, // Using a different port to avoid conflicts
|
||||
redis_url.to_string(),
|
||||
);
|
||||
let (server_task, server_handle) = spawn_circle_server(config).unwrap();
|
||||
let server_join_handle = tokio::spawn(server_task);
|
||||
|
||||
// Give server and worker a moment to start
|
||||
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||
|
||||
// --- Client Connection and Test ---
|
||||
let ws_url = format!("ws://127.0.0.1:9997/{}", circle_pk);
|
||||
let (mut ws_stream, _) = connect_async(ws_url).await.expect("Failed to connect");
|
||||
|
||||
let play_req = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "play",
|
||||
"params": { "script": "40 + 2" },
|
||||
"id": 1
|
||||
});
|
||||
|
||||
ws_stream
|
||||
.send(Message::Text(play_req.to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let response = ws_stream.next().await.unwrap().unwrap();
|
||||
let response_text = response.to_text().unwrap();
|
||||
let response_json: serde_json::Value = serde_json::from_str(response_text).unwrap();
|
||||
|
||||
assert_eq!(response_json["id"], 1);
|
||||
assert!(
|
||||
response_json["result"].is_object(),
|
||||
"The result should be an object, but it was: {}",
|
||||
response_text
|
||||
);
|
||||
assert_eq!(response_json["result"]["output"], "42");
|
||||
|
||||
// --- Cleanup ---
|
||||
server_handle.stop(true).await;
|
||||
let _ = server_join_handle.await;
|
||||
let _ = shutdown_tx.send(()).await;
|
||||
let _ = worker_handle.await;
|
||||
}
|
25
interfaces/websocket/server/tests/connection_test.rs
Normal file
25
interfaces/websocket/server/tests/connection_test.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use circle_ws_lib::{spawn_circle_server, ServerConfig};
|
||||
use std::time::Duration;
|
||||
use tokio_tungstenite::connect_async;
|
||||
use url::Url;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_server_connection() {
|
||||
let config = ServerConfig::new(
|
||||
"127.0.0.1".to_string(),
|
||||
9001,
|
||||
"redis://127.0.0.1:6379".to_string(),
|
||||
);
|
||||
|
||||
let (server_handle, _server_stop_handle) = spawn_circle_server(config).unwrap();
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let url_str = "ws://127.0.0.1:9001/test_pub_key";
|
||||
let url = Url::parse(url_str).unwrap();
|
||||
let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
|
||||
|
||||
println!("WebSocket connection successful: {:?}", ws_stream);
|
||||
|
||||
server_handle.abort();
|
||||
}
|
119
interfaces/websocket/server/tests/timeout_integration_test.rs
Normal file
119
interfaces/websocket/server/tests/timeout_integration_test.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
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<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[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<JsonRpcErrorResponse, _> = 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();
|
||||
}
|
85
interfaces/websocket/server/tests/wss_integration_test.rs
Normal file
85
interfaces/websocket/server/tests/wss_integration_test.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use circle_ws_lib::{spawn_circle_server, ServerConfig};
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_basic_ws_server_startup() {
|
||||
env_logger::init();
|
||||
|
||||
let config = ServerConfig::new(
|
||||
"127.0.0.1".to_string(),
|
||||
8091, // Use a different port to avoid conflicts
|
||||
"redis://127.0.0.1:6379".to_string(),
|
||||
);
|
||||
|
||||
let (server_task, server_handle) = spawn_circle_server(config)
|
||||
.expect("Failed to spawn circle server");
|
||||
|
||||
// Let the server run for a short time
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
|
||||
// Stop the server
|
||||
server_handle.stop(true).await;
|
||||
|
||||
// Wait for the server task to complete
|
||||
let _ = server_task.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_tls_server_configuration() {
|
||||
env_logger::init();
|
||||
|
||||
// Test TLS configuration validation
|
||||
let config = ServerConfig::new(
|
||||
"127.0.0.1".to_string(),
|
||||
8092,
|
||||
"redis://127.0.0.1:6379".to_string(),
|
||||
)
|
||||
.with_tls("nonexistent_cert.pem".to_string(), "nonexistent_key.pem".to_string())
|
||||
.with_tls_port(8444);
|
||||
|
||||
// This should fail gracefully if cert files don't exist
|
||||
match spawn_circle_server(config) {
|
||||
Ok((server_task, server_handle)) => {
|
||||
// If it succeeds (cert files exist), clean up
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
server_handle.stop(true).await;
|
||||
let _ = server_task.await;
|
||||
println!("TLS server started successfully (cert files found)");
|
||||
}
|
||||
Err(e) => {
|
||||
// Expected if cert files don't exist - this is fine for testing
|
||||
println!("TLS server failed to start as expected: {}", e);
|
||||
assert!(e.to_string().contains("Certificate") || e.to_string().contains("TLS"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_server_config_validation() {
|
||||
// Test that ServerConfig properly validates TLS settings
|
||||
let config = ServerConfig::new(
|
||||
"127.0.0.1".to_string(),
|
||||
8093,
|
||||
"redis://127.0.0.1:6379".to_string(),
|
||||
);
|
||||
|
||||
// Test basic configuration
|
||||
|
||||
assert_eq!(config.host, "127.0.0.1");
|
||||
assert_eq!(config.port, 8093);
|
||||
assert!(!config.enable_tls);
|
||||
assert!(!config.enable_auth);
|
||||
|
||||
// Test TLS configuration
|
||||
let tls_config = config
|
||||
.with_tls("cert.pem".to_string(), "key.pem".to_string())
|
||||
.with_tls_port(8445)
|
||||
.with_auth();
|
||||
|
||||
assert!(tls_config.enable_tls);
|
||||
assert!(tls_config.enable_auth);
|
||||
assert_eq!(tls_config.get_tls_port(), 8445);
|
||||
assert_eq!(tls_config.cert_path, Some("cert.pem".to_string()));
|
||||
assert_eq!(tls_config.key_path, Some("key.pem".to_string()));
|
||||
}
|
Reference in New Issue
Block a user