use car_ffi_common::proxy::DaemonClient;
use car_memgine::MemgineEngine;
use car_server_core::{run_dispatch, ServerState, ServerStateConfig};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;
use tempfile::TempDir;
use tokio::net::TcpListener;
use tokio::sync::Mutex;
use tokio_tungstenite::accept_async;
async fn spawn_one_shot_dispatcher(state: Arc<ServerState>) -> SocketAddr {
let listener = TcpListener::bind(SocketAddr::V4(SocketAddrV4::new(
Ipv4Addr::new(127, 0, 0, 1),
0,
)))
.await
.expect("bind loopback");
let addr = listener.local_addr().expect("local_addr");
tokio::spawn(async move {
let (stream, peer) = listener.accept().await.expect("accept");
let ws = accept_async(stream).await.expect("ws handshake");
let (write, read) = futures::StreamExt::split(ws);
let _ = run_dispatch(read, write, peer, state).await;
});
addr
}
fn loopback_state(journal_dir: std::path::PathBuf) -> Arc<ServerState> {
let engine = Arc::new(Mutex::new(MemgineEngine::new(None)));
let cfg = ServerStateConfig::new(journal_dir).with_shared_memgine(engine);
Arc::new(ServerState::with_config(cfg))
}
#[tokio::test]
async fn state_round_trips_on_single_client() {
let tmp = TempDir::new().expect("tempdir");
let state = loopback_state(tmp.path().to_path_buf());
let addr = spawn_one_shot_dispatcher(state).await;
let url = format!("ws://{}", addr);
let client = DaemonClient::with_url(url);
client
.call(
"state.set",
serde_json::json!({ "key": "k", "value": "v" }),
)
.await
.expect("state.set");
let got = client
.call("state.get", serde_json::json!({ "key": "k" }))
.await
.expect("state.get");
assert_eq!(
got,
serde_json::Value::String("v".into()),
"expected the write to be visible to the read on the same client/session"
);
}