summaryrefslogtreecommitdiff
path: root/src/test_support.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test_support.rs')
-rw-r--r--src/test_support.rs72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/test_support.rs b/src/test_support.rs
new file mode 100644
index 0000000..8f2d2bf
--- /dev/null
+++ b/src/test_support.rs
@@ -0,0 +1,72 @@
+//! Test support utilities shared between unit and integration tests.
+//!
+//! Gated behind `cfg(any(test, feature = "integration"))`.
+//! Provides thin wrappers around `pub(crate)` server internals so integration
+//! tests can start a real server on a random port without exposing internal APIs,
+//! plus common helpers (temp dirs, cleanup) used across unit test modules.
+
+#![allow(clippy::unwrap_used, clippy::expect_used)]
+
+use crate::server::{AppState, run_with_listener};
+use anyhow::Result;
+use std::path::{Path, PathBuf};
+use tokio::net::TcpListener;
+
+/// Start the HTTP server on the given listener, shutting down when `shutdown` resolves.
+///
+/// The server behaves identically to production — same middleware, same handlers.
+///
+/// # Errors
+///
+/// Returns an error if the server encounters a fatal I/O error.
+pub async fn run_server(
+ state: AppState,
+ listener: TcpListener,
+ shutdown: impl std::future::Future<Output = ()> + Send + 'static,
+) -> Result<()> {
+ run_with_listener(state, listener, shutdown).await
+}
+
+/// Install the SIGHUP configuration-reload handler for `state`.
+///
+/// Call this before sending SIGHUP in tests that exercise hot-reload.
+/// It replaces the default signal disposition (terminate) with the production
+/// reload handler, so the process stays alive after receiving the signal.
+pub fn setup_sighup_handler(state: &AppState) {
+ crate::server::setup_sighup_handler(state.clone());
+}
+
+/// Generate a unique ID for test isolation (timestamp + counter).
+///
+/// # Panics
+///
+/// Panics if the system clock is before the Unix epoch.
+pub fn uuid() -> String {
+ use std::sync::atomic::{AtomicU64, Ordering};
+ use std::time::{SystemTime, UNIX_EPOCH};
+ static COUNTER: AtomicU64 = AtomicU64::new(0);
+ let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
+ let count = COUNTER.fetch_add(1, Ordering::SeqCst);
+ format!(
+ "{}-{}-{}",
+ duration.as_secs(),
+ duration.subsec_nanos(),
+ count
+ )
+}
+
+/// Create a unique temporary directory for a test.
+///
+/// # Panics
+///
+/// Panics if the directory cannot be created.
+pub async fn temp_dir(prefix: &str) -> PathBuf {
+ let dir = std::env::temp_dir().join(format!("witryna-{}-{}", prefix, uuid()));
+ tokio::fs::create_dir_all(&dir).await.unwrap();
+ dir
+}
+
+/// Remove a temporary directory (ignores errors).
+pub async fn cleanup(dir: &Path) {
+ let _ = tokio::fs::remove_dir_all(dir).await;
+}