mirror of https://github.com/ekzhang/rustpad
231 lines
5.9 KiB
Rust
231 lines
5.9 KiB
Rust
//! Basic tests for real-time collaboration.
|
|
|
|
use std::time::Duration;
|
|
|
|
use anyhow::Result;
|
|
use common::*;
|
|
use log::info;
|
|
use operational_transform::OperationSeq;
|
|
use rustpad_server::{server, ServerConfig};
|
|
use serde_json::json;
|
|
use tokio::time;
|
|
|
|
pub mod common;
|
|
|
|
#[tokio::test]
|
|
async fn test_single_operation() -> Result<()> {
|
|
pretty_env_logger::try_init().ok();
|
|
let filter = server(ServerConfig::default());
|
|
|
|
expect_text(&filter, "foobar", "").await;
|
|
|
|
let mut client = connect(&filter, "foobar").await?;
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, json!({ "Identity": 0 }));
|
|
|
|
let mut operation = OperationSeq::default();
|
|
operation.insert("hello");
|
|
let msg = json!({
|
|
"Edit": {
|
|
"revision": 0,
|
|
"operation": operation
|
|
}
|
|
});
|
|
info!("sending ClientMsg {}", msg);
|
|
client.send(&msg).await;
|
|
|
|
let msg = client.recv().await?;
|
|
assert_eq!(
|
|
msg,
|
|
json!({
|
|
"History": {
|
|
"start": 0,
|
|
"operations": [
|
|
{ "id": 0, "operation": ["hello"] }
|
|
]
|
|
}
|
|
})
|
|
);
|
|
|
|
expect_text(&filter, "foobar", "hello").await;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_invalid_operation() -> Result<()> {
|
|
pretty_env_logger::try_init().ok();
|
|
let filter = server(ServerConfig::default());
|
|
|
|
expect_text(&filter, "foobar", "").await;
|
|
|
|
let mut client = connect(&filter, "foobar").await?;
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, json!({ "Identity": 0 }));
|
|
|
|
let mut operation = OperationSeq::default();
|
|
operation.insert("hello");
|
|
let msg = json!({
|
|
"Edit": {
|
|
"revision": 1,
|
|
"operation": operation
|
|
}
|
|
});
|
|
info!("sending ClientMsg {}", msg);
|
|
client.send(&msg).await;
|
|
|
|
client.recv_closed().await?;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_concurrent_transform() -> Result<()> {
|
|
pretty_env_logger::try_init().ok();
|
|
let filter = server(ServerConfig::default());
|
|
|
|
// Connect the first client
|
|
let mut client = connect(&filter, "foobar").await?;
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, json!({ "Identity": 0 }));
|
|
|
|
// Insert the first operation
|
|
let mut operation = OperationSeq::default();
|
|
operation.insert("hello");
|
|
let msg = json!({
|
|
"Edit": {
|
|
"revision": 0,
|
|
"operation": operation
|
|
}
|
|
});
|
|
info!("sending ClientMsg {}", msg);
|
|
client.send(&msg).await;
|
|
|
|
let msg = client.recv().await?;
|
|
assert_eq!(
|
|
msg,
|
|
json!({
|
|
"History": {
|
|
"start": 0,
|
|
"operations": [
|
|
{ "id": 0, "operation": ["hello"] }
|
|
]
|
|
}
|
|
})
|
|
);
|
|
|
|
// Insert the second operation
|
|
let mut operation = OperationSeq::default();
|
|
operation.retain(2);
|
|
operation.delete(1);
|
|
operation.insert("n");
|
|
operation.retain(2);
|
|
let msg = json!({
|
|
"Edit": {
|
|
"revision": 1,
|
|
"operation": operation
|
|
}
|
|
});
|
|
info!("sending ClientMsg {}", msg);
|
|
client.send(&msg).await;
|
|
|
|
let msg = client.recv().await?;
|
|
assert_eq!(
|
|
msg,
|
|
json!({
|
|
"History": {
|
|
"start": 1,
|
|
"operations": [
|
|
{ "id": 0, "operation": [2, "n", -1, 2] }
|
|
]
|
|
}
|
|
})
|
|
);
|
|
expect_text(&filter, "foobar", "henlo").await;
|
|
|
|
// Connect the second client
|
|
let mut client2 = connect(&filter, "foobar").await?;
|
|
let msg = client2.recv().await?;
|
|
assert_eq!(msg, json!({ "Identity": 1 }));
|
|
|
|
// Insert a concurrent operation before seeing the existing history
|
|
time::sleep(Duration::from_millis(50)).await;
|
|
let mut operation = OperationSeq::default();
|
|
operation.insert("~rust~");
|
|
let msg = json!({
|
|
"Edit": {
|
|
"revision": 0,
|
|
"operation": operation
|
|
}
|
|
});
|
|
info!("sending ClientMsg {}", msg);
|
|
client2.send(&msg).await;
|
|
|
|
// Receive the existing history
|
|
let msg = client2.recv().await?;
|
|
assert_eq!(
|
|
msg,
|
|
json!({
|
|
"History": {
|
|
"start": 0,
|
|
"operations": [
|
|
{ "id": 0, "operation": ["hello"] },
|
|
{ "id": 0, "operation": [2, "n", -1, 2] }
|
|
]
|
|
}
|
|
})
|
|
);
|
|
|
|
// Expect to receive a transformed operation
|
|
let transformed_op = json!({
|
|
"History": {
|
|
"start": 2,
|
|
"operations": [
|
|
{ "id": 1, "operation": ["~rust~", 5] },
|
|
]
|
|
}
|
|
});
|
|
|
|
// ... in the first client
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, transformed_op);
|
|
|
|
// ... and in the second client
|
|
let msg = client2.recv().await?;
|
|
assert_eq!(msg, transformed_op);
|
|
|
|
expect_text(&filter, "foobar", "~rust~henlo").await;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_set_language() -> Result<()> {
|
|
pretty_env_logger::try_init().ok();
|
|
let filter = server(ServerConfig::default());
|
|
|
|
let mut client = connect(&filter, "foobar").await?;
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, json!({ "Identity": 0 }));
|
|
|
|
let msg = json!({ "SetLanguage": "javascript" });
|
|
client.send(&msg).await;
|
|
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, json!({ "Language": "javascript" }));
|
|
|
|
let mut client2 = connect(&filter, "foobar").await?;
|
|
let msg = client2.recv().await?;
|
|
assert_eq!(msg, json!({ "Identity": 1 }));
|
|
let msg = client2.recv().await?;
|
|
assert_eq!(msg, json!({ "Language": "javascript" }));
|
|
|
|
let msg = json!({ "SetLanguage": "python" });
|
|
client2.send(&msg).await;
|
|
|
|
let msg = client.recv().await?;
|
|
assert_eq!(msg, json!({ "Language": "python" }));
|
|
let msg = client2.recv().await?;
|
|
assert_eq!(msg, json!({ "Language": "python" }));
|
|
|
|
expect_text(&filter, "foobar", "").await;
|
|
Ok(())
|
|
}
|