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.
11 ///
12 /// Warning: If you use this, add your test to ROOT_TESTS in tools/impl/test_config.py
13 /// This will ensure they are not run when passwordless root is unavailable.
call_test_with_sudo(name: &str)14 pub fn call_test_with_sudo(name: &str) {
15 check_can_sudo();
16
17 let result = Command::new("sudo")
18 .args([
19 "--preserve-env",
20 current_exe().unwrap().to_str().unwrap(),
21 "--nocapture",
22 "--ignored",
23 "--exact",
24 name,
25 ])
26 .status()
27 .unwrap();
28
29 if !result.success() {
30 panic!("Test {name} failed in child process.");
31 }
32 }
33
34 /// Checks to see if user has entered their password for sudo.
check_can_sudo()35 pub fn check_can_sudo() {
36 // Try a passwordless sudo first to provide a proper error message.
37 // Note: The combination of SUDO_ASKPASS and --askpass will fail if sudo has to ask for a
38 // password. When sudo needs to ask for a password, it will call "false" and fail without
39 // prompting.
40 let can_sudo = Command::new("sudo")
41 .args(["--askpass", "true"]) // Use an askpass program to ask for a password
42 .env("SUDO_ASKPASS", "false") // Set the askpass program to false
43 .output()
44 .unwrap();
45 if !can_sudo.status.success() {
46 panic!("This test need to be run as root or with passwordless sudo.");
47 }
48 }
49
50 /// Assert repeatedly until it's true
51 ///
52 /// Runs the provided `$cond` closure until it returns true. If it does not return true after
53 /// `$tries` times, it will panic.
54 /// There is no delay between polls, but the `$cond` can sleep as needed.
55 #[macro_export]
56 macro_rules! poll_assert {
57 ($tries: tt, $cond:expr) => {
58 $crate::test_utils::poll_assert_impl(stringify!($cond), $tries, $cond)
59 };
60 }
61
62 /// Implementation of [poll_assert]
poll_assert_impl(msg: &'static str, tries: usize, poll_fn: impl Fn() -> bool)63 pub fn poll_assert_impl(msg: &'static str, tries: usize, poll_fn: impl Fn() -> bool) {
64 for _ in 0..tries {
65 if poll_fn() {
66 return;
67 }
68 }
69 panic!("Still failing after {} tries: {}", tries, msg);
70 }
71