From c2505841e005da57f4c5ff9d3e09ffb5dc9ca2b8 Mon Sep 17 00:00:00 2001 From: sreehari prasad <52113972+matrixhead@users.noreply.github.com> Date: Sat, 1 Feb 2025 23:31:49 +0530 Subject: [PATCH] Tests: provides easy mount of temp fs (#7249) --- tests/by-util/test_base64.rs | 2 +- tests/by-util/test_cp.rs | 14 +++----- tests/by-util/test_dd.rs | 2 +- tests/by-util/test_du.rs | 2 +- tests/by-util/test_env.rs | 6 ++-- tests/by-util/test_pwd.rs | 2 +- tests/common/util.rs | 64 +++++++++++++++++++++++++++++++++++- tests/test_util_name.rs | 16 ++++----- 8 files changed, 82 insertions(+), 26 deletions(-) diff --git a/tests/by-util/test_base64.rs b/tests/by-util/test_base64.rs index 29b9edf02..de6cb48f9 100644 --- a/tests/by-util/test_base64.rs +++ b/tests/by-util/test_base64.rs @@ -232,7 +232,7 @@ fn test_manpage() { let test_scenario = TestScenario::new(""); - let child = Command::new(test_scenario.bin_path) + let child = Command::new(&test_scenario.bin_path) .arg("manpage") .arg("base64") .stdin(Stdio::piped()) diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index 072f78aed..69b15e80d 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -2288,7 +2288,7 @@ fn test_cp_one_file_system() { use crate::common::util::AtPath; use walkdir::WalkDir; - let scene = TestScenario::new(util_name!()); + let mut scene = TestScenario::new(util_name!()); let at = &scene.fixtures; // Test must be run as root (or with `sudo -E`) @@ -2304,14 +2304,8 @@ fn test_cp_one_file_system() { let mountpoint_path = &at_src.plus_as_string(TEST_MOUNT_MOUNTPOINT); scene - .cmd("mount") - .arg("-t") - .arg("tmpfs") - .arg("-o") - .arg("size=640k") // ought to be enough - .arg("tmpfs") - .arg(mountpoint_path) - .succeeds(); + .mount_temp_fs(mountpoint_path) + .expect("mounting tmpfs failed"); at_src.touch(TEST_MOUNT_OTHER_FILESYSTEM_FILE); @@ -2324,7 +2318,7 @@ fn test_cp_one_file_system() { .succeeds(); // Ditch the mount before the asserts - scene.cmd("umount").arg(mountpoint_path).succeeds(); + scene.umount_temp_fs(); assert!(!at_dst.file_exists(TEST_MOUNT_OTHER_FILESYSTEM_FILE)); // Check if the other files were copied from the source folder hierarchy diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 57a293320..465a68561 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -1683,7 +1683,7 @@ fn test_reading_partial_blocks_from_fifo() { fn test_reading_partial_blocks_from_fifo_unbuffered() { // Create the FIFO. let ts = TestScenario::new(util_name!()); - let at = ts.fixtures; + let at = &ts.fixtures; at.mkfifo("fifo"); let fifoname = at.plus_as_string("fifo"); diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index ecbf58b11..04185bce2 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -655,7 +655,7 @@ fn test_du_time() { #[cfg(feature = "touch")] fn birth_supported() -> bool { let ts = TestScenario::new(util_name!()); - let m = match std::fs::metadata(ts.fixtures.subdir) { + let m = match std::fs::metadata(&ts.fixtures.subdir) { Ok(m) => m, Err(e) => panic!("{}", e), }; diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 2a5320295..2d1e9feaf 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -137,7 +137,7 @@ fn test_debug_2() { let result = ts .ucmd() .arg("-vv") - .arg(ts.bin_path) + .arg(&ts.bin_path) .args(&["echo", "hello2"]) .succeeds(); result.stderr_matches( @@ -165,7 +165,7 @@ fn test_debug1_part_of_string_arg() { let result = ts .ucmd() .arg("-vS FOO=BAR") - .arg(ts.bin_path) + .arg(&ts.bin_path) .args(&["echo", "hello1"]) .succeeds(); result.stderr_matches( @@ -186,7 +186,7 @@ fn test_debug2_part_of_string_arg() { let result = ts .ucmd() .arg("-vvS FOO=BAR") - .arg(ts.bin_path) + .arg(&ts.bin_path) .args(&["echo", "hello2"]) .succeeds(); result.stderr_matches( diff --git a/tests/by-util/test_pwd.rs b/tests/by-util/test_pwd.rs index 89341c0c3..3966bbef0 100644 --- a/tests/by-util/test_pwd.rs +++ b/tests/by-util/test_pwd.rs @@ -31,7 +31,7 @@ fn test_deleted_dir() { use std::process::Command; let ts = TestScenario::new(util_name!()); - let at = ts.fixtures; + let at = &ts.fixtures; let output = Command::new("sh") .arg("-c") .arg(format!( diff --git a/tests/common/util.rs b/tests/common/util.rs index 844618def..7a5e73a12 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -4,7 +4,7 @@ // file that was distributed with this source code. //spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured scmd SHLVL canonicalized openpty -//spell-checker: ignore (linux) winsize xpixel ypixel setrlimit FSIZE SIGBUS SIGSEGV sigbus +//spell-checker: ignore (linux) winsize xpixel ypixel setrlimit FSIZE SIGBUS SIGSEGV sigbus tmpfs #![allow(dead_code)] #![allow( @@ -1169,6 +1169,8 @@ pub struct TestScenario { pub util_name: String, pub fixtures: AtPath, tmpd: Rc, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + tmp_fs_mountpoint: Option, } impl TestScenario { @@ -1182,6 +1184,8 @@ impl TestScenario { util_name: util_name.as_ref().into(), fixtures: AtPath::new(tmpd.as_ref().path()), tmpd, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + tmp_fs_mountpoint: None, }; let mut fixture_path_builder = env::current_dir().unwrap(); fixture_path_builder.push(TESTS_DIR); @@ -1215,6 +1219,44 @@ impl TestScenario { pub fn ccmd>(&self, util_name: S) -> UCommand { UCommand::with_util(util_name, self.tmpd.clone()) } + + /// Mounts a temporary filesystem at the specified mount point. + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + pub fn mount_temp_fs(&mut self, mount_point: &str) -> core::result::Result<(), String> { + if self.tmp_fs_mountpoint.is_some() { + return Err("already mounted".to_string()); + } + let cmd_result = self + .cmd("mount") + .arg("-t") + .arg("tmpfs") + .arg("-o") + .arg("size=640k") // ought to be enough + .arg("tmpfs") + .arg(mount_point) + .run(); + if !cmd_result.succeeded() { + return Err(format!("mount failed: {}", cmd_result.stderr_str())); + } + self.tmp_fs_mountpoint = Some(mount_point.to_string()); + Ok(()) + } + + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + /// Unmounts the temporary filesystem if it is currently mounted. + pub fn umount_temp_fs(&mut self) { + if let Some(mount_point) = self.tmp_fs_mountpoint.as_ref() { + self.cmd("umount").arg(mount_point).succeeds(); + self.tmp_fs_mountpoint = None; + } + } +} + +impl Drop for TestScenario { + fn drop(&mut self) { + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + self.umount_temp_fs(); + } } #[cfg(unix)] @@ -4007,4 +4049,24 @@ mod tests { .stdout_is(expected); std::assert_eq!(p_umask, get_umask()); // make sure parent umask didn't change } + + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + #[test] + fn test_mount_temp_fs() { + let mut scene = TestScenario::new("util"); + let at = &scene.fixtures; + // Test must be run as root (or with `sudo -E`) + if scene.cmd("whoami").run().stdout_str() != "root\n" { + return; + } + at.mkdir("mountpoint"); + let mountpoint = at.plus("mountpoint"); + scene.mount_temp_fs(mountpoint.to_str().unwrap()).unwrap(); + scene + .cmd("df") + .arg("-h") + .arg(mountpoint) + .succeeds() + .stdout_contains("tmpfs"); + } } diff --git a/tests/test_util_name.rs b/tests/test_util_name.rs index 689c38214..2af85d42e 100644 --- a/tests/test_util_name.rs +++ b/tests/test_util_name.rs @@ -35,7 +35,7 @@ fn execution_phrase_single() { use std::process::Command; let scenario = TestScenario::new("ls"); - symlink_file(scenario.bin_path, scenario.fixtures.plus("uu-ls")).unwrap(); + symlink_file(&scenario.bin_path, scenario.fixtures.plus("uu-ls")).unwrap(); let output = Command::new(scenario.fixtures.plus("uu-ls")) .arg("--some-invalid-arg") .output() @@ -56,7 +56,7 @@ fn util_name_double() { }; let scenario = TestScenario::new("sort"); - let mut child = Command::new(scenario.bin_path) + let mut child = Command::new(&scenario.bin_path) .arg("sort") .stdin(Stdio::piped()) .stderr(Stdio::piped()) @@ -78,7 +78,7 @@ fn util_name_single() { }; let scenario = TestScenario::new("sort"); - symlink_file(scenario.bin_path, scenario.fixtures.plus("uu-sort")).unwrap(); + symlink_file(&scenario.bin_path, scenario.fixtures.plus("uu-sort")).unwrap(); let mut child = Command::new(scenario.fixtures.plus("uu-sort")) .stdin(Stdio::piped()) .stderr(Stdio::piped()) @@ -102,7 +102,7 @@ fn util_invalid_name_help() { }; let scenario = TestScenario::new("invalid_name"); - symlink_file(scenario.bin_path, scenario.fixtures.plus("invalid_name")).unwrap(); + symlink_file(&scenario.bin_path, scenario.fixtures.plus("invalid_name")).unwrap(); let child = Command::new(scenario.fixtures.plus("invalid_name")) .arg("--help") .stdin(Stdio::piped()) @@ -138,7 +138,7 @@ fn util_non_utf8_name_help() { let scenario = TestScenario::new("invalid_name"); let non_utf8_path = scenario.fixtures.plus(OsStr::from_bytes(b"\xff")); - symlink_file(scenario.bin_path, &non_utf8_path).unwrap(); + symlink_file(&scenario.bin_path, &non_utf8_path).unwrap(); let child = Command::new(&non_utf8_path) .arg("--help") .stdin(Stdio::piped()) @@ -166,7 +166,7 @@ fn util_invalid_name_invalid_command() { }; let scenario = TestScenario::new("invalid_name"); - symlink_file(scenario.bin_path, scenario.fixtures.plus("invalid_name")).unwrap(); + symlink_file(&scenario.bin_path, scenario.fixtures.plus("invalid_name")).unwrap(); let child = Command::new(scenario.fixtures.plus("invalid_name")) .arg("definitely_invalid") .stdin(Stdio::piped()) @@ -192,7 +192,7 @@ fn util_completion() { }; let scenario = TestScenario::new("completion"); - let child = Command::new(scenario.bin_path) + let child = Command::new(&scenario.bin_path) .arg("completion") .arg("true") .arg("powershell") @@ -220,7 +220,7 @@ fn util_manpage() { }; let scenario = TestScenario::new("completion"); - let child = Command::new(scenario.bin_path) + let child = Command::new(&scenario.bin_path) .arg("manpage") .arg("true") .stdin(Stdio::piped())