aboutsummaryrefslogtreecommitdiffstats
path: root/crates/atuin-daemon/tests/lifecycle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/atuin-daemon/tests/lifecycle.rs')
-rw-r--r--crates/atuin-daemon/tests/lifecycle.rs222
1 files changed, 0 insertions, 222 deletions
diff --git a/crates/atuin-daemon/tests/lifecycle.rs b/crates/atuin-daemon/tests/lifecycle.rs
deleted file mode 100644
index 4a91e5cb..00000000
--- a/crates/atuin-daemon/tests/lifecycle.rs
+++ /dev/null
@@ -1,222 +0,0 @@
-//! Integration tests for the daemon server lifecycle.
-//!
-//! Each test spins up a real gRPC server on a temporary unix socket,
-//! connects a client, and exercises the daemon RPCs.
-
-#[cfg(unix)]
-mod unix {
- use std::time::Duration;
-
- use atuin_client::database::Sqlite;
- use atuin_client::record::sqlite_store::SqliteStore;
- use atuin_client::settings::{Settings, init_meta_config_for_testing};
- use atuin_daemon::client::HistoryClient;
- use atuin_daemon::components::HistoryComponent;
- use atuin_daemon::{Daemon, DaemonHandle};
- use tempfile::TempDir;
- use tokio::net::UnixListener;
- use tokio_stream::wrappers::UnixListenerStream;
- use tonic::transport::Server;
-
- /// Spins up a daemon server on a temp socket and returns a connected client,
- /// the daemon handle (for shutdown), and the temp dir (must be held to keep paths alive).
- async fn start_test_daemon() -> (HistoryClient, DaemonHandle, TempDir) {
- let tmp = tempfile::tempdir().unwrap();
-
- let db_path = tmp.path().join("history.db");
- let record_path = tmp.path().join("records.db");
- let key_path = tmp.path().join("key");
- let socket_path = tmp.path().join("test.sock");
- let meta_path = tmp.path().join("meta.db");
-
- // Initialize the meta store config for testing (required for Settings::host_id())
- init_meta_config_for_testing(meta_path.to_str().unwrap(), 5.0);
-
- // Build settings with test paths
- let settings: Settings = Settings::builder()
- .expect("could not build settings builder")
- .set_override("db_path", db_path.to_str().unwrap())
- .expect("failed to set db_path")
- .set_override("record_store_path", record_path.to_str().unwrap())
- .expect("failed to set record_store_path")
- .set_override("key_path", key_path.to_str().unwrap())
- .expect("failed to set key_path")
- .set_override("daemon.socket_path", socket_path.to_str().unwrap())
- .expect("failed to set socket_path")
- .set_override("meta.db_path", meta_path.to_str().unwrap())
- .expect("failed to set meta.db_path")
- .build()
- .expect("could not build settings")
- .try_deserialize()
- .expect("could not deserialize settings");
-
- // Create databases
- let history_db = Sqlite::new(&db_path, 5.0).await.unwrap();
- let store = SqliteStore::new(&record_path, 5.0).await.unwrap();
-
- // Create the history component and get its gRPC service
- let history_component = HistoryComponent::new();
- let history_service = history_component.grpc_service();
-
- // Build and start the daemon
- let mut daemon = Daemon::builder(settings)
- .store(store)
- .history_db(history_db)
- .component(history_component)
- .build()
- .await
- .unwrap();
-
- let handle = daemon.handle();
-
- // Start components (this initializes the history component with the handle)
- daemon.start_components().await.unwrap();
-
- // Start the gRPC server
- let uds = UnixListener::bind(&socket_path).unwrap();
- let stream = UnixListenerStream::new(uds);
-
- let server_handle = handle.clone();
- tokio::spawn(async move {
- let mut rx = server_handle.subscribe();
- Server::builder()
- .add_service(history_service)
- .serve_with_incoming_shutdown(stream, async move {
- loop {
- match rx.recv().await {
- Ok(atuin_daemon::DaemonEvent::ShutdownRequested) => break,
- Ok(_) => continue,
- Err(_) => break,
- }
- }
- })
- .await
- .unwrap();
- });
-
- // Spawn the daemon event loop in the background
- tokio::spawn(async move {
- daemon.run_event_loop().await.unwrap();
- });
-
- // Give the server a moment to bind.
- tokio::time::sleep(Duration::from_millis(50)).await;
-
- let client = HistoryClient::new(socket_path.to_string_lossy().to_string())
- .await
- .unwrap();
-
- (client, handle, tmp)
- }
-
- #[tokio::test]
- async fn test_status() {
- let (mut client, _handle, _tmp) = start_test_daemon().await;
-
- let status = client.status().await.unwrap();
- assert!(status.healthy);
- assert_eq!(status.version, env!("CARGO_PKG_VERSION"));
- assert_eq!(status.protocol, 1);
- assert!(status.pid > 0);
- }
-
- #[tokio::test]
- async fn test_start_end_history() {
- use atuin_client::history::History;
-
- let (mut client, _handle, _tmp) = start_test_daemon().await;
-
- let history = History::daemon()
- .timestamp(time::OffsetDateTime::now_utc())
- .command("echo hello".to_string())
- .cwd("/tmp".to_string())
- .session("test-session".to_string())
- .hostname("test-host".to_string())
- .build()
- .into();
-
- let start_reply = client.start_history(history).await.unwrap();
- assert!(!start_reply.id.is_empty());
-
- let end_reply = client
- .end_history(start_reply.id, 1_000_000, 0)
- .await
- .unwrap();
- assert!(!end_reply.id.is_empty());
- }
-
- #[tokio::test]
- async fn test_tail_history_streams_started_and_ended_events() {
- use atuin_client::history::History;
- use atuin_daemon::history::HistoryEventKind;
-
- let (mut client, _handle, _tmp) = start_test_daemon().await;
- let mut stream = client.tail_history().await.unwrap();
-
- let history = History::daemon()
- .timestamp(time::OffsetDateTime::now_utc())
- .command("git status".to_string())
- .cwd("/tmp/repo".to_string())
- .session("tail-session".to_string())
- .hostname("test-host:ellie".to_string())
- .author("claude".to_string())
- .intent("inspect repository state".to_string())
- .build()
- .into();
-
- let start_reply = client.start_history(history).await.unwrap();
-
- let started = stream.message().await.unwrap().unwrap();
- assert_eq!(
- HistoryEventKind::try_from(started.kind).unwrap(),
- HistoryEventKind::Started
- );
- let started_history = started.history.unwrap();
- assert_eq!(started_history.id, start_reply.id);
- assert_eq!(started_history.command, "git status");
- assert_eq!(started_history.cwd, "/tmp/repo");
- assert_eq!(started_history.hostname, "test-host:ellie");
- assert_eq!(started_history.author, "claude");
- assert_eq!(started_history.intent, "inspect repository state");
-
- client
- .end_history(start_reply.id.clone(), 1_000_000, 0)
- .await
- .unwrap();
-
- let ended = stream.message().await.unwrap().unwrap();
- assert_eq!(
- HistoryEventKind::try_from(ended.kind).unwrap(),
- HistoryEventKind::Ended
- );
- let ended_history = ended.history.unwrap();
- assert_eq!(ended_history.id, start_reply.id);
- assert_eq!(ended_history.exit, 0);
- assert_eq!(ended_history.duration, 1_000_000);
- }
-
- #[tokio::test]
- async fn test_end_unknown_history_fails() {
- let (mut client, _handle, _tmp) = start_test_daemon().await;
-
- let result = client
- .end_history("nonexistent-id".to_string(), 1000, 0)
- .await;
- assert!(result.is_err());
- }
-
- #[tokio::test]
- async fn test_shutdown() {
- let (mut client, _handle, _tmp) = start_test_daemon().await;
-
- let accepted = client.shutdown().await.unwrap();
- assert!(accepted);
-
- // Give server time to shut down.
- tokio::time::sleep(Duration::from_millis(100)).await;
-
- // Subsequent calls should fail since the server is gone.
- let result = client.status().await;
- assert!(result.is_err());
- }
-}