mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 20:48:55 +00:00
2e93874a25
This CL adds a new "root" test suite for trace_marker integration tests, since the tests require root to run in order to access the kernel's tracefs mounted partition. BUG=b:273379306 TEST=CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='sudo -E' cargo test --features=trace_marker Change-Id: I4656374023d91d87959f6ce0d59eb9e51bdc77bd Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4349039 Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org> Auto-Submit: Morg <morg@chromium.org> Commit-Queue: Morg <morg@chromium.org>
157 lines
5.1 KiB
Rust
157 lines
5.1 KiB
Rust
// Copyright 2023 The ChromiumOS Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
use std::env;
|
|
use std::env::current_exe;
|
|
use std::fs::File;
|
|
use std::io::BufRead;
|
|
use std::io::BufReader;
|
|
use std::process::Command;
|
|
|
|
use cros_tracing::*;
|
|
|
|
const TRACE_FILE: &str = "/sys/kernel/tracing/trace";
|
|
const TRACE_CONTEXT_INFO: &str = "/sys/kernel/tracing/options/context-info";
|
|
const TRACING_ON: &str = "/sys/kernel/tracing/tracing_on";
|
|
|
|
fn setup() {
|
|
// Make sure tracing is enabled.
|
|
std::fs::write(TRACING_ON, b"1").unwrap();
|
|
// Remove extra noise from trace file for easier parsing
|
|
std::fs::write(TRACE_CONTEXT_INFO, b"0").unwrap();
|
|
// Clear the trace backlog by writing an empty string, in case we have extra
|
|
// rogue messages in the trace buffer
|
|
std::fs::write(TRACE_FILE, b"").unwrap();
|
|
|
|
init();
|
|
}
|
|
|
|
fn cleanup() {
|
|
// Stop tracing.
|
|
std::fs::write(TRACING_ON, b"0").unwrap();
|
|
// Reset trace file format back to how it was.
|
|
std::fs::write(TRACE_CONTEXT_INFO, b"1").unwrap();
|
|
}
|
|
|
|
fn trace_simple_print() {
|
|
let reader = BufReader::new(File::open(TRACE_FILE).ok().unwrap());
|
|
|
|
let message1 = "Simple print test one";
|
|
let message2 = "Simple print test two";
|
|
|
|
trace_simple_print!("{message1}");
|
|
trace_simple_print!("{message2}");
|
|
|
|
// Read contents of the file, skip the first two lines which are just a preamble.
|
|
let mut lines = reader.lines().map(|l| l.unwrap()).skip(2);
|
|
|
|
// Check the printed lines are in order.
|
|
// We need to use contains instead of matching the full string because each time we
|
|
// print to trace_marker we will get unique data like PID and timestamps that we cannot
|
|
// rely on, but the contents of the message itself should always contain our string.
|
|
assert!(lines.next().unwrap().contains(message1));
|
|
assert!(lines.next().unwrap().contains(message2));
|
|
}
|
|
|
|
fn push_descriptors() {
|
|
let mut keep_rds = Vec::new();
|
|
|
|
push_descriptors!(&mut keep_rds);
|
|
|
|
// We cannot know the fd of the trace marker file beforehand but we can check if there
|
|
// is only one fd in the vector it means we can assume it's the trace_marker one.
|
|
assert_eq!(keep_rds.len(), 1);
|
|
}
|
|
|
|
/// Executes the individual test `name` with root, in the same environment as the test suite,
|
|
/// if it does not already have root privileges. Sudo needs to be set up to run passwordless
|
|
/// or have cached credentials. The parent process spawns a child that runs with higher privileges
|
|
/// for that individual `name` test, and then waits for its completion.
|
|
///
|
|
/// Returns `true` if the test suite already has root privilege, in which case it
|
|
/// proceeds to run the test without forking, otherwise it returns `false` to let the
|
|
/// test suite know that the test was run by the child process instead.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `name` - Name of the individual test to execute as root
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// libtest_mimic::Trial::test("test_with_root", move || {
|
|
/// if run_test_with_root("test_with_root") {
|
|
/// // This part only executes with root
|
|
/// function_to_test();
|
|
/// }
|
|
/// Ok(())
|
|
/// });
|
|
/// ```
|
|
fn run_test_with_root(name: &str) -> bool {
|
|
// This test needs to run as root, so if we aren't root we need to re-execute ourselves
|
|
// with sudo.
|
|
let is_root = match env::var("USER") {
|
|
Ok(val) => val == "root",
|
|
Err(_) => false,
|
|
};
|
|
|
|
if !is_root {
|
|
let can_sudo = Command::new("sudo")
|
|
.args(["--askpass", "true"])
|
|
.env("SUDO_ASKPASS", "false")
|
|
.output()
|
|
.unwrap();
|
|
if !can_sudo.status.success() {
|
|
panic!("This test needs to be run as root or with passwordless sudo.");
|
|
}
|
|
|
|
let result = Command::new("sudo")
|
|
.args([
|
|
"--preserve-env",
|
|
current_exe().unwrap().to_str().unwrap(),
|
|
"--nocapture",
|
|
"--ignored",
|
|
"--exact",
|
|
name,
|
|
])
|
|
.status()
|
|
.unwrap();
|
|
|
|
if !result.success() {
|
|
panic!("Test {name} forked with root by the trace_marker suite failed.");
|
|
}
|
|
return false;
|
|
}
|
|
true
|
|
}
|
|
|
|
fn main() {
|
|
let args = libtest_mimic::Arguments {
|
|
// Force single-threaded execution to make sure there is no race condition between
|
|
// data written to the trace_marker file. In case the tracefs environment is being
|
|
// used by other processes on the system, these tests might fail.
|
|
test_threads: Some(1),
|
|
..libtest_mimic::Arguments::from_args()
|
|
};
|
|
|
|
let tests = vec![
|
|
libtest_mimic::Trial::test("trace_simple_print", move || {
|
|
if run_test_with_root("trace_simple_print") {
|
|
setup();
|
|
trace_simple_print();
|
|
cleanup();
|
|
}
|
|
Ok(())
|
|
}),
|
|
libtest_mimic::Trial::test("push_descriptors", move || {
|
|
if run_test_with_root("push_descriptors") {
|
|
setup();
|
|
push_descriptors();
|
|
cleanup();
|
|
}
|
|
Ok(())
|
|
}),
|
|
];
|
|
libtest_mimic::run(&args, tests).exit();
|
|
}
|