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