mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-09 03:57:24 +00:00
tools/run_tests: Run some tests as root
Testing tap functionality requires root privileges. The crosvmdev user of our dev_container is set up for passwordless sudo, so we can seamlessly execute these tests via sudo. For running on the developer workstation directly, this will prompt for a password, which is disruptive to workflows. The --no-root option can be used to prevent this and skip the tests in question. BUG=None TEST=tools/run_tests [--no-root] Change-Id: I731887837affceb76152466f0006c4ee51a19234 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4063237 Reviewed-by: Zihan Chen <zihanchen@google.com> Commit-Queue: Dennis Kempin <denniskempin@google.com>
This commit is contained in:
parent
354bd50590
commit
b157bda3ee
5 changed files with 43 additions and 8 deletions
|
@ -11,13 +11,11 @@ use net_util::MacAddress;
|
||||||
use net_util::TapTCommon;
|
use net_util::TapTCommon;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "Requires root privileges"]
|
|
||||||
fn tap_create() {
|
fn tap_create() {
|
||||||
Tap::new(true, false).unwrap();
|
Tap::new(true, false).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "Requires root privileges"]
|
|
||||||
fn tap_configure() {
|
fn tap_configure() {
|
||||||
let tap = Tap::new(true, false).unwrap();
|
let tap = Tap::new(true, false).unwrap();
|
||||||
let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap();
|
let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap();
|
||||||
|
@ -32,7 +30,6 @@ fn tap_configure() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "Requires root privileges"]
|
|
||||||
fn tap_enable() {
|
fn tap_enable() {
|
||||||
let tap = Tap::new(true, false).unwrap();
|
let tap = Tap::new(true, false).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,11 @@ class TestOption(enum.Enum):
|
||||||
# This test needs longer than usual to run.
|
# This test needs longer than usual to run.
|
||||||
LARGE = "large"
|
LARGE = "large"
|
||||||
|
|
||||||
|
# Integration test that requires root privileges to execute.
|
||||||
|
# Note that this does not apply to unit tests, which will never be allowed privileged access
|
||||||
|
# to the system.
|
||||||
|
REQUIRES_ROOT = "requires_root"
|
||||||
|
|
||||||
|
|
||||||
# Configuration to restrict how and where tests of a certain crate can
|
# Configuration to restrict how and where tests of a certain crate can
|
||||||
# be build and run.
|
# be build and run.
|
||||||
|
@ -95,6 +100,7 @@ CRATE_OPTIONS: Dict[str, List[TestOption]] = {
|
||||||
], # b/181674144
|
], # b/181674144
|
||||||
"libvda": [TestOption.DO_NOT_RUN], # b/202293971
|
"libvda": [TestOption.DO_NOT_RUN], # b/202293971
|
||||||
"sandbox": [TestOption.DO_NOT_RUN],
|
"sandbox": [TestOption.DO_NOT_RUN],
|
||||||
|
"net_util": [TestOption.REQUIRES_ROOT],
|
||||||
}
|
}
|
||||||
|
|
||||||
for name in WIN64_DISABLED_CRATES:
|
for name in WIN64_DISABLED_CRATES:
|
||||||
|
|
|
@ -16,7 +16,7 @@ from typing import Dict, Iterable, List, NamedTuple, Optional
|
||||||
|
|
||||||
from . import test_target, testvm
|
from . import test_target, testvm
|
||||||
from .common import all_tracked_files, very_verbose
|
from .common import all_tracked_files, very_verbose
|
||||||
from .test_config import BUILD_FEATURES, CRATE_OPTIONS, TestOption
|
from .test_config import CRATE_OPTIONS, TestOption
|
||||||
from .test_target import TestTarget, Triple
|
from .test_target import TestTarget, Triple
|
||||||
|
|
||||||
USAGE = """\
|
USAGE = """\
|
||||||
|
@ -119,7 +119,9 @@ def get_workspace_excludes(build_triple: Triple):
|
||||||
yield crate
|
yield crate
|
||||||
|
|
||||||
|
|
||||||
def should_run_executable(executable: Executable, target: TestTarget, test_names: List[str]):
|
def should_run_executable(
|
||||||
|
executable: Executable, target: TestTarget, test_names: List[str], execute_as_root: bool
|
||||||
|
):
|
||||||
arch = target.build_triple.arch
|
arch = target.build_triple.arch
|
||||||
options = CRATE_OPTIONS.get(executable.crate_name, [])
|
options = CRATE_OPTIONS.get(executable.crate_name, [])
|
||||||
if TestOption.DO_NOT_RUN in options:
|
if TestOption.DO_NOT_RUN in options:
|
||||||
|
@ -132,6 +134,8 @@ def should_run_executable(executable: Executable, target: TestTarget, test_names
|
||||||
return False
|
return False
|
||||||
if TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL in options and not target.is_native:
|
if TestOption.DO_NOT_RUN_ON_FOREIGN_KERNEL in options and not target.is_native:
|
||||||
return False
|
return False
|
||||||
|
if TestOption.REQUIRES_ROOT in options and not execute_as_root:
|
||||||
|
return False
|
||||||
if test_names:
|
if test_names:
|
||||||
for name in test_names:
|
for name in test_names:
|
||||||
if fnmatch.fnmatch(executable.name, name):
|
if fnmatch.fnmatch(executable.name, name):
|
||||||
|
@ -366,6 +370,8 @@ def execute_integration_test(
|
||||||
"""
|
"""
|
||||||
args: List[str] = ["--test-threads=1"]
|
args: List[str] = ["--test-threads=1"]
|
||||||
binary_path = executable.binary_path
|
binary_path = executable.binary_path
|
||||||
|
options = CRATE_OPTIONS.get(executable.crate_name, [])
|
||||||
|
execute_as_root = TestOption.REQUIRES_ROOT in options
|
||||||
|
|
||||||
previous_attempts: List[ExecutableResults] = []
|
previous_attempts: List[ExecutableResults] = []
|
||||||
for i in range(1, attempts + 1):
|
for i in range(1, attempts + 1):
|
||||||
|
@ -380,6 +386,7 @@ def execute_integration_test(
|
||||||
generate_profile=True,
|
generate_profile=True,
|
||||||
stdout=None if VERBOSE else subprocess.PIPE,
|
stdout=None if VERBOSE else subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
|
execute_as_root=execute_as_root,
|
||||||
)
|
)
|
||||||
profile_files: List[Path] = []
|
profile_files: List[Path] = []
|
||||||
if collect_coverage:
|
if collect_coverage:
|
||||||
|
@ -528,6 +535,13 @@ def generate_lcov(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def sudo_is_passwordless():
|
||||||
|
# Run with --askpass but no askpass set, succeeds only if passwordless sudo
|
||||||
|
# is available.
|
||||||
|
(ret, _) = subprocess.getstatusoutput("SUDO_ASKPASS=false sudo --askpass true")
|
||||||
|
return ret == 0
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(usage=USAGE)
|
parser = argparse.ArgumentParser(usage=USAGE)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -581,6 +595,11 @@ def main():
|
||||||
"--crosvm-direct",
|
"--crosvm-direct",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-root",
|
||||||
|
action="store_true",
|
||||||
|
help="Disables tests that require to be run as root.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--repeat",
|
"--repeat",
|
||||||
type=int,
|
type=int,
|
||||||
|
@ -649,6 +668,7 @@ def main():
|
||||||
integration_test_target = test_target.TestTarget("vm:aarch64", build_target)
|
integration_test_target = test_target.TestTarget("vm:aarch64", build_target)
|
||||||
elif str(build_target) == "x86_64-pc-windows-gnu" and os.name == "nt":
|
elif str(build_target) == "x86_64-pc-windows-gnu" and os.name == "nt":
|
||||||
integration_test_target = unit_test_target
|
integration_test_target = unit_test_target
|
||||||
|
args.no_root = True
|
||||||
else:
|
else:
|
||||||
# Do not run integration tests in unrecognized scenarios.
|
# Do not run integration tests in unrecognized scenarios.
|
||||||
integration_test_target = None
|
integration_test_target = None
|
||||||
|
@ -661,6 +681,14 @@ def main():
|
||||||
print("Unit Test target:", unit_test_target or "skip")
|
print("Unit Test target:", unit_test_target or "skip")
|
||||||
print("Integration Test target:", integration_test_target or "skip")
|
print("Integration Test target:", integration_test_target or "skip")
|
||||||
|
|
||||||
|
if not args.no_root and integration_test_target and integration_test_target.is_host:
|
||||||
|
if not sudo_is_passwordless():
|
||||||
|
print()
|
||||||
|
print("Prompting for sudo password to execute privileged tests.")
|
||||||
|
print("If you'd like to prevent this, use the --no-root option.")
|
||||||
|
subprocess.check_call(["sudo", "true"])
|
||||||
|
print()
|
||||||
|
|
||||||
main_target = integration_test_target or unit_test_target
|
main_target = integration_test_target or unit_test_target
|
||||||
if not main_target:
|
if not main_target:
|
||||||
return
|
return
|
||||||
|
@ -692,7 +720,7 @@ def main():
|
||||||
test_executables = [
|
test_executables = [
|
||||||
e
|
e
|
||||||
for e in executables
|
for e in executables
|
||||||
if e.is_test and should_run_executable(e, main_target, args.test_names)
|
if e.is_test and should_run_executable(e, main_target, args.test_names, not args.no_root)
|
||||||
]
|
]
|
||||||
|
|
||||||
all_results: List[ExecutableResults] = []
|
all_results: List[ExecutableResults] = []
|
||||||
|
|
|
@ -392,6 +392,7 @@ def exec_file_on_target(
|
||||||
args: List[str] = [],
|
args: List[str] = [],
|
||||||
extra_files: List[Path] = [],
|
extra_files: List[Path] = [],
|
||||||
generate_profile: bool = False,
|
generate_profile: bool = False,
|
||||||
|
execute_as_root: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
):
|
):
|
||||||
"""Executes a file on the test target.
|
"""Executes a file on the test target.
|
||||||
|
@ -432,11 +433,14 @@ def exec_file_on_target(
|
||||||
env["LLVM_PROFILE_FILE"] = f"{profile_prefix}.%p"
|
env["LLVM_PROFILE_FILE"] = f"{profile_prefix}.%p"
|
||||||
|
|
||||||
cmd_line = [*prefix, str(filepath), *args]
|
cmd_line = [*prefix, str(filepath), *args]
|
||||||
|
if execute_as_root:
|
||||||
|
cmd_line = ["sudo", *cmd_line]
|
||||||
return subprocess.run(
|
return subprocess.run(
|
||||||
cmd_line,
|
cmd_line,
|
||||||
env=env,
|
env=env,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
text=True,
|
text=True,
|
||||||
|
shell=False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -97,7 +97,7 @@ commands=(
|
||||||
|
|
||||||
if [ "$ALL" == true ]; then
|
if [ "$ALL" == true ]; then
|
||||||
commands+=(
|
commands+=(
|
||||||
"./tools/run_tests"
|
"./tools/run_tests --no-root"
|
||||||
"./tools/run_tests --platform=mingw64"
|
"./tools/run_tests --platform=mingw64"
|
||||||
"./tools/clippy --platform=mingw64"
|
"./tools/clippy --platform=mingw64"
|
||||||
"$(aarch64_wrapper) ./tools/run_tests --platform=aarch64"
|
"$(aarch64_wrapper) ./tools/run_tests --platform=aarch64"
|
||||||
|
@ -106,7 +106,7 @@ if [ "$ALL" == true ]; then
|
||||||
)
|
)
|
||||||
elif [ "$QUICK" != true ]; then
|
elif [ "$QUICK" != true ]; then
|
||||||
commands+=(
|
commands+=(
|
||||||
"./tools/run_tests"
|
"./tools/run_tests --no-root"
|
||||||
"$(aarch64_wrapper) ./tools/run_tests --platform=aarch64 --unit-tests"
|
"$(aarch64_wrapper) ./tools/run_tests --platform=aarch64 --unit-tests"
|
||||||
"./tools/run_tests --platform=mingw64 --unit-tests"
|
"./tools/run_tests --platform=mingw64 --unit-tests"
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue