mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
refactor(test): promote shared server-lifecycle test helpers into fabro-test
Move wait_for_path, wait_for_log_line, stop_pid, server_log_files, and isolated_storage_dir out of the three integration test files that duplicated them and into fabro-test's public surface next to apply_test_isolation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a256c14a77
commit
f8c560a9a6
5 changed files with 76 additions and 122 deletions
|
|
@ -2,66 +2,10 @@ use std::process::Stdio;
|
|||
use std::sync::{Arc, Barrier};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use fabro_test::{apply_test_isolation, fabro_snapshot, test_context};
|
||||
|
||||
fn isolated_storage_dir() -> tempfile::TempDir {
|
||||
let root = tempfile::tempdir_in("/tmp").unwrap();
|
||||
std::fs::create_dir_all(root.path().join("storage")).unwrap();
|
||||
root
|
||||
}
|
||||
|
||||
fn server_log_files(logs_dir: &std::path::Path) -> Vec<std::path::PathBuf> {
|
||||
let Ok(entries) = std::fs::read_dir(logs_dir) else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
entries
|
||||
.flatten()
|
||||
.map(|entry| entry.path())
|
||||
.filter(|path| {
|
||||
path.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.is_some_and(|name| name.starts_with("server.") && name.ends_with(".log"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn wait_for_path(path: &std::path::Path) {
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
while Instant::now() < deadline {
|
||||
if path.exists() {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
panic!("timed out waiting for {}", path.display());
|
||||
}
|
||||
|
||||
fn wait_for_log_line(path: &std::path::Path, needle: &str) {
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
while Instant::now() < deadline {
|
||||
if std::fs::read_to_string(path)
|
||||
.ok()
|
||||
.is_some_and(|contents| contents.contains(needle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
panic!("timed out waiting for {needle:?} in {}", path.display());
|
||||
}
|
||||
|
||||
fn stop_pid(pid: u32) {
|
||||
fabro_proc::sigterm(pid);
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
while Instant::now() < deadline {
|
||||
if !fabro_proc::process_alive(pid) {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
fabro_proc::sigkill(pid);
|
||||
}
|
||||
use fabro_test::{
|
||||
apply_test_isolation, fabro_snapshot, isolated_storage_dir, server_log_files, stop_pid,
|
||||
test_context, wait_for_log_line, wait_for_path,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn help() {
|
||||
|
|
|
|||
|
|
@ -1,33 +1,4 @@
|
|||
use fabro_test::{fabro_snapshot, test_context};
|
||||
|
||||
fn isolated_storage_dir() -> tempfile::TempDir {
|
||||
let root = tempfile::tempdir_in("/tmp").unwrap();
|
||||
std::fs::create_dir_all(root.path().join("storage")).unwrap();
|
||||
root
|
||||
}
|
||||
|
||||
fn wait_for_path(path: &std::path::Path) {
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
while std::time::Instant::now() < deadline {
|
||||
if path.exists() {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
panic!("timed out waiting for {}", path.display());
|
||||
}
|
||||
|
||||
fn stop_pid(pid: u32) {
|
||||
fabro_proc::sigterm(pid);
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
while std::time::Instant::now() < deadline {
|
||||
if !fabro_proc::process_alive(pid) {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
fabro_proc::sigkill(pid);
|
||||
}
|
||||
use fabro_test::{fabro_snapshot, isolated_storage_dir, stop_pid, test_context, wait_for_path};
|
||||
|
||||
#[test]
|
||||
fn help() {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
use fabro_test::{fabro_snapshot, test_context};
|
||||
|
||||
fn isolated_storage_dir() -> tempfile::TempDir {
|
||||
let root = tempfile::tempdir_in("/tmp").unwrap();
|
||||
std::fs::create_dir_all(root.path().join("storage")).unwrap();
|
||||
root
|
||||
}
|
||||
use fabro_test::{fabro_snapshot, isolated_storage_dir, test_context};
|
||||
|
||||
#[test]
|
||||
fn help() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::fs;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
use fabro_test::{fabro_snapshot, stop_pid, test_context, wait_for_path};
|
||||
use serde_json::Value;
|
||||
|
||||
#[test]
|
||||
|
|
@ -38,29 +37,6 @@ fn command_with_no_fabro_home(context: &fabro_test::TestContext) -> assert_cmd::
|
|||
cmd
|
||||
}
|
||||
|
||||
fn wait_for_path(path: &std::path::Path) {
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
while Instant::now() < deadline {
|
||||
if path.exists() {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
panic!("timed out waiting for {}", path.display());
|
||||
}
|
||||
|
||||
fn stop_pid(pid: u32) {
|
||||
fabro_proc::sigterm(pid);
|
||||
let deadline = Instant::now() + Duration::from_secs(5);
|
||||
while Instant::now() < deadline {
|
||||
if !fabro_proc::process_alive(pid) {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
fabro_proc::sigkill(pid);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_installed_prints_message() {
|
||||
let context = test_context!();
|
||||
|
|
|
|||
|
|
@ -150,6 +150,75 @@ fn apply_test_isolation_with_lookup(
|
|||
cmd.env(TEST_IN_MEMORY_STORE_ENV, "1");
|
||||
}
|
||||
|
||||
/// Create a fresh tempdir containing an empty `storage/` subdirectory, for
|
||||
/// isolating server lifecycle tests from the shared nextest session storage.
|
||||
#[must_use]
|
||||
pub fn isolated_storage_dir() -> tempfile::TempDir {
|
||||
let root = tempfile::tempdir_in("/tmp").expect("tempdir under /tmp");
|
||||
std::fs::create_dir_all(root.path().join("storage")).expect("create storage dir");
|
||||
root
|
||||
}
|
||||
|
||||
/// Poll up to 5s for a path to appear; panic on timeout.
|
||||
pub fn wait_for_path(path: &Path) {
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
while std::time::Instant::now() < deadline {
|
||||
if path.exists() {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
panic!("timed out waiting for {}", path.display());
|
||||
}
|
||||
|
||||
/// Poll up to 5s for `needle` to appear in the contents of `path`; panic on
|
||||
/// timeout.
|
||||
pub fn wait_for_log_line(path: &Path, needle: &str) {
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
while std::time::Instant::now() < deadline {
|
||||
if std::fs::read_to_string(path)
|
||||
.ok()
|
||||
.is_some_and(|contents| contents.contains(needle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
panic!("timed out waiting for {needle:?} in {}", path.display());
|
||||
}
|
||||
|
||||
/// SIGTERM the pid, wait up to 5s for it to exit, then SIGKILL if still alive.
|
||||
pub fn stop_pid(pid: u32) {
|
||||
fabro_proc::sigterm(pid);
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
|
||||
while std::time::Instant::now() < deadline {
|
||||
if !fabro_proc::process_alive(pid) {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
fabro_proc::sigkill(pid);
|
||||
}
|
||||
|
||||
/// List any `server.*.log` files under `logs_dir`. Used by server-lifecycle
|
||||
/// tests to assert that no server logs leak into the home logs directory.
|
||||
#[must_use]
|
||||
pub fn server_log_files(logs_dir: &Path) -> Vec<PathBuf> {
|
||||
let Ok(entries) = std::fs::read_dir(logs_dir) else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
entries
|
||||
.flatten()
|
||||
.map(|entry| entry.path())
|
||||
.filter(|path| {
|
||||
path.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.is_some_and(|name| name.starts_with("server.") && name.ends_with(".log"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// A test context for running fabro CLI commands.
|
||||
///
|
||||
/// Each context gets isolated home/temp directories. The storage directory is
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue