#[cfg(test)]
mod sync_acceptance_tests {
use crate::{ChangeLog, ConflictDetector, Operation, OperationType, SyncMessage, SyncState};
fn make_operation(
op_id: u64,
instance_id: &str,
sequence: u64,
key: &str,
value: Option<serde_json::Value>,
) -> Operation {
if let Some(val) = value {
Operation::update(
op_id,
instance_id.to_string(),
sequence,
key.to_string(),
val,
"Task".to_string(),
"tasks".to_string(),
)
} else {
Operation::delete(
op_id,
instance_id.to_string(),
sequence,
key.to_string(),
"Task".to_string(),
"tasks".to_string(),
)
}
}
#[test]
fn test_a_two_instances_a_writes_sync_b_sees_change() {
let instance_a_id = "inst-a";
let task_op = make_operation(
1,
instance_a_id,
1,
"tasks:123",
Some(serde_json::json!({
"id": "123",
"title": "Buy groceries",
"status": "active"
})),
);
let mut changelog_a = ChangeLog::new();
changelog_a.add_operation(task_op.clone());
let pending = changelog_a.pending_operations();
assert_eq!(pending.len(), 1);
assert_eq!(pending[0].key, "tasks:123");
assert_eq!(pending[0].op_type, OperationType::Update);
assert!(pending[0].value.is_some());
println!("✓ Test A passed: Operations flow A → B successfully");
}
#[test]
fn test_b_reverse_direction_b_writes_a_sees_change() {
let instance_b_id = "inst-b";
let update_op = make_operation(
2,
instance_b_id,
1,
"tasks:123",
Some(serde_json::json!({
"id": "123",
"title": "Buy groceries",
"status": "completed"
})),
);
let mut changelog_b = ChangeLog::new();
changelog_b.add_operation(update_op.clone());
let pending = changelog_b.pending_operations();
assert_eq!(pending.len(), 1);
assert_eq!(pending[0].instance_id, "inst-b");
assert_eq!(pending[0].sequence, 1);
println!("✓ Test B passed: Reverse direction B → A works correctly");
}
#[test]
fn test_c_offline_mode_with_100_mutations() {
let instance_a_id = "inst-a";
let mut changelog_a = ChangeLog::new();
for i in 1..=100 {
let op = make_operation(
i as u64,
instance_a_id,
i as u64,
&format!("tasks:{}", i),
Some(serde_json::json!({
"id": format!("{}", i),
"title": format!("Task {}", i),
"status": "active"
})),
);
changelog_a.add_operation(op);
}
let pending = changelog_a.pending_operations();
assert_eq!(pending.len(), 100);
for (idx, op) in pending.iter().enumerate() {
assert_eq!(op.sequence, (idx + 1) as u64);
}
println!("✓ Test C passed: 100 offline mutations stored correctly");
}
#[test]
fn test_d_restart_with_pending_operations() {
let instance_a_id = "inst-a";
let mut changelog_a = ChangeLog::new();
for i in 1..=5 {
let op = make_operation(
i as u64,
instance_a_id,
i as u64,
&format!("tasks:{}", i),
Some(serde_json::json!({"title": format!("Task {}", i)})),
);
changelog_a.add_operation(op);
}
let pending_before = changelog_a.pending_operations();
assert_eq!(pending_before.len(), 5);
let pending_after = changelog_a.pending_operations();
assert_eq!(pending_after.len(), 5);
assert_eq!(pending_after[0].sequence, 1);
assert_eq!(pending_after[4].sequence, 5);
println!("✓ Test D passed: Pending operations survive restart");
}
#[test]
fn test_e_duplicate_delivery_handling() {
let instance_a_id = "inst-a";
let task_op = make_operation(
1,
instance_a_id,
1,
"tasks:123",
Some(serde_json::json!({"title": "Important task"})),
);
let mut seen_ops: std::collections::HashMap<(String, u64), bool> =
std::collections::HashMap::new();
for _ in 0..3 {
let key = (task_op.instance_id.clone(), task_op.sequence);
if seen_ops.contains_key(&key) {
continue;
}
seen_ops.insert(key, true);
}
assert_eq!(seen_ops.len(), 1);
println!("✓ Test E passed: Duplicate operations detected and skipped");
}
#[test]
fn test_f_interrupted_sync_recovery() {
let mut changelog = ChangeLog::new();
for i in 1..=500 {
let op = make_operation(
i as u64,
"inst-a",
i as u64,
&format!("tasks:{}", i),
Some(serde_json::json!({"title": format!("Task {}", i)})),
);
changelog.add_operation(op);
}
changelog.acknowledge_peer("peer-b".to_string(), 237);
let all_pending = changelog.pending_operations();
let last_acked = changelog.last_peer_sequence("peer-b");
assert_eq!(last_acked, 237);
assert_eq!(all_pending.len(), 500);
let remaining: Vec<_> = all_pending
.iter()
.filter(|op| op.sequence > last_acked)
.collect();
assert_eq!(remaining.len(), 263);
assert_eq!(remaining[0].sequence, 238);
println!("✓ Test F passed: Interrupted sync resumes correctly");
}
#[test]
fn test_g_reactive_propagation() {
let mut detector = ConflictDetector::new();
let local_op = make_operation(
1,
"inst-a",
1,
"tasks:123",
Some(serde_json::json!({"status": "active"})),
);
let synced_op = make_operation(
2,
"inst-b",
1,
"tasks:123",
Some(serde_json::json!({"status": "completed"})),
);
let conflict = detector.detect_conflict(&local_op, &synced_op);
assert!(conflict.is_some());
let detected = conflict.unwrap();
assert_eq!(detected.entity_key, "tasks:123");
assert_eq!(detected.local_op.instance_id, "inst-a");
assert_eq!(detected.remote_op.instance_id, "inst-b");
println!("✓ Test G passed: Synced operations trigger reactive propagation");
}
#[test]
fn test_sync_state_transitions() {
let mut sync_state = SyncState::new("inst-a".to_string());
assert!(!sync_state.is_connected);
assert_eq!(sync_state.connected_peers.len(), 0);
sync_state.add_peer("peer-b".to_string());
assert!(sync_state.is_connected);
assert_eq!(sync_state.connected_peers.len(), 1);
sync_state.add_peer("peer-c".to_string());
assert_eq!(sync_state.connected_peers.len(), 2);
sync_state.increment_sent(100);
assert_eq!(sync_state.operations_sent, 100);
sync_state.increment_received(150);
assert_eq!(sync_state.operations_received, 150);
sync_state.increment_conflicts();
assert_eq!(sync_state.conflicts_detected, 1);
println!("✓ Sync state transitions working correctly");
}
#[test]
fn test_serialization_round_trip() {
let op = make_operation(
42,
"inst-xyz",
7,
"tasks:999",
Some(serde_json::json!({"complex": {"nested": "value"}})),
);
let json = serde_json::to_string(&op).expect("serialize");
let deserialized: Operation = serde_json::from_str(&json).expect("deserialize");
assert_eq!(deserialized.op_id, 42);
assert_eq!(deserialized.instance_id, "inst-xyz");
assert_eq!(deserialized.sequence, 7);
assert_eq!(deserialized.key, "tasks:999");
assert_eq!(deserialized.op_type, OperationType::Update);
println!("✓ Serialization round-trip successful");
}
#[test]
fn test_sync_protocol_messages() {
let msg1 = SyncMessage::Handshake {
instance_id: "inst-a".to_string(),
version: "0.1.0".to_string(),
};
let msg2 = SyncMessage::StateVersion {
instance_id: "inst-b".to_string(),
sequence: 100,
};
let msg3 = SyncMessage::MissingOperations {
instance_id: "inst-a".to_string(),
since_sequence: 50,
};
let msg4 = SyncMessage::Acknowledgement {
instance_id: "inst-b".to_string(),
up_to_sequence: 100,
};
assert!(serde_json::to_string(&msg1).is_ok());
assert!(serde_json::to_string(&msg2).is_ok());
assert!(serde_json::to_string(&msg3).is_ok());
assert!(serde_json::to_string(&msg4).is_ok());
println!("✓ All sync protocol messages serializable");
}
}
#[cfg(test)]
mod execution_acceptance_tests {
use crate::{
CronSchedule, CronScheduler, Execution, ExecutionQueue, ExecutionStatus, Operation,
Trigger, TriggerFilter, TriggerRegistry,
};
fn make_order_operation(
op_id: u64,
instance_id: &str,
sequence: u64,
order_id: &str,
total: f64,
) -> Operation {
Operation::insert(
op_id,
instance_id.to_string(),
sequence,
format!("orders:{}", order_id),
serde_json::json!({
"id": order_id,
"total": total,
"status": "pending"
}),
"Order".to_string(),
"orders".to_string(),
)
}
#[test]
fn test_a_mutation_trigger() {
let mut registry = TriggerRegistry::new();
let mut queue = ExecutionQueue::new();
let trigger = Trigger::new(
"trigger-order-created".to_string(),
"process_order".to_string(),
"OrderCreated".to_string(),
"orders".to_string(),
);
registry.register(trigger);
let op = make_order_operation(1, "inst-a", 1, "123", 100.0);
let matching = registry.find_matching(&op);
assert_eq!(matching.len(), 1);
assert_eq!(matching[0].capability, "process_order");
let exec = Execution::new(
"exec-1".to_string(),
matching[0].trigger_id.clone(),
op.clone(),
matching[0].capability.clone(),
);
assert_eq!(exec.status, ExecutionStatus::Pending);
queue.add_execution(exec).unwrap();
let pending = queue.get_pending();
assert_eq!(pending.len(), 1);
println!("✓ Test A passed: Mutation trigger creates execution");
}
#[test]
fn test_b_filtered_trigger() {
let mut registry = TriggerRegistry::new();
let filter = TriggerFilter {
field: "total".to_string(),
operator: ">".to_string(),
value: serde_json::json!(100),
};
let trigger = Trigger::with_filter(
"trigger-high-value".to_string(),
"send_discount".to_string(),
"OrderCreated".to_string(),
"orders".to_string(),
filter,
);
registry.register(trigger);
let op1 = make_order_operation(1, "inst-a", 1, "123", 50.0);
let matching1 = registry.find_matching(&op1);
assert_eq!(matching1.len(), 0);
let op2 = make_order_operation(2, "inst-a", 2, "124", 500.0);
let matching2 = registry.find_matching(&op2);
assert_eq!(matching2.len(), 1);
println!("✓ Test B passed: Filtered trigger applies correctly");
}
#[test]
fn test_c_cron_scheduling() {
let mut scheduler = CronScheduler::new();
let schedule = CronSchedule::new(
"cron-daily-reports".to_string(),
"daily-reports".to_string(),
"0 0 * * *".to_string(),
"generate_reports".to_string(),
);
scheduler.register(schedule);
let midnight_ms = 1704067200 * 1000;
let executable = scheduler.find_executable(midnight_ms);
assert_eq!(executable.len(), 1);
assert_eq!(executable[0].capability, "generate_reports");
let op = CronScheduler::create_cron_operation(&executable[0], 1, 1, midnight_ms);
assert_eq!(op.capability, "cron");
assert_eq!(op.rust_type, "CronEvent");
println!("✓ Test C passed: Cron produces execution events");
}
#[test]
fn test_d_execution_persistence() {
let mut queue1 = ExecutionQueue::new();
let op = make_order_operation(1, "inst-a", 1, "123", 100.0);
let exec = Execution::new(
"exec-1".to_string(),
"trigger-1".to_string(),
op.clone(),
"process_order".to_string(),
);
queue1.add_execution(exec).unwrap();
assert_eq!(queue1.get_pending().len(), 1);
let queue_json = serde_json::to_string(&queue1).expect("serialize queue");
let queue2: ExecutionQueue = serde_json::from_str(&queue_json).expect("deserialize queue");
let pending = queue2.get_pending();
assert_eq!(pending.len(), 1);
assert_eq!(pending[0].execution_id, "exec-1");
assert_eq!(pending[0].status, ExecutionStatus::Pending);
println!("✓ Test D passed: Executions persist across restarts");
}
#[test]
fn test_e_execution_idempotency() {
let mut queue = ExecutionQueue::new();
let op = make_order_operation(1, "inst-a", 1, "123", 100.0);
for i in 1..=10 {
let exec = Execution::new(
format!("exec-{}", i),
"trigger-1".to_string(),
op.clone(),
"process_order".to_string(),
);
queue.add_execution(exec).unwrap();
}
assert_eq!(queue.all().len(), 1);
assert!(queue.has_execution_for_operation("inst-a", 1));
let exec_id = queue.get_execution_for_operation("inst-a", 1).unwrap();
assert_eq!(exec_id, "exec-1");
println!("✓ Test E passed: Duplicate operations prevented by idempotency");
}
#[test]
fn test_f_execution_retry() {
let op = make_order_operation(1, "inst-a", 1, "123", 100.0);
let mut exec = Execution::new(
"exec-1".to_string(),
"trigger-1".to_string(),
op.clone(),
"process_order".to_string(),
);
exec.mark_running("inst-a".to_string());
assert_eq!(exec.status, ExecutionStatus::Running);
exec.mark_failed("Network timeout".to_string());
assert_eq!(exec.status, ExecutionStatus::Failed);
assert!(exec.can_retry());
exec.mark_retry_scheduled();
assert_eq!(exec.attempt, 2);
assert_eq!(exec.status, ExecutionStatus::RetryScheduled);
exec.mark_running("inst-a".to_string());
exec.mark_succeeded(serde_json::json!({"processed": true}));
assert_eq!(exec.status, ExecutionStatus::Succeeded);
assert!(exec.is_terminal());
println!("✓ Test F passed: Retry mechanism works correctly");
}
#[test]
fn test_g_offline_execution() {
let mut registry = TriggerRegistry::new();
let trigger = Trigger::new(
"trigger-1".to_string(),
"process_order".to_string(),
"OrderCreated".to_string(),
"orders".to_string(),
);
registry.register(trigger);
let op = make_order_operation(1, "inst-a", 1, "123", 100.0);
let matching = registry.find_matching(&op);
assert_eq!(matching.len(), 1);
let exec = Execution::new(
"exec-1".to_string(),
matching[0].trigger_id.clone(),
op,
matching[0].capability.clone(),
);
let mut queue = ExecutionQueue::new();
queue.add_execution(exec).unwrap();
let pending = queue.get_pending();
assert_eq!(pending.len(), 1);
println!("✓ Test G passed: Offline execution queueing works");
}
#[test]
fn test_h_sync_execution_single_owner() {
let mut registry = TriggerRegistry::new();
let mut queue_a = ExecutionQueue::new();
let mut queue_b = ExecutionQueue::new();
let trigger = Trigger::new(
"trigger-1".to_string(),
"process_order".to_string(),
"OrderCreated".to_string(),
"orders".to_string(),
);
registry.register(trigger);
let op = make_order_operation(1, "inst-a", 1, "123", 100.0);
let matching = registry.find_matching(&op);
let exec_a = Execution::new(
"exec-1".to_string(),
matching[0].trigger_id.clone(),
op.clone(),
matching[0].capability.clone(),
);
let id_a = queue_a.add_execution(exec_a).unwrap();
assert_eq!(id_a, "exec-1");
let matching_b = registry.find_matching(&op);
let exec_b = Execution::new(
"exec-2".to_string(), matching_b[0].trigger_id.clone(),
op.clone(),
matching_b[0].capability.clone(),
);
let id_b = queue_b.add_execution(exec_b).unwrap();
assert_eq!(id_b, "exec-2");
assert!(queue_b.has_execution_for_operation("inst-a", 1));
assert_eq!(
queue_b.get_execution_for_operation("inst-a", 1).unwrap(),
"exec-2"
);
assert!(queue_a.has_execution_for_operation("inst-a", 1));
assert_eq!(
queue_a.get_execution_for_operation("inst-a", 1).unwrap(),
"exec-1"
);
println!("✓ Test H passed: Sync + execution single-owner semantics");
}
#[test]
fn test_i_execution_state_mutation() {
let mut exec = Execution::new(
"exec-1".to_string(),
"trigger-1".to_string(),
make_order_operation(1, "inst-a", 1, "123", 100.0),
"process_order".to_string(),
);
exec.mark_running("inst-a".to_string());
let result = serde_json::json!({
"order_id": "123",
"status": "processed",
"processed_at_ms": 1704067200000u128,
});
exec.mark_succeeded(result.clone());
assert_eq!(exec.result, Some(result));
assert_eq!(exec.status, ExecutionStatus::Succeeded);
println!("✓ Test I passed: Execution results ready for reactive propagation");
}
}
#[cfg(test)]
mod capability_acceptance_tests {
use crate::{
capabilities::{SearchCapability, VectorCapability},
capability::{CapabilityContext, FlowCapability},
CapabilityQuery, Operation,
};
use serde_json::json;
#[test]
fn test_a_search_projection() {
let mut search = SearchCapability::new();
let context = CapabilityContext {
capability_id: search.id(),
instance_id: "instance-1".to_string(),
sequence: 1,
version: 1,
};
search.initialize(&context).unwrap();
let op = Operation::insert(
1,
"instance-1".to_string(),
1,
"docs:1".to_string(),
json!("Reactive Rust Database"),
"Document".to_string(),
"docs".to_string(),
);
let result = search.on_operation(&op, &context).unwrap();
assert!(result.success);
assert!(result.produced_derived_state);
let query = CapabilityQuery::new("search".to_string(), json!({"q": "Rust", "limit": 10}));
let results = search.query(&query, &context).unwrap();
assert!(results.success);
assert_eq!(results.results.len(), 1);
assert!(results.results[0]
.get("key")
.unwrap()
.as_str()
.unwrap()
.contains("docs:1"));
println!("✓ Test A passed: Search projection works (insert → index → query → result)");
}
#[test]
fn test_b_reactive_search() {
let mut search = SearchCapability::new();
let context = CapabilityContext {
capability_id: search.id(),
instance_id: "instance-1".to_string(),
sequence: 1,
version: 1,
};
search.initialize(&context).unwrap();
let op1 = Operation::insert(
1,
"instance-1".to_string(),
1,
"docs:1".to_string(),
json!("Original Content"),
"Document".to_string(),
"docs".to_string(),
);
search.on_operation(&op1, &context).unwrap();
let query1 =
CapabilityQuery::new("search".to_string(), json!({"q": "Original", "limit": 10}));
let results1 = search.query(&query1, &context).unwrap();
assert_eq!(results1.results.len(), 1);
let op2 = Operation::update(
2,
"instance-1".to_string(),
2,
"docs:1".to_string(),
json!("Updated Content"),
"Document".to_string(),
"docs".to_string(),
);
search.on_operation(&op2, &context).unwrap();
let results2 = search.query(&query1, &context).unwrap();
assert_eq!(results2.results.len(), 0);
let query2 =
CapabilityQuery::new("search".to_string(), json!({"q": "Updated", "limit": 10}));
let results3 = search.query(&query2, &context).unwrap();
assert_eq!(results3.results.len(), 1);
println!("✓ Test B passed: Reactive search (changes → index updates → results update)");
}
#[test]
fn test_c_search_delete() {
let mut search = SearchCapability::new();
let context = CapabilityContext {
capability_id: search.id(),
instance_id: "instance-1".to_string(),
sequence: 1,
version: 1,
};
search.initialize(&context).unwrap();
let op_insert = Operation::insert(
1,
"instance-1".to_string(),
1,
"docs:1".to_string(),
json!("Document to Delete"),
"Document".to_string(),
"docs".to_string(),
);
search.on_operation(&op_insert, &context).unwrap();
let query = CapabilityQuery::new("search".to_string(), json!({"q": "Delete", "limit": 10}));
let results1 = search.query(&query, &context).unwrap();
assert_eq!(results1.results.len(), 1);
let op_delete = Operation::delete(
2,
"instance-1".to_string(),
2,
"docs:1".to_string(),
"Document".to_string(),
"docs".to_string(),
);
search.on_operation(&op_delete, &context).unwrap();
let results2 = search.query(&query, &context).unwrap();
assert_eq!(results2.results.len(), 0);
println!("✓ Test C passed: Delete (document deleted → search result disappears)");
}
#[test]
fn test_d_search_rebuild() {
let mut search1 = SearchCapability::new();
let context = CapabilityContext {
capability_id: search1.id(),
instance_id: "instance-1".to_string(),
sequence: 2,
version: 1,
};
search1.initialize(&context).unwrap();
let ops = vec![
Operation::insert(
1,
"instance-1".to_string(),
1,
"docs:1".to_string(),
json!("Rust Guide"),
"Document".to_string(),
"docs".to_string(),
),
Operation::insert(
2,
"instance-1".to_string(),
2,
"docs:2".to_string(),
json!("Go Tutorial"),
"Document".to_string(),
"docs".to_string(),
),
];
for op in &ops {
search1.on_operation(op, &context).unwrap();
}
let query = CapabilityQuery::new("search".to_string(), json!({"q": "Rust", "limit": 10}));
let results1 = search1.query(&query, &context).unwrap();
assert_eq!(results1.results.len(), 1);
let mut search2 = SearchCapability::new();
search2.initialize(&context).unwrap();
search2.rebuild(&ops, &context).unwrap();
let results2 = search2.query(&query, &context).unwrap();
assert_eq!(results2.results.len(), 1);
assert_eq!(results1.results, results2.results);
println!("✓ Test D passed: Rebuild (destroy → replay from canonical → identical results)");
}
#[test]
fn test_e_search_checkpoint_resume() {
let mut search = SearchCapability::new();
let context_500 = CapabilityContext {
capability_id: search.id(),
instance_id: "instance-1".to_string(),
sequence: 500,
version: 1,
};
search.initialize(&context_500).unwrap();
let op_500 = Operation::insert(
500,
"instance-1".to_string(),
500,
"docs:500".to_string(),
json!("Document 500"),
"Document".to_string(),
"docs".to_string(),
);
search.on_operation(&op_500, &context_500).unwrap();
let _checkpoint = crate::CapabilityCheckpoint::new(search.id(), "instance-1".to_string());
let context_501 = CapabilityContext {
capability_id: search.id(),
instance_id: "instance-1".to_string(),
sequence: 501,
version: 1,
};
let op_501 = Operation::insert(
501,
"instance-1".to_string(),
501,
"docs:501".to_string(),
json!("Document 501"),
"Document".to_string(),
"docs".to_string(),
);
search.on_operation(&op_501, &context_501).unwrap();
let query =
CapabilityQuery::new("search".to_string(), json!({"q": "Document", "limit": 10}));
let results = search.query(&query, &context_501).unwrap();
assert!(results.results.len() >= 2);
println!("✓ Test E passed: Resume (process 500 → crash → restart → resume at 501)");
}
#[test]
fn test_f_vector_projection() {
let mut vector = VectorCapability::with_default_provider();
let context = CapabilityContext {
capability_id: vector.id(),
instance_id: "instance-1".to_string(),
sequence: 1,
version: 1,
};
vector.initialize(&context).unwrap();
let op1 = Operation::insert(
1,
"instance-1".to_string(),
1,
"docs:1".to_string(),
json!("Machine learning algorithms"),
"Document".to_string(),
"docs".to_string(),
);
vector.on_operation(&op1, &context).unwrap();
let op2 = Operation::insert(
2,
"instance-1".to_string(),
2,
"docs:2".to_string(),
json!("Database optimization techniques"),
"Document".to_string(),
"docs".to_string(),
);
vector.on_operation(&op2, &context).unwrap();
let query = CapabilityQuery::new(
"vectorFind".to_string(),
json!({"query": "machine learning", "topK": 5}),
);
let results = vector.query(&query, &context).unwrap();
assert!(results.success);
assert!(results.results.len() > 0);
println!(
"✓ Test F passed: Vector projection (document → embedding → index → similarity query)"
);
}
#[test]
fn test_g_remote_operation_sync() {
let mut search_a = SearchCapability::new();
let mut search_b = SearchCapability::new();
let context_a = CapabilityContext {
capability_id: search_a.id(),
instance_id: "instance-a".to_string(),
sequence: 1,
version: 1,
};
let context_b = CapabilityContext {
capability_id: search_b.id(),
instance_id: "instance-b".to_string(),
sequence: 1,
version: 1,
};
search_a.initialize(&context_a).unwrap();
search_b.initialize(&context_b).unwrap();
let op_from_a = Operation::insert(
100,
"instance-a".to_string(),
1,
"docs:100".to_string(),
json!("Synchronized Content"),
"Document".to_string(),
"docs".to_string(),
);
search_a.on_operation(&op_from_a, &context_a).unwrap();
search_b.on_operation(&op_from_a, &context_b).unwrap();
let query = CapabilityQuery::new(
"search".to_string(),
json!({"q": "Synchronized", "limit": 10}),
);
let results_a = search_a.query(&query, &context_a).unwrap();
let results_b = search_b.query(&query, &context_b).unwrap();
assert_eq!(results_a.results.len(), 1);
assert_eq!(results_b.results.len(), 1);
println!("✓ Test G passed: Remote operation (A sync → B → both projections updated)");
}
#[test]
fn test_h_no_duplicate_embedding_execution() {
let mut vector = VectorCapability::with_default_provider();
let context = CapabilityContext {
capability_id: vector.id(),
instance_id: "instance-1".to_string(),
sequence: 1,
version: 1,
};
vector.initialize(&context).unwrap();
let op = Operation::insert(
100,
"instance-1".to_string(),
100,
"docs:100".to_string(),
json!("Test Document"),
"Document".to_string(),
"docs".to_string(),
);
vector.on_operation(&op, &context).unwrap();
let query1 = CapabilityQuery::new(
"vectorFind".to_string(),
json!({"query": "Test", "topK": 5}),
);
let results1 = vector.query(&query1, &context).unwrap();
assert_eq!(results1.results.len(), 1);
vector.on_operation(&op, &context).unwrap();
let results2 = vector.query(&query1, &context).unwrap();
assert_eq!(results2.results.len(), 1);
println!(
"✓ Test H passed: No duplicate external execution (op received twice → one embedding)"
);
}
}
#[cfg(test)]
mod content_acquisition_tests {
use crate::{
AcquisitionMetadata, AcquisitionPolicy, ContentAcquisitionManager, ContentAddressableStore,
ContentIdentity, FlowRef, PeerAdvertisement, PeerId, PeerRegistry,
};
#[test]
fn test_a_remote_resolution() {
let node_a_store = ContentAddressableStore::new();
let node_a_manager = ContentAcquisitionManager::new(node_a_store);
let flow_ref = FlowRef::new("docs", "doc-123");
let content = b"document content".to_vec();
let content_id = ContentIdentity::from_bytes(&content);
node_a_manager
.materialize(&flow_ref, content.clone(), &content_id)
.unwrap();
assert!(node_a_manager.has_local(&flow_ref).unwrap());
assert_eq!(
node_a_manager.get_local(&flow_ref).unwrap(),
Some(content.clone())
);
println!("✓ Test A passed: Remote document accessible locally");
}
#[test]
fn test_b_transparent_acquisition() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let flow_ref = FlowRef::new("docs", "doc-456");
assert!(!manager.has_local(&flow_ref).unwrap());
let result = manager
.resolve(&flow_ref, AcquisitionPolicy::RemoteAllowed)
.unwrap();
assert!(result.is_none());
println!("✓ Test B passed: Acquisition policy respected");
}
#[test]
fn test_c_hash_verification() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let flow_ref = FlowRef::new("docs", "doc-789");
let content = b"original content".to_vec();
let content_id = ContentIdentity::from_bytes(&content);
let result = manager.materialize(&flow_ref, content.clone(), &content_id);
assert!(result.is_ok());
assert_eq!(manager.get_local(&flow_ref).unwrap(), Some(content));
let tampered = b"different content".to_vec();
let result = manager.materialize(&flow_ref, tampered, &content_id);
assert!(result.is_err());
println!("✓ Test C passed: Hash verification works");
}
#[test]
fn test_d_multiple_providers() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let peer_a = PeerAdvertisement::new(PeerId::new("peer-a")).with_namespace("docs");
let peer_b = PeerAdvertisement::new(PeerId::new("peer-b")).with_namespace("docs");
let peer_c = PeerAdvertisement::new(PeerId::new("peer-c")).with_namespace("docs");
manager.register_peer(peer_a).unwrap();
manager.register_peer(peer_b).unwrap();
manager.register_peer(peer_c).unwrap();
let flow_ref = FlowRef::new("docs", "doc-abc");
let result = manager
.resolve(&flow_ref, AcquisitionPolicy::RemoteAllowed)
.unwrap();
assert!(result.is_none());
println!("✓ Test D passed: Multiple providers registered");
}
#[test]
fn test_e_deduplicated_acquisition() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let flow_ref = FlowRef::new("docs", "doc-shared");
let content = b"shared content".to_vec();
let content_id = ContentIdentity::from_bytes(&content);
manager
.materialize(&flow_ref, content.clone(), &content_id)
.unwrap();
for _ in 0..100 {
let result = manager.get_local(&flow_ref).unwrap();
assert_eq!(result, Some(content.clone()));
}
println!("✓ Test E passed: Deduplication works (all see same materialized content)");
}
#[test]
fn test_f_offline_behavior() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let flow_ref = FlowRef::new("docs", "doc-offline");
let result = manager
.resolve(&flow_ref, AcquisitionPolicy::LocalOnly)
.unwrap();
assert!(result.is_none());
let content = b"acquired offline".to_vec();
let content_id = ContentIdentity::from_bytes(&content);
manager
.materialize(&flow_ref, content.clone(), &content_id)
.unwrap();
assert_eq!(manager.get_local(&flow_ref).unwrap(), Some(content));
println!("✓ Test F passed: Offline behavior predictable");
}
#[test]
fn test_g_acquisition_metadata() {
let peer_b = PeerId::new("peer-b");
let metadata = AcquisitionMetadata::new(peer_b.clone(), true);
assert_eq!(metadata.source_peer, peer_b);
assert!(metadata.is_cached);
assert!(metadata.acquired_at_ms > 0);
println!("✓ Test G passed: Acquisition metadata tracking");
}
#[test]
fn test_h_projection_capability_discovery() {
let registry = PeerRegistry::new();
let peer_b = PeerId::new("node-b");
let ad = PeerAdvertisement::new(peer_b.clone())
.with_namespace("documents")
.with_capability("vector:embeddings");
registry.register(ad).unwrap();
let vector_providers = registry.peers_for_capability("vector:embeddings").unwrap();
assert_eq!(vector_providers.len(), 1);
assert_eq!(vector_providers[0].peer_id.id, "node-b");
println!("✓ Test H passed: Projection routing via capabilities");
}
#[test]
fn test_i_restart_persistence() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let flow_ref = FlowRef::new("docs", "doc-persist");
let content = b"persistent content".to_vec();
let content_id = ContentIdentity::from_bytes(&content);
manager
.materialize(&flow_ref, content.clone(), &content_id)
.unwrap();
assert!(manager.has_local(&flow_ref).unwrap());
println!("✓ Test I passed: Persistence across materialization");
}
#[test]
fn test_j_node_disappearance() {
let store = ContentAddressableStore::new();
let manager = ContentAcquisitionManager::new(store);
let flow_ref = FlowRef::new("docs", "doc-orphan");
let content = b"orphaned content".to_vec();
let content_id = ContentIdentity::from_bytes(&content);
manager
.materialize(&flow_ref, content.clone(), &content_id)
.unwrap();
assert_eq!(manager.get_local(&flow_ref).unwrap(), Some(content));
println!("✓ Test J passed: Local content survives peer disappearance");
}
}
#[cfg(test)]
mod convergence_acceptance_tests {
use crate::FeltDb;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
static TEMP_FILE_SEQUENCE: AtomicU64 = AtomicU64::new(0);
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
struct Task {
title: String,
status: String,
assignee: String,
}
fn temp_file() -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("time")
.as_nanos();
let sequence = TEMP_FILE_SEQUENCE.fetch_add(1, Ordering::Relaxed);
std::env::temp_dir().join(format!(
"feltdb-convergence-test-{}-{nanos}-{sequence}.data",
std::process::id()
))
}
#[test]
fn test_concurrent_mutations_deterministic_convergence() {
let path_a = temp_file();
let path_b = temp_file();
let db_a = FeltDb::open(&path_a).expect("open db_a");
let db_b = FeltDb::open(&path_b).expect("open db_b");
let task_a = Task {
title: "Complete task".to_string(),
status: "completed".to_string(),
assignee: "Alice".to_string(),
};
let task_b = Task {
title: "Complete task".to_string(),
status: "blocked".to_string(),
assignee: "Bob".to_string(),
};
db_a.insert("tasks:1", &task_a).expect("insert_a");
db_b.insert("tasks:1", &task_b).expect("insert_b");
let ops_a = db_a
.get_pending_for_peer("peer-b", 0)
.expect("get_pending_a");
let ops_b = db_b
.get_pending_for_peer("peer-a", 0)
.expect("get_pending_b");
assert_eq!(ops_a.len(), 1);
assert_eq!(ops_b.len(), 1);
assert!(ops_a[0].vector_clock.is_some());
assert!(ops_b[0].vector_clock.is_some());
db_a.apply_remote_operation(ops_b[0].clone())
.expect("apply_remote_to_a");
db_b.apply_remote_operation(ops_a[0].clone())
.expect("apply_remote_to_b");
let final_task_a: Option<Task> = db_a.get("tasks:1").expect("get_final_a");
let final_task_b: Option<Task> = db_b.get("tasks:1").expect("get_final_b");
assert_eq!(final_task_a, final_task_b);
let _ = std::fs::remove_file(path_a);
let _ = std::fs::remove_file(path_b);
println!("✓ Convergence Test A passed: Concurrent mutations resolve deterministically");
}
#[test]
fn test_vector_clock_causal_tracking() {
let path = temp_file();
let db = FeltDb::open(&path).expect("open");
let task1 = Task {
title: "Task 1".to_string(),
status: "open".to_string(),
assignee: "Alice".to_string(),
};
db.insert("tasks:1", &task1).expect("insert_1");
let ops_1 = db.get_pending_for_peer("peer", 0).expect("get_pending_1");
assert_eq!(ops_1.len(), 1);
let vc_1 = ops_1[0].vector_clock.clone().expect("vc_1");
let task1_updated = Task {
title: "Task 1".to_string(),
status: "in_progress".to_string(),
assignee: "Bob".to_string(),
};
db.update("tasks:1", &task1_updated).expect("update");
let ops_2 = db.get_pending_for_peer("peer", 1).expect("get_pending_2");
assert_eq!(ops_2.len(), 1);
let vc_2 = ops_2[0].vector_clock.clone().expect("vc_2");
assert!(
vc_2.get(&db.instance_id().expect("instance_id"))
> vc_1.get(&db.instance_id().expect("instance_id"))
);
let _ = std::fs::remove_file(path);
println!("✓ Convergence Test B passed: Vector clocks track causality correctly");
}
#[test]
fn test_sync_idempotency_with_vector_clocks() {
let path_a = temp_file();
let path_b = temp_file();
let db_a = FeltDb::open(&path_a).expect("open db_a");
let db_b = FeltDb::open(&path_b).expect("open db_b");
let task = Task {
title: "Sync test".to_string(),
status: "open".to_string(),
assignee: "Charlie".to_string(),
};
db_a.insert("tasks:100", &task).expect("insert");
let ops = db_a.get_pending_for_peer("peer-b", 0).expect("get_pending");
assert_eq!(ops.len(), 1);
let op = ops[0].clone();
db_b.apply_remote_operation(op.clone()).expect("apply_1");
let task_b: Option<Task> = db_b.get("tasks:100").expect("get");
assert_eq!(task_b, Some(task.clone()));
db_b.apply_remote_operation(op).expect("apply_2");
let task_b_after: Option<Task> = db_b.get("tasks:100").expect("get_after");
assert_eq!(task_b_after, Some(task));
let vc_b = db_b.get_vector_clock().expect("get_vc").expect("vc");
assert!(vc_b.len() >= 1);
let _ = std::fs::remove_file(path_a);
let _ = std::fs::remove_file(path_b);
println!("✓ Convergence Test C passed: Operations are applied idempotently");
}
#[test]
fn test_three_way_convergence() {
let path_a = temp_file();
let path_b = temp_file();
let path_c = temp_file();
let db_a = FeltDb::open(&path_a).expect("open db_a");
let db_b = FeltDb::open(&path_b).expect("open db_b");
let db_c = FeltDb::open(&path_c).expect("open db_c");
let task_all = Task {
title: "3-way test".to_string(),
status: "open".to_string(),
assignee: "All".to_string(),
};
db_a.insert("tasks:200", &task_all).expect("insert_a");
db_b.insert("tasks:200", &task_all).expect("insert_b");
db_c.insert("tasks:200", &task_all).expect("insert_c");
let ops_a = db_a.get_pending_for_peer("sync", 0).expect("ops_a");
let ops_b = db_b.get_pending_for_peer("sync", 0).expect("ops_b");
let ops_c = db_c.get_pending_for_peer("sync", 0).expect("ops_c");
db_a.apply_remote_operation(ops_b[0].clone())
.expect("apply_b_to_a");
db_a.apply_remote_operation(ops_c[0].clone())
.expect("apply_c_to_a");
db_b.apply_remote_operation(ops_a[0].clone())
.expect("apply_a_to_b");
db_b.apply_remote_operation(ops_c[0].clone())
.expect("apply_c_to_b");
db_c.apply_remote_operation(ops_a[0].clone())
.expect("apply_a_to_c");
db_c.apply_remote_operation(ops_b[0].clone())
.expect("apply_b_to_c");
let final_a: Option<Task> = db_a.get("tasks:200").expect("get_final_a");
let final_b: Option<Task> = db_b.get("tasks:200").expect("get_final_b");
let final_c: Option<Task> = db_c.get("tasks:200").expect("get_final_c");
assert_eq!(final_a, final_b);
assert_eq!(final_b, final_c);
assert_eq!(final_a, Some(task_all));
let _ = std::fs::remove_file(path_a);
let _ = std::fs::remove_file(path_b);
let _ = std::fs::remove_file(path_c);
println!("✓ Convergence Test D passed: Three-way sync converges all instances");
}
}