test(peer): consolidate temp dir helper
Move the repeated test TempDir implementations into a single peer test_support module. The shared helper keeps the existing automatic cleanup behavior and uses an atomic suffix plus timestamp so parallel tests do not collide on the same path. This is intentionally limited to test hygiene. It does not change the availability model, split download.rs, or touch production scan/install behavior beyond importing the shared helper from test modules. Test Plan: - git diff --check - just fmt - just clippy - just test Follow-up-Plan: FOLLOW_UP_2.md
This commit is contained in:
@@ -119,39 +119,12 @@ fn sync_parent_dir(_path: &Path) -> std::io::Result<()> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::*;
|
||||
|
||||
struct TempDir(PathBuf);
|
||||
|
||||
impl TempDir {
|
||||
fn new() -> Self {
|
||||
let mut path = std::env::temp_dir();
|
||||
path.push(format!(
|
||||
"lanspread-intent-{}-{}",
|
||||
std::process::id(),
|
||||
now_unix_secs()
|
||||
));
|
||||
path.push(format!("{:?}", std::thread::current().id()).replace(['(', ')'], ""));
|
||||
std::fs::create_dir_all(&path).expect("temp dir should be created");
|
||||
Self(path)
|
||||
}
|
||||
|
||||
fn path(&self) -> &Path {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TempDir {
|
||||
fn drop(&mut self) {
|
||||
let _ = std::fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
use crate::test_support::TempDir;
|
||||
|
||||
#[tokio::test]
|
||||
async fn tmp_write_without_rename_leaves_previous_intent_intact() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-intent");
|
||||
let previous = InstallIntent::new(
|
||||
"game",
|
||||
InstallIntentState::Updating,
|
||||
@@ -180,7 +153,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn schema_mismatch_is_treated_as_missing() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-intent");
|
||||
tokio::fs::write(
|
||||
intent_path(temp.path()),
|
||||
r#"{"schema_version":2,"id":"game","recorded_at":0,"state":"Updating"}"#,
|
||||
@@ -194,7 +167,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn mismatched_id_is_treated_as_missing() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-intent");
|
||||
tokio::fs::write(
|
||||
intent_path(temp.path()),
|
||||
r#"{"schema_version":1,"id":"other","recorded_at":0,"state":"Updating"}"#,
|
||||
@@ -208,7 +181,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn corrupt_intent_is_treated_as_missing() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-intent");
|
||||
tokio::fs::write(intent_path(temp.path()), b"not json")
|
||||
.await
|
||||
.expect("intent should be written");
|
||||
@@ -219,7 +192,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn old_manifest_hash_field_is_ignored_and_new_writes_omit_it() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-intent");
|
||||
tokio::fs::write(
|
||||
intent_path(temp.path()),
|
||||
r#"{"schema_version":1,"id":"game","recorded_at":0,"state":"Updating","eti_version":"20240101","manifest_hash":42}"#,
|
||||
|
||||
@@ -464,15 +464,11 @@ mod tests {
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
Arc,
|
||||
Mutex,
|
||||
atomic::{AtomicU64, Ordering},
|
||||
},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::install::unpack::UnpackFuture;
|
||||
use crate::{install::unpack::UnpackFuture, test_support::TempDir};
|
||||
|
||||
#[derive(Default)]
|
||||
struct FakeUnpacker {
|
||||
@@ -523,38 +519,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
struct TempDir(PathBuf);
|
||||
|
||||
static NEXT_TEMP_ID: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
impl TempDir {
|
||||
fn new() -> Self {
|
||||
let mut path = std::env::temp_dir();
|
||||
let unique_id = NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed);
|
||||
path.push(format!(
|
||||
"lanspread-install-{}-{}-{}",
|
||||
std::process::id(),
|
||||
unique_id,
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
));
|
||||
std::fs::create_dir_all(&path).expect("temp dir should be created");
|
||||
Self(path)
|
||||
}
|
||||
|
||||
fn game_root(&self) -> PathBuf {
|
||||
self.0.join("game")
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TempDir {
|
||||
fn drop(&mut self) {
|
||||
let _ = std::fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_file(path: &Path, bytes: &[u8]) {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent).expect("parent dir should be created");
|
||||
@@ -568,7 +532,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn install_success_promotes_staging_and_clears_intent() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
@@ -585,7 +549,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn install_unpacks_multiple_root_eti_archives_in_sorted_order() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join("b.eti"), b"archive");
|
||||
write_file(&root.join("a.eti"), b"archive");
|
||||
@@ -608,7 +572,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_failure_restores_previous_local() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
@@ -628,7 +592,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_commit_rename_failure_restores_previous_local() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
@@ -656,7 +620,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_success_promotes_new_local_and_removes_backup() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
@@ -676,7 +640,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn uninstall_removes_only_local_install() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
@@ -696,7 +660,7 @@ mod tests {
|
||||
async fn uninstall_delete_failure_restores_backup() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
let locked_dir = root.join("local").join("locked");
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
@@ -881,7 +845,7 @@ mod tests {
|
||||
];
|
||||
|
||||
for case in cases {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
seed_recovery_case(&root, &case);
|
||||
write_intent(
|
||||
@@ -909,7 +873,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn none_recovery_leaves_markerless_reserved_dirs_untouched() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join(".local.backup").join("user.txt"), b"user");
|
||||
|
||||
@@ -922,7 +886,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn download_recovery_sweeps_reserved_version_files() {
|
||||
let temp = TempDir::new();
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let root = temp.game_root();
|
||||
write_file(&root.join(VERSION_TMP_FILE), b"tmp");
|
||||
write_file(&root.join(VERSION_DISCARDED_FILE), b"old");
|
||||
@@ -937,13 +901,13 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn startup_recovery_skips_active_game_roots() {
|
||||
let temp = TempDir::new();
|
||||
let active_root = temp.0.join("active");
|
||||
let inactive_root = temp.0.join("inactive");
|
||||
let temp = TempDir::new("lanspread-install");
|
||||
let active_root = temp.path().join("active");
|
||||
let inactive_root = temp.path().join("inactive");
|
||||
write_file(&active_root.join(VERSION_TMP_FILE), b"tmp");
|
||||
write_file(&inactive_root.join(VERSION_TMP_FILE), b"tmp");
|
||||
|
||||
recover_on_startup(&temp.0, &HashSet::from(["active".to_string()]))
|
||||
recover_on_startup(temp.path(), &HashSet::from(["active".to_string()]))
|
||||
.await
|
||||
.expect("recovery should succeed");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user