mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-02-20 07:37:26 -05:00
- Removed the static ASCII logo and implemented a new function to calculate brightness on a sphere, allowing for a dynamic rendering of the Spacedrive logo as a purple orb using ANSI colors and Unicode half-blocks. - Enhanced the `print_logo_colored` function to utilize the new brightness calculation and color gradient, improving visual representation. - Updated related documentation to reflect the changes in logo rendering.
219 lines
6.1 KiB
Rust
219 lines
6.1 KiB
Rust
//! Test data directory management with automatic cleanup and snapshot support
|
|
|
|
use super::snapshot::SnapshotManager;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
/// Manages test data directories with automatic cleanup and optional snapshot support
|
|
pub struct TestDataDir {
|
|
test_name: String,
|
|
temp_path: PathBuf,
|
|
snapshot_manager: Option<SnapshotManager>,
|
|
}
|
|
|
|
impl TestDataDir {
|
|
/// Create new test data directory in system temp location
|
|
///
|
|
/// Directory structure:
|
|
/// ```
|
|
/// /tmp/spacedrive-test-{test_name}/
|
|
/// ├── core_data/ # Core database and state
|
|
/// ├── locations/ # Test file locations
|
|
/// └── logs/ # Test execution logs
|
|
/// ```
|
|
///
|
|
/// Snapshots are enabled if SD_TEST_SNAPSHOTS=1 environment variable is set.
|
|
pub fn new(test_name: impl Into<String>) -> anyhow::Result<Self> {
|
|
Self::with_mode(test_name, false)
|
|
}
|
|
|
|
/// Create test data directory with filesystem watcher support
|
|
///
|
|
/// Uses home directory instead of temp on macOS because temp directories
|
|
/// don't reliably deliver filesystem events. This is required for tests
|
|
/// that use the filesystem watcher.
|
|
pub fn new_for_watcher(test_name: impl Into<String>) -> anyhow::Result<Self> {
|
|
Self::with_mode(test_name, true)
|
|
}
|
|
|
|
fn with_mode(test_name: impl Into<String>, use_home_for_watcher: bool) -> anyhow::Result<Self> {
|
|
let test_name = test_name.into();
|
|
|
|
// Choose base directory based on watcher requirements
|
|
let temp_base = if use_home_for_watcher {
|
|
// Use home directory for watcher support (macOS temp doesn't deliver events)
|
|
if cfg!(windows) {
|
|
std::env::var("USERPROFILE").unwrap_or_else(|_| {
|
|
std::env::var("TEMP").unwrap_or_else(|_| "C:\\temp".to_string())
|
|
})
|
|
} else {
|
|
std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string())
|
|
}
|
|
} else {
|
|
// Use temp directory for regular tests
|
|
if cfg!(windows) {
|
|
std::env::var("TEMP").unwrap_or_else(|_| "C:\\temp".to_string())
|
|
} else {
|
|
"/tmp".to_string()
|
|
}
|
|
};
|
|
|
|
// On Windows, add timestamp + counter to ensure uniqueness even across test runs
|
|
// This prevents conflicts with leftover files from previous runs where cleanup failed
|
|
let dir_name = if use_home_for_watcher {
|
|
#[cfg(windows)]
|
|
{
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
let id = COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
let timestamp = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_secs();
|
|
format!(".spacedrive_test_{}_{}_{}", test_name, timestamp, id)
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
format!(".spacedrive_test_{}", test_name)
|
|
}
|
|
} else {
|
|
#[cfg(windows)]
|
|
{
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
let id = COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
let timestamp = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_secs();
|
|
format!("spacedrive-test-{}-{}-{}", test_name, timestamp, id)
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
format!("spacedrive-test-{}", test_name)
|
|
}
|
|
};
|
|
|
|
let temp_path = PathBuf::from(temp_base).join(dir_name);
|
|
|
|
// On Windows, try to clean up any leftover directory from failed previous cleanup
|
|
// Retry a few times since file locks may be released shortly
|
|
#[cfg(windows)]
|
|
{
|
|
for attempt in 0..3 {
|
|
match std::fs::remove_dir_all(&temp_path) {
|
|
Ok(_) => break,
|
|
Err(e) if attempt < 2 => {
|
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
|
}
|
|
Err(_) => {
|
|
// After retries, ignore - we have unique timestamp+counter so no conflict
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
let _ = std::fs::remove_dir_all(&temp_path);
|
|
}
|
|
|
|
std::fs::create_dir_all(&temp_path)?;
|
|
|
|
// Create standard subdirectories
|
|
std::fs::create_dir_all(temp_path.join("core_data"))?;
|
|
std::fs::create_dir_all(temp_path.join("locations"))?;
|
|
std::fs::create_dir_all(temp_path.join("logs"))?;
|
|
|
|
// Check if snapshots are enabled
|
|
let snapshot_enabled = std::env::var("SD_TEST_SNAPSHOTS")
|
|
.map(|v| v == "1" || v.to_lowercase() == "true")
|
|
.unwrap_or(false);
|
|
|
|
let snapshot_manager = if snapshot_enabled {
|
|
Some(SnapshotManager::new(&test_name, &temp_path)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(Self {
|
|
test_name,
|
|
temp_path,
|
|
snapshot_manager,
|
|
})
|
|
}
|
|
|
|
/// Get path to temp directory root
|
|
pub fn path(&self) -> &Path {
|
|
&self.temp_path
|
|
}
|
|
|
|
/// Get path for core data (database, preferences, etc.)
|
|
pub fn core_data_path(&self) -> PathBuf {
|
|
self.temp_path.join("core_data")
|
|
}
|
|
|
|
/// Get path for test locations
|
|
pub fn locations_path(&self) -> PathBuf {
|
|
self.temp_path.join("locations")
|
|
}
|
|
|
|
/// Get path for test logs
|
|
pub fn logs_path(&self) -> PathBuf {
|
|
self.temp_path.join("logs")
|
|
}
|
|
|
|
/// Check if snapshots are enabled
|
|
pub fn snapshots_enabled(&self) -> bool {
|
|
self.snapshot_manager.is_some()
|
|
}
|
|
|
|
/// Get snapshot manager (if snapshots enabled)
|
|
pub fn snapshot_manager(&self) -> Option<&SnapshotManager> {
|
|
self.snapshot_manager.as_ref()
|
|
}
|
|
|
|
/// Get mutable snapshot manager (if snapshots enabled)
|
|
pub fn snapshot_manager_mut(&mut self) -> Option<&mut SnapshotManager> {
|
|
self.snapshot_manager.as_mut()
|
|
}
|
|
|
|
/// Get test name
|
|
pub fn test_name(&self) -> &str {
|
|
&self.test_name
|
|
}
|
|
}
|
|
|
|
impl Drop for TestDataDir {
|
|
fn drop(&mut self) {
|
|
// Capture final snapshot if enabled and not already captured
|
|
if let Some(manager) = &mut self.snapshot_manager {
|
|
if !manager.captured() {
|
|
// Use blocking operation in drop
|
|
let _ = manager.capture_final_blocking();
|
|
}
|
|
}
|
|
|
|
// Clean up temp directory
|
|
// On Windows, SQLite file locks may persist even after shutdown, causing
|
|
// removal to fail. Since tests use unique directories (via atomic counter),
|
|
// we can safely ignore cleanup failures. Windows will clean temp directories
|
|
// periodically.
|
|
if let Err(e) = std::fs::remove_dir_all(&self.temp_path) {
|
|
#[cfg(windows)]
|
|
{
|
|
// Silently ignore on Windows - file locks are expected
|
|
let _ = e;
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
eprintln!(
|
|
"Warning: Failed to clean up test directory {:?}: {}",
|
|
self.temp_path, e
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|