#[cfg(test)]
mod tests {
use crate::SyncResult;
use crate::coordinator::{DeviceStatus, SyncCoordinator};
use crate::crdt::{Crdt, GCounter, OrSet};
use crate::merkle::MerkleTree;
use crate::vector_clock::VectorClock;
#[test]
fn test_basic_two_device_sync() -> SyncResult<()> {
let coord1 = SyncCoordinator::new("device-1".to_string());
let coord2_id = "device-2".to_string();
coord1.register_device(coord2_id.clone())?;
let session = coord1.start_sync_session(coord2_id.clone())?;
assert!(!session.is_completed());
coord1.complete_sync_session(&session.session_id)?;
let device1 = coord1
.get_device(&"device-1".to_string())
.ok_or_else(|| crate::SyncError::InvalidDeviceId("device-1".to_string()))?;
assert_eq!(device1.status, DeviceStatus::Online);
Ok(())
}
#[test]
fn test_multi_device_coordination() -> SyncResult<()> {
let coordinator = SyncCoordinator::new("central".to_string());
for i in 1..=5 {
coordinator.register_device(format!("device-{}", i))?;
}
assert_eq!(coordinator.list_devices().len(), 6);
for i in 1..=5 {
coordinator.update_device_status(&format!("device-{}", i), DeviceStatus::Online)?;
}
let online = coordinator.list_online_devices();
assert_eq!(online.len(), 6);
Ok(())
}
#[test]
fn test_sync_with_delta_encoding() -> SyncResult<()> {
let coordinator = SyncCoordinator::new("device-1".to_string());
let base_data = b"Hello, world! This is a test document with some content.";
let target_data = b"Hello, world! This is a modified test document with updated content.";
let delta = coordinator.create_delta(base_data, target_data)?;
let result = coordinator.apply_delta(base_data, &delta)?;
assert_eq!(result, target_data);
Ok(())
}
#[test]
fn test_merkle_tree_sync_protocol() -> SyncResult<()> {
let device1_blocks: Vec<Vec<u8>> = vec![
b"block-1".to_vec(),
b"block-2".to_vec(),
b"block-3".to_vec(),
b"block-4".to_vec(),
];
let mut device2_blocks = device1_blocks.clone();
device2_blocks[2] = b"block-3-modified".to_vec();
let tree1 = MerkleTree::from_data(device1_blocks.clone())?;
let tree2 = MerkleTree::from_data(device2_blocks)?;
let differences = tree1.diff(&tree2);
assert!(!differences.is_empty());
Ok(())
}
#[test]
fn test_concurrent_edit_scenario() -> SyncResult<()> {
let mut doc1 = OrSet::new("device-1".to_string());
let mut doc2 = OrSet::new("device-2".to_string());
doc1.insert("para-1".to_string());
doc1.insert("para-2".to_string());
doc2.insert("para-1".to_string());
doc2.insert("para-2".to_string());
doc1.insert("para-3".to_string());
doc1.remove(&"para-2".to_string());
doc2.insert("para-4".to_string());
doc2.remove(&"para-1".to_string());
doc1.merge(&doc2)?;
assert!(doc1.contains(&"para-3".to_string()));
assert!(doc1.contains(&"para-4".to_string()));
Ok(())
}
#[test]
fn test_offline_online_sync() -> SyncResult<()> {
let coordinator = SyncCoordinator::new("server".to_string());
coordinator.register_device("mobile".to_string())?;
coordinator.register_device("desktop".to_string())?;
coordinator.update_device_status(&"mobile".to_string(), DeviceStatus::Online)?;
coordinator.update_device_status(&"desktop".to_string(), DeviceStatus::Offline)?;
let online = coordinator.list_online_devices();
assert_eq!(online.len(), 2);
coordinator.update_device_status(&"desktop".to_string(), DeviceStatus::Online)?;
let online = coordinator.list_online_devices();
assert_eq!(online.len(), 3);
Ok(())
}
#[test]
fn test_vector_clock_sync_ordering() {
let mut clock1 = VectorClock::new("device-1".to_string());
let mut clock2 = VectorClock::new("device-2".to_string());
clock1.tick(); clock2.merge(&clock1);
clock2.tick(); clock1.merge(&clock2);
clock1.tick();
assert!(clock1.happened_after(&clock2));
}
#[test]
fn test_conflict_free_counter_updates() -> SyncResult<()> {
let devices = ["dev1", "dev2", "dev3", "dev4", "dev5"];
let mut counters: Vec<GCounter> = devices
.iter()
.map(|d| GCounter::new(d.to_string()))
.collect();
for (i, counter) in counters.iter_mut().enumerate() {
for _ in 0..(i + 1) * 5 {
counter.increment(1);
}
}
for i in 1..counters.len() {
let counter_i = counters[i].clone();
counters[0].merge(&counter_i)?;
}
let expected = 5 + 10 + 15 + 20 + 25; assert_eq!(counters[0].value(), expected);
Ok(())
}
#[test]
fn test_session_tracking() -> SyncResult<()> {
let coordinator = SyncCoordinator::new("device-1".to_string());
coordinator.register_device("device-2".to_string())?;
let session1 = coordinator.start_sync_session("device-2".to_string())?;
assert_eq!(coordinator.active_sessions().len(), 1);
coordinator.complete_sync_session(&session1.session_id)?;
assert_eq!(coordinator.active_sessions().len(), 0);
assert_eq!(coordinator.completed_sessions().len(), 1);
Ok(())
}
#[test]
fn test_large_scale_sync() -> SyncResult<()> {
let coordinator = SyncCoordinator::new("master".to_string());
for i in 0..100 {
coordinator.register_device(format!("device-{}", i))?;
coordinator.update_device_status(&format!("device-{}", i), DeviceStatus::Online)?;
}
assert_eq!(coordinator.list_online_devices().len(), 101);
Ok(())
}
}