use std::time::Duration;
use d_engine_core::ClientApi;
use d_engine_server::EmbeddedEngine;
use tempfile::TempDir;
use tracing_test::traced_test;
use crate::common::get_available_ports;
async fn create_test_engine_with_lease(test_name: &str) -> (EmbeddedEngine, TempDir) {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let db_path = temp_dir.path().join(test_name);
let config_path = temp_dir.path().join("d-engine.toml");
let mut port_guard = get_available_ports(1).await;
port_guard.release_listeners();
let port = port_guard.as_slice()[0];
let config_content = format!(
r#"
[cluster]
listen_address = "127.0.0.1:{}"
db_root_dir = "{}"
single_node = true
[raft.state_machine.lease]
enabled = true
[raft.read_consistency]
state_machine_sync_timeout_ms = 2000
"#,
port,
db_path.display()
);
std::fs::write(&config_path, config_content).expect("Failed to write config");
let engine = EmbeddedEngine::start_with(config_path.to_str().unwrap())
.await
.expect("Failed to start engine");
engine.wait_ready(Duration::from_secs(5)).await.expect("Engine not ready");
(engine, temp_dir)
}
#[tokio::test]
#[traced_test]
async fn test_lease_read_with_valid_lease() {
let (engine, _temp_dir) = create_test_engine_with_lease("lease_valid").await;
assert!(engine.is_leader(), "Single-node cluster should be leader");
let client = engine.client();
client.put(b"lease_key_1", b"lease_value_1").await.expect("PUT failed");
tokio::time::sleep(Duration::from_millis(100)).await;
let result = client.get_lease(b"lease_key_1").await.expect("Lease read failed");
assert_eq!(
result.as_deref(),
Some(b"lease_value_1".as_ref()),
"Lease read should return committed value"
);
println!("✅ Lease read with valid lease succeeded (local read path)");
}
#[tokio::test]
#[traced_test]
async fn test_lease_read_consistency_across_writes() {
let (engine, _temp_dir) = create_test_engine_with_lease("lease_consistency").await;
let client = engine.client();
for i in 1..=5 {
let value = format!("value_{i}");
client.put(b"seq_key", value.as_bytes()).await.expect("PUT failed");
tokio::time::sleep(Duration::from_millis(100)).await;
let result = client.get_lease(b"seq_key").await.expect("Lease read failed");
assert_eq!(
result.as_deref(),
Some(value.as_bytes()),
"Lease read should see value_{i}"
);
}
println!("✅ Lease read consistency verified across 5 sequential writes");
}
#[tokio::test]
#[traced_test]
async fn test_lease_vs_linearizable_read_consistency() {
let (engine, _temp_dir) = create_test_engine_with_lease("lease_vs_lin").await;
let client = engine.client();
client.put(b"compare_key", b"compare_value").await.expect("PUT failed");
tokio::time::sleep(Duration::from_millis(150)).await;
let lease_result = client.get_lease(b"compare_key").await.expect("Lease read failed");
let lin_result =
client.get_linearizable(b"compare_key").await.expect("Linearizable read failed");
assert_eq!(
lease_result, lin_result,
"Lease and linearizable reads should return identical data"
);
assert_eq!(
lease_result.as_deref(),
Some(b"compare_value".as_ref()),
"Both reads should see committed value"
);
println!("✅ Lease and linearizable reads return consistent data");
}