1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::env::current_exe;
6 use std::process::Command;
7
8 /// The tests below require root privileges.
9 /// Re-invoke the test binary to execute the specified test with sudo. The test will fail if
10 /// passwordless sudo is not available.
call_test_with_sudo(name: &str)11 pub fn call_test_with_sudo(name: &str) {
12 check_can_sudo();
13
14 let result = Command::new("sudo")
15 .args([
16 "--preserve-env",
17 current_exe().unwrap().to_str().unwrap(),
18 "--nocapture",
19 "--ignored",
20 "--exact",
21 name,
22 ])
23 .status()
24 .unwrap();
25
26 if !result.success() {
27 panic!("Test {name} failed in child process.");
28 }
29 }
30
31 /// Checks to see if user has entered their password for sudo.
check_can_sudo()32 pub fn check_can_sudo() {
33 // Try a passwordless sudo first to provide a proper error message.
34 // Note: The combination of SUDO_ASKPASS and --askpass will fail if sudo has to ask for a
35 // password. When sudo needs to ask for a password, it will call "false" and fail without
36 // prompting.
37 let can_sudo = Command::new("sudo")
38 .args(["--askpass", "true"]) // Use an askpass program to ask for a password
39 .env("SUDO_ASKPASS", "false") // Set the askpass program to false
40 .output()
41 .unwrap();
42 if !can_sudo.status.success() {
43 panic!("This test need to be run as root or with passwordless sudo.");
44 }
45 }
46
47 /// Assert repeatedly until it's true
48 ///
49 /// Runs the provided `$cond` closure until it returns true. If it does not return true after
50 /// `$tries` times, it will panic.
51 /// There is no delay between polls, but the `$cond` can sleep as needed.
52 #[macro_export]
53 macro_rules! poll_assert {
54 ($tries: tt, $cond:expr) => {
55 $crate::test_utils::poll_assert_impl(stringify!($cond), $tries, $cond)
56 };
57 }
58
59 /// Implementation of [poll_assert]
poll_assert_impl(msg: &'static str, tries: usize, poll_fn: impl Fn() -> bool)60 pub fn poll_assert_impl(msg: &'static str, tries: usize, poll_fn: impl Fn() -> bool) {
61 for _ in 0..tries {
62 if poll_fn() {
63 return;
64 }
65 }
66 panic!("Still failing after {} tries: {}", tries, msg);
67 }
68