use oxi_store::session::{AgentMessage, AssistantContentBlock, ContentValue, SessionManager};
use tempfile::TempDir;
fn make_user_message(text: &str) -> AgentMessage {
AgentMessage::User {
content: ContentValue::String(text.to_string()),
}
}
fn make_assistant_message(text: &str) -> AgentMessage {
AgentMessage::Assistant {
content: vec![AssistantContentBlock::Text {
text: text.to_string(),
}],
provider: Some("mock".to_string()),
model_id: Some("mock/model".to_string()),
usage: None,
stop_reason: None,
}
}
#[test]
fn test_create_and_load_session() {
let dir = TempDir::new().unwrap();
let dir_path = dir.path().to_str().unwrap();
let mut manager = SessionManager::create(".", Some(dir_path));
let id = manager.get_session_id();
assert!(!id.is_empty());
let session_file = manager
.get_session_file()
.expect("session file should be set");
manager.append_message(make_user_message("hello"));
manager.append_message(make_assistant_message("world"));
assert!(
std::path::Path::new(&session_file).exists(),
"session file should exist after assistant message"
);
}
#[test]
fn test_session_file_is_valid_jsonl() {
let dir = TempDir::new().unwrap();
let dir_path = dir.path().to_str().unwrap();
let mut manager = SessionManager::create("/tmp/test", Some(dir_path));
manager.append_message(make_user_message("hello"));
manager.append_message(make_assistant_message("response"));
let session_file = manager.get_session_file().unwrap();
let contents = std::fs::read_to_string(&session_file).unwrap();
for (i, line) in contents.lines().enumerate() {
if line.trim().is_empty() {
continue;
}
serde_json::from_str::<serde_json::Value>(line)
.unwrap_or_else(|e| panic!("line {} is not valid JSON: {} — {}", i, e, line));
}
}
#[test]
fn test_session_roundtrip_preserves_assistant_content() {
let dir = TempDir::new().unwrap();
let dir_path = dir.path().to_str().unwrap();
let mut manager = SessionManager::create("/tmp/test", Some(dir_path));
let _uid = manager.append_message(make_user_message("question"));
let aid = manager.append_message(make_assistant_message("answer"));
let session_file = manager.get_session_file().unwrap();
let loaded = SessionManager::open(&session_file, Some(dir_path), None);
let entry = loaded.get_entry(&aid);
assert!(entry.is_some(), "assistant entry should survive roundtrip");
assert_eq!(entry.unwrap().content(), "answer");
}
#[test]
fn test_no_temp_files_left_behind() {
let dir = TempDir::new().unwrap();
let dir_path = dir.path().to_str().unwrap();
let mut manager = SessionManager::create("/tmp/test", Some(dir_path));
manager.append_message(make_user_message("msg"));
manager.append_message(make_assistant_message("reply"));
let tmp_files: Vec<_> = std::fs::read_dir(dir_path)
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| {
e.path()
.extension()
.map(|ext| ext.to_string_lossy().starts_with("tmp"))
.unwrap_or(false)
})
.collect();
assert!(
tmp_files.is_empty(),
"no temp files should remain: {:?}",
tmp_files
);
}
#[test]
fn test_in_memory_session_has_no_file() {
let manager = SessionManager::in_memory("/tmp/test");
assert!(!manager.is_persisted());
assert!(manager.get_session_file().is_none());
}
#[test]
fn test_multiple_messages_persist() {
let dir = TempDir::new().unwrap();
let dir_path = dir.path().to_str().unwrap();
let mut manager = SessionManager::create("/tmp/test", Some(dir_path));
for i in 0..5 {
manager.append_message(make_user_message(&format!("user msg {}", i)));
manager.append_message(make_assistant_message(&format!("assistant msg {}", i)));
}
let session_file = manager.get_session_file().unwrap();
let contents = std::fs::read_to_string(&session_file).unwrap();
let line_count = contents.lines().filter(|l| !l.trim().is_empty()).count();
assert!(
line_count >= 6,
"expected at least 6 lines, got {}",
line_count
);
}