use crate::cook::session::{
SessionInfo, SessionManager, SessionState, SessionSummary, SessionUpdate,
};
use anyhow::Result;
use async_trait::async_trait;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
pub struct MockSessionManager {
state: Arc<Mutex<SessionState>>,
pub start_called: Arc<Mutex<bool>>,
pub update_calls: Arc<Mutex<Vec<SessionUpdate>>>,
pub complete_called: Arc<Mutex<bool>>,
pub save_path: Arc<Mutex<Option<PathBuf>>>,
pub load_path: Arc<Mutex<Option<PathBuf>>>,
pub should_fail: bool,
}
impl Default for MockSessionManager {
fn default() -> Self {
Self::new()
}
}
impl MockSessionManager {
pub fn new() -> Self {
let state = SessionState::new("test-session".to_string(), PathBuf::from("/test"));
Self {
state: Arc::new(Mutex::new(state)),
start_called: Arc::new(Mutex::new(false)),
update_calls: Arc::new(Mutex::new(Vec::new())),
complete_called: Arc::new(Mutex::new(false)),
save_path: Arc::new(Mutex::new(None)),
load_path: Arc::new(Mutex::new(None)),
should_fail: false,
}
}
pub fn failing() -> Self {
let mut mock = Self::new();
mock.should_fail = true;
mock
}
pub fn get_update_calls(&self) -> Vec<SessionUpdate> {
self.update_calls.lock().unwrap().clone()
}
pub fn was_start_called(&self) -> bool {
*self.start_called.lock().unwrap()
}
pub fn was_complete_called(&self) -> bool {
*self.complete_called.lock().unwrap()
}
pub fn set_state(&self, state: SessionState) {
*self.state.lock().unwrap() = state;
}
}
#[async_trait]
impl SessionManager for MockSessionManager {
async fn start_session(&self, session_id: &str) -> Result<()> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
*self.start_called.lock().unwrap() = true;
self.state.lock().unwrap().session_id = session_id.to_string();
Ok(())
}
async fn update_session(&self, update: SessionUpdate) -> Result<()> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
self.update_calls.lock().unwrap().push(update.clone());
let mut state = self.state.lock().unwrap();
match update {
SessionUpdate::IncrementIteration => {
state.increment_iteration();
}
SessionUpdate::AddFilesChanged(count) => {
state.add_files_changed(count);
}
SessionUpdate::UpdateStatus(status) => {
state.status = status;
}
SessionUpdate::AddError(error) => {
state.errors.push(error);
}
_ => {} }
Ok(())
}
async fn complete_session(&self) -> Result<SessionSummary> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
*self.complete_called.lock().unwrap() = true;
self.state.lock().unwrap().complete();
Ok(SessionSummary {
iterations: self.state.lock().unwrap().iterations_completed,
files_changed: self.state.lock().unwrap().files_changed,
})
}
fn get_state(&self) -> Result<SessionState> {
Ok(self.state.lock().unwrap().clone())
}
async fn save_state(&self, path: &Path) -> Result<()> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
*self.save_path.lock().unwrap() = Some(path.to_path_buf());
Ok(())
}
async fn load_state(&self, path: &Path) -> Result<()> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
*self.load_path.lock().unwrap() = Some(path.to_path_buf());
Ok(())
}
async fn load_session(&self, session_id: &str) -> Result<SessionState> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
let mut state = self.state.lock().unwrap().clone();
state.session_id = session_id.to_string();
Ok(state)
}
async fn save_checkpoint(&self, state: &SessionState) -> Result<()> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
*self.state.lock().unwrap() = state.clone();
Ok(())
}
async fn list_resumable(&self) -> Result<Vec<SessionInfo>> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
let state = self.state.lock().unwrap().clone();
if state.is_resumable() {
Ok(vec![SessionInfo {
session_id: state.session_id.clone(),
status: state.status.clone(),
started_at: state.started_at,
workflow_path: PathBuf::from("test.yml"),
progress: "test progress".to_string(),
}])
} else {
Ok(Vec::new())
}
}
async fn get_last_interrupted(&self) -> Result<Option<String>> {
if self.should_fail {
return Err(anyhow::anyhow!("Mock failure"));
}
let state = self.state.lock().unwrap();
if state.status == crate::cook::session::SessionStatus::Interrupted {
Ok(Some(state.session_id.clone()))
} else {
Ok(None)
}
}
}