]> git.ipfire.org Git - thirdparty/dracut-ng.git/commitdiff
fix(cpio): use mutex to avoid multi-threaded failures
authorDavid Disseldorp <ddiss@suse.de>
Thu, 25 Sep 2025 04:21:18 +0000 (06:21 +0200)
committerLaszlo <laszlo.gombos@gmail.com>
Thu, 25 Sep 2025 19:02:05 +0000 (15:02 -0400)
`cargo test` runs tests in parallel by default, unless the
--test-threads=1 parameter is provided. This causes the dracut-cpio
unit tests to fail due to their working directory changes.

Add a mutex and hold it over the course of the changed directory, so
that the --test-threads=1 parameter is no longer needed.

Suggested-by: Benjamin Drung <bdrung@posteo.de>
Fixes: https://github.com/dracut-ng/dracut-ng/issues/1702
src/dracut-cpio/src/main.rs

index 7d409c8fe5f944056f5a98fe325306a5d865077a..70a7e6d2faffd933c418a6c2183d85b19761603c 100644 (file)
@@ -813,8 +813,6 @@ fn main() -> std::io::Result<()> {
     Ok(())
 }
 
-// tests change working directory, so need to be run with:
-// cargo test -- --test-threads=1 --nocapture
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -823,7 +821,12 @@ mod tests {
     use std::path::PathBuf;
     use std::process::{Command, Stdio};
 
-    struct TempWorkDir {
+    pub static TEST_LOCK: std::sync::Mutex<u32> = std::sync::Mutex::new(0);
+
+    struct TempWorkDir<'a> {
+        // Hold a mutex alongside directory change, to avoid failures due to
+        // multi-threaded "cargo test".
+        cwd_lock: std::sync::MutexGuard<'a, u32>,
         prev_dir: PathBuf,
         parent_tmp_dir: PathBuf,
         cleanup_files: Vec<PathBuf>,
@@ -831,10 +834,10 @@ mod tests {
         ignore_cleanup: bool, // useful for debugging
     }
 
-    impl TempWorkDir {
+    impl TempWorkDir<'_> {
         // create a temporary directory under CWD and cd into it.
         // The directory will be cleaned up when twd goes out of scope.
-        pub fn new() -> TempWorkDir {
+        pub fn new() -> TempWorkDir<'static> {
             let mut buf = [0u8; 16];
             let mut s = String::from("cpio-selftest-");
             fs::File::open("/dev/urandom")
@@ -844,7 +847,14 @@ mod tests {
             for i in &buf {
                 s.push_str(&format!("{:02x}", i).to_string());
             }
+
             let mut twd = TempWorkDir {
+                cwd_lock: TEST_LOCK.lock().unwrap_or_else(|mut e| {
+                    // another test panicked while holding the lock
+                    **e.get_mut() = 1;
+                    TEST_LOCK.clear_poison();
+                    e.into_inner()
+                }),
                 prev_dir: env::current_dir().unwrap(),
                 parent_tmp_dir: {
                     let mut t = env::current_dir().unwrap().clone();
@@ -908,7 +918,7 @@ mod tests {
         }
     }
 
-    impl Drop for TempWorkDir {
+    impl Drop for TempWorkDir<'_> {
         fn drop(&mut self) {
             for f in self.cleanup_files.iter().rev() {
                 if self.ignore_cleanup {
@@ -934,6 +944,7 @@ mod tests {
             }
             println!("returning cwd to {}", self.prev_dir.display());
             env::set_current_dir(self.prev_dir.as_path()).unwrap();
+            // cwd_lock should be dropped automatically
         }
     }