use super::super::*;
#[tokio::test]
async fn bind_does_not_load_metadata_cache_from_disk() {
let tmp = tempfile::tempdir().unwrap();
let cache_dir = crate::core::NormalizedPath::new(tmp.path());
let snapshot_path = crate::core::config::metadata_path_from_cache_dir(&cache_dir);
let pre = crate::fscache::MetadataCache::new();
let file_a = tmp.path().join("a.txt");
let file_b = tmp.path().join("b.txt");
std::fs::write(&file_a, b"file a").unwrap();
std::fs::write(&file_b, b"file b").unwrap();
pre.insert(
crate::core::NormalizedPath::new(&file_a),
synthetic_metadata([0xAA; 32]),
);
pre.insert(
crate::core::NormalizedPath::new(&file_b),
synthetic_metadata([0xBB; 32]),
);
pre.save_to_disk(snapshot_path.as_path()).unwrap();
assert!(snapshot_path.as_path().exists());
let endpoint = crate::ipc::unique_test_endpoint();
let server = DaemonServer::bind_with_cache_dir(&endpoint, &cache_dir).unwrap();
let state = server.test_state();
assert_eq!(
state.cache_system.metadata().len(),
0,
"bind must start with an empty metadata cache",
);
assert!(
!state.metadata_cache_loaded.load(Ordering::Acquire),
"the loaded flag must start false until the background loader runs",
);
}
#[tokio::test]
async fn metadata_cache_loader_merges_snapshot_into_live_cache() {
let tmp = tempfile::tempdir().unwrap();
let cache_dir = crate::core::NormalizedPath::new(tmp.path());
let snapshot_path = crate::core::config::metadata_path_from_cache_dir(&cache_dir);
let pre = crate::fscache::MetadataCache::new();
let file = tmp.path().join("source.cpp");
std::fs::write(&file, b"int main() {}").unwrap();
let file_path = crate::core::NormalizedPath::new(&file);
pre.insert(file_path.clone(), synthetic_metadata([0x42; 32]));
pre.save_to_disk(snapshot_path.as_path()).unwrap();
let endpoint = crate::ipc::unique_test_endpoint();
let server = DaemonServer::bind_with_cache_dir(&endpoint, &cache_dir).unwrap();
server.metadata_cache_loader().load_and_install();
let state = server.test_state();
assert_eq!(
state.cache_system.metadata().len(),
1,
"loader must merge the persisted entry into the live cache",
);
assert!(
state.metadata_cache_loaded.load(Ordering::Acquire),
"loader must set metadata_cache_loaded=true so shutdown save fires",
);
assert!(
state.cache_system.metadata().get(&file_path).is_some(),
"the merged entry must be observable via the live cache API",
);
}
#[tokio::test]
async fn metadata_cache_loader_tolerates_missing_snapshot() {
let tmp = tempfile::tempdir().unwrap();
let cache_dir = crate::core::NormalizedPath::new(tmp.path());
let endpoint = crate::ipc::unique_test_endpoint();
let server = DaemonServer::bind_with_cache_dir(&endpoint, &cache_dir).unwrap();
server.metadata_cache_loader().load_and_install();
let state = server.test_state();
assert_eq!(state.cache_system.metadata().len(), 0);
assert!(
state.metadata_cache_loaded.load(Ordering::Acquire),
"loaded flag flips even when the snapshot was absent",
);
}
#[test]
fn metadata_cache_merge_from_drains_other() {
let tmp = tempfile::tempdir().unwrap();
let a = tmp.path().join("a");
let b = tmp.path().join("b");
std::fs::write(&a, b"a").unwrap();
std::fs::write(&b, b"b").unwrap();
let live = crate::fscache::MetadataCache::new();
live.insert(
crate::core::NormalizedPath::new(&a),
synthetic_metadata([1; 32]),
);
let loaded = crate::fscache::MetadataCache::new();
loaded.insert(
crate::core::NormalizedPath::new(&b),
synthetic_metadata([2; 32]),
);
live.merge_from(loaded);
assert_eq!(live.len(), 2);
assert!(live.get(&crate::core::NormalizedPath::new(&a)).is_some());
assert!(live.get(&crate::core::NormalizedPath::new(&b)).is_some());
}
fn synthetic_metadata(hash: [u8; 32]) -> crate::fscache::FileMetadata {
crate::fscache::FileMetadata {
mtime: std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_700_000_000),
size: 42,
content_hash: Some(hash),
confidence: crate::fscache::Confidence::High,
last_verified: std::time::Instant::now(),
}
}