Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/cros_tracing/tests/trace_marker.rs
5392 views
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;
6
use std::env::current_exe;
7
use std::fs::File;
8
use std::io::BufRead;
9
use std::io::BufReader;
10
use std::process::Command;
11
12
use cros_tracing::*;
13
14
const TRACE_FILE: &str = "/sys/kernel/tracing/trace";
15
const TRACE_CONTEXT_INFO: &str = "/sys/kernel/tracing/options/context-info";
16
const TRACING_ON: &str = "/sys/kernel/tracing/tracing_on";
17
18
fn setup() {
19
// Make sure tracing is enabled.
20
std::fs::write(TRACING_ON, b"1").unwrap();
21
// Remove extra noise from trace file for easier parsing
22
std::fs::write(TRACE_CONTEXT_INFO, b"0").unwrap();
23
// Clear the trace backlog by writing an empty string, in case we have extra
24
// rogue messages in the trace buffer
25
std::fs::write(TRACE_FILE, b"").unwrap();
26
27
init();
28
}
29
30
fn cleanup() {
31
// Stop tracing.
32
std::fs::write(TRACING_ON, b"0").unwrap();
33
// Reset trace file format back to how it was.
34
std::fs::write(TRACE_CONTEXT_INFO, b"1").unwrap();
35
}
36
37
fn trace_simple_print() {
38
let reader = BufReader::new(File::open(TRACE_FILE).ok().unwrap());
39
40
let message1 = "Simple print test one";
41
let message2 = "Simple print test two";
42
43
trace_simple_print!("{message1}");
44
trace_simple_print!("{message2}");
45
46
// Read contents of the file, skip the first two lines which are just a preamble.
47
let mut lines = reader.lines().map(|l| l.unwrap()).skip(2);
48
49
// Check the printed lines are in order.
50
// We need to use contains instead of matching the full string because each time we
51
// print to trace_marker we will get unique data like PID and timestamps that we cannot
52
// rely on, but the contents of the message itself should always contain our string.
53
assert!(lines.next().unwrap().contains(message1));
54
assert!(lines.next().unwrap().contains(message2));
55
}
56
57
fn push_descriptors() {
58
let mut keep_rds = Vec::new();
59
60
push_descriptors!(&mut keep_rds);
61
62
// We cannot know the fd of the trace marker file beforehand but we can check if there
63
// is only one fd in the vector it means we can assume it's the trace_marker one.
64
assert_eq!(keep_rds.len(), 1);
65
}
66
67
/// Executes the individual test `name` with root, in the same environment as the test suite,
68
/// if it does not already have root privileges. Sudo needs to be set up to run passwordless
69
/// or have cached credentials. The parent process spawns a child that runs with higher privileges
70
/// for that individual `name` test, and then waits for its completion.
71
///
72
/// Returns `true` if the test suite already has root privilege, in which case it
73
/// proceeds to run the test without forking, otherwise it returns `false` to let the
74
/// test suite know that the test was run by the child process instead.
75
///
76
/// # Arguments
77
///
78
/// * `name` - Name of the individual test to execute as root
79
///
80
/// # Examples
81
///
82
/// ```
83
/// libtest_mimic::Trial::test("test_with_root", move || {
84
/// if run_test_with_root("test_with_root") {
85
/// // This part only executes with root
86
/// function_to_test();
87
/// }
88
/// Ok(())
89
/// });
90
/// ```
91
fn run_test_with_root(name: &str) -> bool {
92
// This test needs to run as root, so if we aren't root we need to re-execute ourselves
93
// with sudo.
94
let is_root = match env::var("USER") {
95
Ok(val) => val == "root",
96
Err(_) => false,
97
};
98
99
if !is_root {
100
let can_sudo = Command::new("sudo")
101
.args(["--askpass", "true"])
102
.env("SUDO_ASKPASS", "false")
103
.output()
104
.unwrap();
105
if !can_sudo.status.success() {
106
panic!("This test needs to be run as root or with passwordless sudo.");
107
}
108
109
let result = Command::new("sudo")
110
.args([
111
"--preserve-env",
112
current_exe().unwrap().to_str().unwrap(),
113
"--nocapture",
114
"--ignored",
115
"--exact",
116
name,
117
])
118
.status()
119
.unwrap();
120
121
if !result.success() {
122
panic!("Test {name} forked with root by the trace_marker suite failed.");
123
}
124
return false;
125
}
126
true
127
}
128
129
fn main() {
130
let args = libtest_mimic::Arguments {
131
// Force single-threaded execution to make sure there is no race condition between
132
// data written to the trace_marker file. In case the tracefs environment is being
133
// used by other processes on the system, these tests might fail.
134
test_threads: Some(1),
135
..libtest_mimic::Arguments::from_args()
136
};
137
138
let tests = vec![
139
libtest_mimic::Trial::test("trace_simple_print", move || {
140
if run_test_with_root("trace_simple_print") {
141
setup();
142
trace_simple_print();
143
cleanup();
144
}
145
Ok(())
146
}),
147
libtest_mimic::Trial::test("push_descriptors", move || {
148
if run_test_with_root("push_descriptors") {
149
setup();
150
push_descriptors();
151
cleanup();
152
}
153
Ok(())
154
}),
155
];
156
libtest_mimic::run(&args, tests).exit();
157
}
158
159