use std::{str::FromStr, sync::Arc};
use anyhow::Result;
use dittolive_ditto::{fs::TempRoot, prelude::*};
pub fn get_ditto(
database_id: Option<DatabaseId>,
use_server_mode: bool,
) -> Result<(TempRoot, Ditto)> {
let database_id = database_id.unwrap_or_else(DatabaseId::generate);
let connect = if use_server_mode {
DittoConfigConnect::Server {
url: format!("https://{}.cloud.ditto.live", database_id)
.parse()
.unwrap(),
}
} else {
DittoConfigConnect::SmallPeersOnly { private_key: None }
};
let temp_root = TempRoot::new();
let config = DittoConfig::new(database_id.to_string(), connect)
.with_persistence_directory(temp_root.root_path());
let ditto = Ditto::open_sync(config)?;
if !use_server_mode {
let _ = ditto.set_license_from_env("DITTO_LICENSE");
}
Ok((temp_root, ditto))
}
#[tokio::test]
#[ignore = "Requires DITTO_LICENSE environment variable"]
async fn mixed_case_database_id_succeeds_with_shared_key_authentication() -> Result<()> {
let database_id = DatabaseId::from_str("heLLo")?;
let (_root1, ditto1) = get_ditto(Some(database_id.clone()), false)?;
let (_root2, ditto2) = get_ditto(Some(database_id), false)?;
let mut server = TransportConfig::new();
server.listen.tcp = TcpListenConfig {
enabled: true,
interface_ip: "127.0.0.1".into(),
port: 53644,
};
ditto1.set_transport_config(server);
let mut client = TransportConfig::new();
client
.connect
.tcp_servers
.insert("localhost:53644".to_string());
ditto2.set_transport_config(client);
ditto1.sync().start()?;
ditto2.sync().start()?;
let ditto2 = Arc::new(ditto2);
assert_connected_peers(Arc::clone(&ditto2), 1).await;
Ok(())
}
#[tokio::test]
#[ignore = "Requires DITTO_LICENSE environment variable"]
async fn mixed_case_database_id_succeeds_with_shared_key_authentication_on_peers_with_different_cases(
) -> Result<()> {
let database_id_1 = DatabaseId::from_str("HeLLo")?;
let database_id_2 = DatabaseId::from_str("hello")?;
let (_root1, ditto1) = get_ditto(Some(database_id_1), false)?;
let (_root2, ditto2) = get_ditto(Some(database_id_2), false)?;
let mut server = TransportConfig::new();
server.listen.tcp = TcpListenConfig {
enabled: true,
interface_ip: "127.0.0.1".into(),
port: 53645,
};
ditto1.set_transport_config(server);
let mut client = TransportConfig::new();
client
.connect
.tcp_servers
.insert("localhost:53645".to_string());
ditto2.set_transport_config(client);
ditto1.sync().start()?;
ditto2.sync().start()?;
let ditto2 = Arc::new(ditto2);
assert_connected_peers(Arc::clone(&ditto2), 1).await;
Ok(())
}
#[tokio::test]
async fn database_id_must_be_a_uuid_with_online_with_authentication() -> Result<()> {
assert!(get_ditto(Some(DatabaseId::from_str("hello")?), true).is_err());
assert!(get_ditto(Some(DatabaseId::from_str("HELLO")?), true).is_err());
assert!(get_ditto(Some(DatabaseId::from_str("E4CAB6FB-6B3F")?), true).is_err());
assert!(get_ditto(
Some(DatabaseId::from_str(
"E4CAB6FB_6B3F_4173_95EB_B5162034C235"
)?),
true,
)
.is_err(),);
assert!(get_ditto(
Some(DatabaseId::from_str(
"E4CAB6FB-6B3F-4173-95EB-B5162034C235"
)?),
true,
)
.is_ok(),);
assert!(get_ditto(
Some(DatabaseId::from_str(
"e4cab6fb-6b3f-4173-95eb-b5162034c235"
)?),
true,
)
.is_ok());
assert!(get_ditto(
Some(DatabaseId::from_str(
"E4CAB6FB-6b3f-4173-95eb-b5162034c235"
)?),
true,
)
.is_ok());
Ok(())
}
async fn assert_connected_peers(ditto: Arc<Ditto>, count: usize) {
let f = tokio::spawn(async move {
let mut cur_peers = 0;
for _ in 0..10 {
cur_peers = ditto.presence().graph().remote_peers.len();
if cur_peers == count {
return Ok(());
}
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
Err(cur_peers)
});
let result = tokio::time::timeout(std::time::Duration::from_secs(11), f)
.await
.unwrap()
.unwrap();
if let Err(peers_count) = result {
panic!("Expected {count} connected peer(s), got {peers_count}");
}
}