mod session_db {
use crate::db::Database;
use crate::db::models::Session;
use crate::services::{ServiceContext, SessionService};
async fn setup() -> SessionService {
let db = Database::connect_in_memory().await.unwrap();
db.run_migrations().await.unwrap();
SessionService::new(ServiceContext::new(db.pool().clone()))
}
#[tokio::test]
async fn new_session_has_no_working_directory() {
let svc = setup().await;
let session = svc.create_session(Some("Test".into())).await.unwrap();
assert!(session.working_directory.is_none());
}
#[tokio::test]
async fn update_working_directory_persists() {
let svc = setup().await;
let session = svc.create_session(Some("Test".into())).await.unwrap();
svc.update_session_working_directory(session.id, Some("/tmp/project".into()))
.await
.unwrap();
let loaded = svc.get_session_required(session.id).await.unwrap();
assert_eq!(loaded.working_directory, Some("/tmp/project".into()));
}
#[tokio::test]
async fn update_working_directory_to_none() {
let svc = setup().await;
let session = svc.create_session(Some("Test".into())).await.unwrap();
svc.update_session_working_directory(session.id, Some("/tmp/a".into()))
.await
.unwrap();
svc.update_session_working_directory(session.id, None)
.await
.unwrap();
let loaded = svc.get_session_required(session.id).await.unwrap();
assert!(loaded.working_directory.is_none());
}
#[tokio::test]
async fn working_directory_survives_session_update() {
let svc = setup().await;
let mut session = svc.create_session(Some("Test".into())).await.unwrap();
svc.update_session_working_directory(session.id, Some("/home/user/proj".into()))
.await
.unwrap();
session = svc.get_session_required(session.id).await.unwrap();
session.title = Some("Renamed".into());
svc.update_session(&session).await.unwrap();
let loaded = svc.get_session_required(session.id).await.unwrap();
assert_eq!(loaded.title, Some("Renamed".into()));
assert_eq!(loaded.working_directory, Some("/home/user/proj".into()));
}
#[tokio::test]
async fn working_directory_included_in_list() {
let svc = setup().await;
let session = svc.create_session(Some("Listed".into())).await.unwrap();
svc.update_session_working_directory(session.id, Some("/srv/app".into()))
.await
.unwrap();
let options = crate::db::repository::SessionListOptions {
include_archived: false,
limit: None,
offset: 0,
query: None,
};
let sessions = svc.list_sessions(options).await.unwrap();
let found = sessions.iter().find(|s| s.id == session.id).unwrap();
assert_eq!(found.working_directory, Some("/srv/app".into()));
}
#[tokio::test]
async fn working_directory_in_new_session_via_create() {
let session = Session::new(
Some("Manual".into()),
Some("model".into()),
Some("provider".into()),
);
assert!(session.working_directory.is_none());
}
#[tokio::test]
async fn multiple_sessions_different_directories() {
let svc = setup().await;
let s1 = svc.create_session(Some("Project A".into())).await.unwrap();
let s2 = svc.create_session(Some("Project B".into())).await.unwrap();
let s3 = svc.create_session(Some("No dir".into())).await.unwrap();
svc.update_session_working_directory(s1.id, Some("/home/user/project-a".into()))
.await
.unwrap();
svc.update_session_working_directory(s2.id, Some("/home/user/project-b".into()))
.await
.unwrap();
let loaded1 = svc.get_session_required(s1.id).await.unwrap();
let loaded2 = svc.get_session_required(s2.id).await.unwrap();
let loaded3 = svc.get_session_required(s3.id).await.unwrap();
assert_eq!(
loaded1.working_directory,
Some("/home/user/project-a".into())
);
assert_eq!(
loaded2.working_directory,
Some("/home/user/project-b".into())
);
assert!(loaded3.working_directory.is_none());
}
}
mod channel_session_wd_inherit {
use crate::channels::session_init::create_channel_session;
use crate::db::Database;
use crate::services::{ServiceContext, SessionService};
async fn setup() -> SessionService {
let db = Database::connect_in_memory().await.unwrap();
db.run_migrations().await.unwrap();
SessionService::new(ServiceContext::new(db.pool().clone()))
}
#[tokio::test]
async fn inherits_working_directory_from_prior_session() {
let svc = setup().await;
let prior = svc.create_session(Some("Prior".into())).await.unwrap();
svc.update_session_working_directory(prior.id, Some("/home/user/my-project".into()))
.await
.unwrap();
let new_session = create_channel_session(&svc, Some("Channel".into()))
.await
.unwrap();
assert_eq!(
new_session.working_directory,
Some("/home/user/my-project".into()),
"create_channel_session must inherit working_directory from the most recent session"
);
}
#[tokio::test]
async fn no_working_directory_when_no_prior_session() {
let svc = setup().await;
let new_session = create_channel_session(&svc, Some("First".into()))
.await
.unwrap();
assert!(
new_session.working_directory.is_none(),
"create_channel_session should set working_directory=None when no prior session exists"
);
}
#[tokio::test]
async fn no_working_directory_when_prior_has_none() {
let svc = setup().await;
let _prior = svc
.create_session(Some("Prior No WD".into()))
.await
.unwrap();
let new_session = create_channel_session(&svc, Some("Channel".into()))
.await
.unwrap();
assert!(
new_session.working_directory.is_none(),
"create_channel_session should be None when prior session has no working_directory"
);
}
#[tokio::test]
async fn inherits_latest_session_wd_not_earlier() {
let svc = setup().await;
let s_a = svc.create_session(Some("A".into())).await.unwrap();
svc.update_session_working_directory(s_a.id, Some("/project-a".into()))
.await
.unwrap();
{
let conn = svc.pool().get().await.unwrap();
let sid = s_a.id.to_string();
conn.interact(move |c| {
c.execute(
"UPDATE sessions SET updated_at = updated_at - 60 WHERE id = ?1",
rusqlite::params![sid],
)
})
.await
.unwrap()
.unwrap();
}
let s_b = svc.create_session(Some("B".into())).await.unwrap();
svc.update_session_working_directory(s_b.id, Some("/project-b".into()))
.await
.unwrap();
let new_session = create_channel_session(&svc, Some("Channel".into()))
.await
.unwrap();
assert_eq!(
new_session.working_directory,
Some("/project-b".into()),
"should inherit from the MOST RECENT session (B), not an earlier one (A)"
);
}
}
mod update_checker {
use crate::brain::tools::evolve::is_newer;
#[test]
fn newer_patch() {
assert!(is_newer("0.2.58", "0.2.57"));
}
#[test]
fn same_version() {
assert!(!is_newer("0.2.57", "0.2.57"));
}
#[test]
fn older_version_not_newer() {
assert!(!is_newer("0.2.57", "0.2.58"));
}
#[test]
fn newer_minor() {
assert!(is_newer("0.3.0", "0.2.99"));
}
#[test]
fn newer_major() {
assert!(is_newer("1.0.0", "0.99.99"));
}
#[test]
fn older_major_not_newer() {
assert!(!is_newer("0.9.0", "1.0.0"));
}
#[test]
fn equal_major_older_minor() {
assert!(!is_newer("1.0.5", "1.1.0"));
}
#[test]
fn two_segment_versions() {
assert!(is_newer("1.1", "1.0"));
assert!(!is_newer("1.0", "1.1"));
}
}