use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard, OnceLock};
use std::time::{Duration, Instant};
pub async fn make_temp_dir(prefix: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!("{prefix}-{}", uuid::Uuid::new_v4()));
tokio::fs::create_dir_all(&dir).await.unwrap();
dir
}
pub fn test_config(dir: &Path) -> crate::config::Config {
crate::config::Config::new_for_test(dir)
}
pub fn restore_current_dir(dir: &Path) {
std::env::set_current_dir(dir).expect("restore current dir");
}
pub fn env_lock() -> MutexGuard<'static, ()> {
static ENV_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
ENV_LOCK
.get_or_init(|| Mutex::new(()))
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
pub struct AdminCategoryTestLockGuard {
path: PathBuf,
}
impl Drop for AdminCategoryTestLockGuard {
fn drop(&mut self) {
let _ = std::fs::remove_dir(&self.path);
}
}
pub async fn admin_category_test_lock() -> AdminCategoryTestLockGuard {
let path = std::env::temp_dir().join("shine-admin-category-test.lock");
let deadline = Instant::now() + Duration::from_secs(60);
loop {
match tokio::fs::create_dir(&path).await {
Ok(()) => return AdminCategoryTestLockGuard { path },
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
if Instant::now() >= deadline {
let _ = tokio::fs::remove_dir(&path).await;
continue;
}
tokio::time::sleep(Duration::from_millis(50)).await;
}
Err(_) => return AdminCategoryTestLockGuard { path },
}
}
}