203 lines
5.4 KiB
Rust
203 lines
5.4 KiB
Rust
use crate::util::{spawn_server, TestServer, TestUser};
|
|
|
|
use collab::core::collab::MutexCollab;
|
|
use collab::core::origin::{CollabClient, CollabOrigin};
|
|
use collab::preclude::Collab;
|
|
use collab_client_ws::{WSClient, WSClientConfig, WSObjectHandler};
|
|
use collab_plugins::disk::kv::rocks_kv::RocksCollabDB;
|
|
use collab_plugins::disk::rocksdb::RocksdbDiskPlugin;
|
|
use collab_plugins::sync::SyncPlugin;
|
|
use serde_json::Value;
|
|
use std::collections::HashMap;
|
|
use std::net::SocketAddr;
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use tempfile::TempDir;
|
|
use tokio::sync::RwLock;
|
|
|
|
pub enum TestScript {
|
|
CreateClient {
|
|
uid: i64,
|
|
},
|
|
OpenObject {
|
|
uid: i64,
|
|
object_id: String,
|
|
},
|
|
AssertClientContent {
|
|
uid: i64,
|
|
object_id: String,
|
|
expected: Value,
|
|
},
|
|
Wait {
|
|
secs: u64,
|
|
},
|
|
AssertServerContent {
|
|
object_id: String,
|
|
expected: Value,
|
|
},
|
|
ModifyClientCollab {
|
|
uid: i64,
|
|
object_id: String,
|
|
f: fn(&Collab),
|
|
},
|
|
AssertClientEqualToServer {
|
|
uid: i64,
|
|
object_id: String,
|
|
},
|
|
}
|
|
|
|
pub struct ScriptTest {
|
|
server: TestServer,
|
|
pub clients: RwLock<HashMap<i64, TestClient>>,
|
|
}
|
|
|
|
impl ScriptTest {
|
|
pub async fn new() -> Self {
|
|
let server = spawn_server().await;
|
|
ScriptTest {
|
|
server,
|
|
clients: RwLock::new(HashMap::new()),
|
|
}
|
|
}
|
|
|
|
async fn get_client_doc_value(&self, uid: i64, object_id: &str) -> Value {
|
|
self
|
|
.clients
|
|
.read()
|
|
.await
|
|
.get(&uid)
|
|
.unwrap()
|
|
.collab_by_object_id
|
|
.get(object_id)
|
|
.unwrap()
|
|
.lock()
|
|
.to_json_value()
|
|
}
|
|
|
|
pub async fn run_script(&mut self, script: TestScript) {
|
|
match script {
|
|
TestScript::CreateClient { uid } => {
|
|
let test_user = TestUser::generate();
|
|
let token = test_user.register(&self.server).await;
|
|
let address = format!("{}/{}", self.server.ws_addr, token);
|
|
let ws = WSClient::new(address, WSClientConfig::default());
|
|
let addr = ws.connect().await.unwrap().unwrap();
|
|
let origin = origin_from_tcp_stream(&addr);
|
|
let tempdir = TempDir::new().unwrap();
|
|
let db_path = tempdir.into_path();
|
|
let db = Arc::new(RocksCollabDB::open(db_path.clone()).unwrap());
|
|
let cleaner = Cleaner::new(db_path);
|
|
let client = TestClient {
|
|
ws,
|
|
db,
|
|
origin,
|
|
collab_by_object_id: Default::default(),
|
|
handlers: vec![],
|
|
cleaner,
|
|
};
|
|
self.clients.write().await.insert(uid, client);
|
|
},
|
|
TestScript::OpenObject { uid, object_id } => {
|
|
let mut clients = self.clients.write().await;
|
|
let client = clients.get_mut(&uid).unwrap();
|
|
let handler = client.ws.subscribe(1, object_id.clone()).await.unwrap();
|
|
let (sink, stream) = (handler.sink(), handler.stream());
|
|
let collab = Arc::new(MutexCollab::new(client.origin.clone(), &object_id, vec![]));
|
|
|
|
// Sync
|
|
let sync_plugin = SyncPlugin::new(
|
|
client.origin.clone(),
|
|
&object_id,
|
|
collab.clone(),
|
|
sink,
|
|
stream,
|
|
);
|
|
collab.lock().add_plugin(Arc::new(sync_plugin));
|
|
|
|
// Disk
|
|
let disk_plugin = RocksdbDiskPlugin::new(uid, client.db.clone()).unwrap();
|
|
collab.lock().add_plugin(Arc::new(disk_plugin));
|
|
|
|
collab.initial();
|
|
client.handlers.push(handler);
|
|
client.collab_by_object_id.insert(object_id, collab);
|
|
},
|
|
TestScript::Wait { secs } => {
|
|
tokio::time::sleep(Duration::from_secs(secs)).await;
|
|
},
|
|
TestScript::AssertClientContent {
|
|
uid,
|
|
object_id,
|
|
expected,
|
|
} => {
|
|
let value = self.get_client_doc_value(uid, &object_id).await;
|
|
assert_json_diff::assert_json_eq!(value, expected);
|
|
},
|
|
TestScript::AssertServerContent {
|
|
object_id,
|
|
expected,
|
|
} => {
|
|
let value = self.server.get_doc(&object_id);
|
|
assert_json_diff::assert_json_eq!(value, expected);
|
|
},
|
|
TestScript::AssertClientEqualToServer { uid, object_id } => {
|
|
let server_value = self.server.get_doc(&object_id);
|
|
let client_value = self.get_client_doc_value(uid, &object_id).await;
|
|
assert_eq!(client_value, server_value);
|
|
assert_json_diff::assert_json_eq!(client_value, server_value);
|
|
},
|
|
TestScript::ModifyClientCollab { uid, object_id, f } => {
|
|
let mut clients = self.clients.write().await;
|
|
let client = clients.get_mut(&uid).unwrap();
|
|
let collab = client
|
|
.collab_by_object_id
|
|
.get_mut(&object_id)
|
|
.unwrap()
|
|
.lock();
|
|
f(&collab);
|
|
},
|
|
}
|
|
}
|
|
|
|
pub async fn run_scripts(&mut self, scripts: Vec<TestScript>) {
|
|
for script in scripts {
|
|
self.run_script(script).await;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn origin_from_tcp_stream(addr: &SocketAddr) -> CollabOrigin {
|
|
let origin = CollabClient::new(addr.port() as i64, &addr.to_string());
|
|
CollabOrigin::Client(origin)
|
|
}
|
|
|
|
pub struct TestClient {
|
|
pub ws: WSClient,
|
|
pub db: Arc<RocksCollabDB>,
|
|
pub origin: CollabOrigin,
|
|
pub collab_by_object_id: HashMap<String, Arc<MutexCollab>>,
|
|
pub handlers: Vec<Arc<WSObjectHandler>>,
|
|
#[allow(dead_code)]
|
|
cleaner: Cleaner,
|
|
}
|
|
|
|
struct Cleaner(PathBuf);
|
|
|
|
impl Cleaner {
|
|
fn new(dir: PathBuf) -> Self {
|
|
Cleaner(dir)
|
|
}
|
|
|
|
fn cleanup(dir: &PathBuf) {
|
|
let _ = std::fs::remove_dir_all(dir);
|
|
}
|
|
}
|
|
|
|
impl Drop for Cleaner {
|
|
fn drop(&mut self) {
|
|
Self::cleanup(&self.0)
|
|
}
|
|
}
|