use std::path::Path;
use std::time::SystemTime;
use serde_json::json;
use crate::llm::cache::Cache;
fn set_mtime(path: &Path, mtime: SystemTime) {
let file = std::fs::OpenOptions::new()
.write(true)
.open(path)
.expect("open for mtime set");
file.set_modified(mtime).expect("set_modified");
}
#[test]
fn entry_older_than_ttl_is_a_miss() {
let temp = tempfile::tempdir().expect("tempdir");
let cache = Cache::new(temp.path().to_path_buf(), 30, 1024 * 1024);
let key = cache.key(
"sys",
"content",
"http://endpoint/v1",
"model",
"openai",
Some(0.2),
);
cache.put(&key, &json!({"x": 1})).expect("put");
let path = cache.entry_path(&key);
let ancient = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(60 * 86_400);
set_mtime(&path, ancient);
assert!(
cache.get(&key).is_none(),
"an entry older than TTL must be a miss"
);
}
#[test]
fn entry_within_ttl_is_a_hit() {
let temp = tempfile::tempdir().expect("tempdir");
let cache = Cache::new(temp.path().to_path_buf(), 30, 1024 * 1024);
let key = cache.key(
"sys",
"content",
"http://endpoint/v1",
"model",
"openai",
Some(0.2),
);
let value = json!({"answer": 42});
cache.put(&key, &value).expect("put");
assert_eq!(
cache.get(&key).as_ref(),
Some(&value),
"a fresh entry must hit"
);
}
#[test]
fn reading_expired_entry_removes_it_from_disk() {
let temp = tempfile::tempdir().expect("tempdir");
let cache = Cache::new(temp.path().to_path_buf(), 30, 1024 * 1024);
let key = cache.key(
"sys",
"content",
"http://endpoint/v1",
"model",
"openai",
Some(0.2),
);
cache.put(&key, &json!({"x": 1})).expect("put");
let path = cache.entry_path(&key);
let ancient = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(60 * 86_400);
set_mtime(&path, ancient);
let _ = cache.get(&key);
assert!(
!path.exists(),
"reading an expired entry must remove the file from disk: {path:?}"
);
}
#[test]
fn age_equal_to_ttl_is_a_hit_not_a_miss() {
let temp = tempfile::tempdir().expect("tempdir");
let cache = Cache::new(temp.path().to_path_buf(), 0, 1024 * 1024);
let key = cache.key(
"sys",
"content",
"http://endpoint/v1",
"model",
"openai",
Some(0.2),
);
let value = json!({"x": 1});
cache.put(&key, &value).expect("put");
let path = cache.entry_path(&key);
let future = SystemTime::now() + std::time::Duration::from_secs(3600);
set_mtime(&path, future);
assert_eq!(
cache.get(&key).as_ref(),
Some(&value),
"age == ttl must be a hit under strict `>` semantics"
);
}