Skip to content

Commit e38f58e

Browse files
committed
fix: resolve clippy warning for hydrate_session
1 parent 1b1310f commit e38f58e

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

src/data/poller.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,160 @@ fn chrono_like_epoch(value: &str) -> Option<u64> {
368368
.ok()
369369
.map(|dt| dt.timestamp().max(0) as u64)
370370
}
371+
372+
/// Hydrate a single session from the DB into a `DiscoveredSessionInfo`.
373+
/// Returns `Ok(None)` if the session doesn't exist or has no directory.
374+
#[cfg(test)]
375+
fn hydrate_session(
376+
reader: &DbReader,
377+
session_id: &str,
378+
process_pid: Option<u32>,
379+
serve_port: Option<u16>,
380+
source: DiscoverySource,
381+
) -> anyhow::Result<Option<DiscoveredSessionInfo>> {
382+
let Some(session) = reader.get_session_by_id(session_id)? else {
383+
return Ok(None);
384+
};
385+
if session.directory.as_os_str().is_empty() {
386+
return Ok(None);
387+
}
388+
let status = reader.get_session_status(session_id)?;
389+
Ok(Some(DiscoveredSessionInfo {
390+
session_id: session_id.to_string(),
391+
cwd: session.directory.clone(),
392+
title: session.title.clone(),
393+
status,
394+
process_pid,
395+
model: reader.get_session_model(session_id)?,
396+
preview: reader
397+
.get_last_message_preview(session_id)?
398+
.map(|p| p.text),
399+
time_updated: Some(session.time_updated),
400+
has_children: reader.has_child_sessions(session_id)?,
401+
children: collect_children(reader, session_id, 2)?,
402+
serve_port,
403+
source,
404+
}))
405+
}
406+
407+
#[cfg(test)]
408+
mod tests {
409+
use super::*;
410+
use crate::app::sessions::SessionStatus;
411+
use rusqlite::Connection;
412+
use std::path::PathBuf;
413+
use std::time::{SystemTime, UNIX_EPOCH};
414+
415+
fn temp_db_path(label: &str) -> PathBuf {
416+
let nanos = SystemTime::now()
417+
.duration_since(UNIX_EPOCH)
418+
.unwrap()
419+
.as_nanos();
420+
std::env::temp_dir().join(format!("ocmux-rs-{label}-{nanos}.db"))
421+
}
422+
423+
fn init_db(path: &PathBuf) -> Connection {
424+
let conn = Connection::open(path).unwrap();
425+
conn.execute_batch(
426+
r#"
427+
CREATE TABLE project (
428+
id TEXT PRIMARY KEY,
429+
worktree TEXT NOT NULL,
430+
name TEXT,
431+
time_created INTEGER,
432+
time_updated INTEGER
433+
);
434+
CREATE TABLE session (
435+
id TEXT PRIMARY KEY,
436+
project_id TEXT NOT NULL,
437+
parent_id TEXT,
438+
title TEXT,
439+
directory TEXT,
440+
permission TEXT,
441+
time_created INTEGER,
442+
time_updated INTEGER,
443+
time_archived INTEGER
444+
);
445+
CREATE TABLE message (
446+
id TEXT PRIMARY KEY,
447+
session_id TEXT NOT NULL,
448+
data TEXT NOT NULL,
449+
time_created INTEGER
450+
);
451+
CREATE TABLE part (
452+
id TEXT PRIMARY KEY,
453+
session_id TEXT NOT NULL,
454+
message_id TEXT NOT NULL,
455+
data TEXT NOT NULL,
456+
time_created INTEGER
457+
);
458+
"#,
459+
)
460+
.unwrap();
461+
conn
462+
}
463+
464+
#[test]
465+
fn hydrate_session_builds_info_from_db() {
466+
let db_path = temp_db_path("hydrate");
467+
let conn = init_db(&db_path);
468+
conn.execute(
469+
"INSERT INTO project VALUES ('proj1', '/tmp/proj', 'proj', 100, 200)",
470+
[],
471+
)
472+
.unwrap();
473+
conn.execute(
474+
"INSERT INTO session VALUES ('sess1', 'proj1', NULL, 'My Title', '/tmp/proj', NULL, 100, 200, NULL)",
475+
[],
476+
)
477+
.unwrap();
478+
conn.execute(
479+
r#"INSERT INTO message VALUES ('msg1', 'sess1', '{"role":"assistant","time":{"completed":200}}', 200)"#,
480+
[],
481+
)
482+
.unwrap();
483+
484+
let reader = DbReader::open(&db_path).unwrap();
485+
let info = hydrate_session(&reader, "sess1", Some(123), Some(4200), DiscoverySource::Serve)
486+
.unwrap()
487+
.unwrap();
488+
assert_eq!(info.session_id, "sess1");
489+
assert_eq!(info.title, "My Title");
490+
assert_eq!(info.status, SessionStatus::Idle);
491+
assert_eq!(info.process_pid, Some(123));
492+
assert_eq!(info.serve_port, Some(4200));
493+
assert_eq!(info.source, DiscoverySource::Serve);
494+
assert_eq!(info.cwd, PathBuf::from("/tmp/proj"));
495+
}
496+
497+
#[test]
498+
fn hydrate_session_returns_none_for_missing_session() {
499+
let db_path = temp_db_path("hydrate-miss");
500+
let _conn = init_db(&db_path);
501+
let reader = DbReader::open(&db_path).unwrap();
502+
let result =
503+
hydrate_session(&reader, "nonexistent", None, None, DiscoverySource::Serve).unwrap();
504+
assert!(result.is_none());
505+
}
506+
507+
#[test]
508+
fn hydrate_session_returns_none_for_empty_directory() {
509+
let db_path = temp_db_path("hydrate-nodir");
510+
let conn = init_db(&db_path);
511+
conn.execute(
512+
"INSERT INTO project VALUES ('proj1', '/tmp/proj', 'proj', 100, 200)",
513+
[],
514+
)
515+
.unwrap();
516+
conn.execute(
517+
"INSERT INTO session VALUES ('sess1', 'proj1', NULL, 'Title', '', NULL, 100, 200, NULL)",
518+
[],
519+
)
520+
.unwrap();
521+
522+
let reader = DbReader::open(&db_path).unwrap();
523+
let result =
524+
hydrate_session(&reader, "sess1", None, None, DiscoverySource::Serve).unwrap();
525+
assert!(result.is_none());
526+
}
527+
}

0 commit comments

Comments
 (0)