• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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