Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/tests/syslog.rs
5394 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
#![allow(clippy::field_reassign_with_default)]
6
7
use std::io;
8
use std::io::Write;
9
use std::sync::Arc;
10
11
use base::syslog::test_only_ensure_inited;
12
use base::syslog::LogArgs;
13
use base::syslog::LogConfig;
14
use base::syslog::Priority;
15
use base::syslog::State;
16
use base::syslog::Syslogger;
17
use env_logger::fmt;
18
use log::Level;
19
use log::Log;
20
use log::Record;
21
use sync::Mutex;
22
23
#[derive(Clone)]
24
struct MockWrite {
25
buffer: Arc<Mutex<Vec<u8>>>,
26
}
27
28
impl MockWrite {
29
fn new() -> Self {
30
Self {
31
buffer: Arc::new(Mutex::new(vec![])),
32
}
33
}
34
35
fn into_inner(self) -> Vec<u8> {
36
Arc::try_unwrap(self.buffer).unwrap().into_inner()
37
}
38
}
39
40
impl Write for MockWrite {
41
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
42
self.buffer.lock().write(buf)
43
}
44
45
fn flush(&mut self) -> io::Result<()> {
46
Ok(())
47
}
48
}
49
50
#[test]
51
fn syslog_log() {
52
let state = State::default();
53
state.log(
54
&log::RecordBuilder::new()
55
.level(Level::Error)
56
.file(Some(file!()))
57
.line(Some(line!()))
58
.args(format_args!("hello syslog"))
59
.build(),
60
);
61
}
62
63
#[test]
64
fn proc_name() {
65
let state = State::new(LogConfig {
66
log_args: LogArgs {
67
proc_name: String::from("syslog-test"),
68
..Default::default()
69
},
70
..Default::default()
71
})
72
.unwrap();
73
state.log(
74
&log::RecordBuilder::new()
75
.level(Level::Error)
76
.file(Some(file!()))
77
.line(Some(line!()))
78
.args(format_args!("hello syslog"))
79
.build(),
80
);
81
}
82
83
#[test]
84
fn macros() {
85
test_only_ensure_inited().unwrap();
86
log::error!("this is an error {}", 3);
87
log::warn!("this is a warning {}", "uh oh");
88
log::info!("this is info {}", true);
89
log::debug!("this is debug info {:?}", Some("helpful stuff"));
90
}
91
92
fn pipe_formatter(buf: &mut fmt::Formatter, record: &Record<'_>) -> io::Result<()> {
93
writeln!(buf, "{}", record.args())
94
}
95
96
#[test]
97
fn syslogger_char() {
98
let output = MockWrite::new();
99
let mut cfg = LogConfig::default();
100
cfg.pipe_formatter = Some(Box::new(pipe_formatter));
101
cfg.pipe = Some(Box::new(output.clone()));
102
let state = Mutex::new(State::new(cfg).unwrap());
103
104
let mut syslogger = Syslogger::test_only_from_state(Level::Info, || state.lock());
105
106
let string = "chars";
107
for c in string.chars() {
108
syslogger.write_all(&[c as u8]).expect("error writing char");
109
}
110
111
syslogger
112
.write_all(b"\n")
113
.expect("error writing newline char");
114
115
std::mem::drop(syslogger);
116
std::mem::drop(state);
117
assert_eq!(
118
format!("{string}\n"),
119
String::from_utf8_lossy(&output.into_inner()[..])
120
);
121
}
122
123
#[test]
124
fn syslogger_line() {
125
let output = MockWrite::new();
126
let mut cfg = LogConfig::default();
127
cfg.pipe_formatter = Some(Box::new(pipe_formatter));
128
cfg.pipe = Some(Box::new(output.clone()));
129
let state = Mutex::new(State::new(cfg).unwrap());
130
131
let mut syslogger = Syslogger::test_only_from_state(Level::Info, || state.lock());
132
133
let s = "Writing string to syslog\n";
134
syslogger
135
.write_all(s.as_bytes())
136
.expect("error writing string");
137
138
std::mem::drop(syslogger);
139
std::mem::drop(state);
140
assert_eq!(s, String::from_utf8_lossy(&output.into_inner()[..]));
141
}
142
143
#[test]
144
fn syslogger_partial() {
145
let output = MockWrite::new();
146
let state = Mutex::new(
147
State::new(LogConfig {
148
pipe: Some(Box::new(output.clone())),
149
..Default::default()
150
})
151
.unwrap(),
152
);
153
154
let mut syslogger = Syslogger::test_only_from_state(Level::Info, || state.lock());
155
156
let s = "Writing partial string";
157
// Should not log because there is no newline character
158
syslogger
159
.write_all(s.as_bytes())
160
.expect("error writing string");
161
162
std::mem::drop(syslogger);
163
std::mem::drop(state);
164
assert_eq!(Vec::<u8>::new(), output.into_inner());
165
}
166
167
#[test]
168
fn log_priority_try_from_number() {
169
assert_eq!("0".try_into(), Ok(Priority::Emergency));
170
assert!(Priority::try_from("100").is_err());
171
}
172
173
#[test]
174
fn log_priority_try_from_words() {
175
assert_eq!("EMERGENCY".try_into(), Ok(Priority::Emergency));
176
assert!(Priority::try_from("_EMERGENCY").is_err());
177
}
178
179
#[test]
180
fn log_should_always_be_enabled_for_level_show_all() {
181
let state = State::new(LogConfig {
182
log_args: LogArgs {
183
filter: String::from("trace"),
184
..Default::default()
185
},
186
..Default::default()
187
})
188
.unwrap();
189
190
assert!(state.enabled(
191
log::RecordBuilder::new()
192
.level(Level::Debug)
193
.build()
194
.metadata(),
195
));
196
}
197
198
#[test]
199
fn log_should_always_be_disabled_for_level_silent() {
200
let state = State::new(LogConfig {
201
log_args: LogArgs {
202
filter: String::from("off"),
203
..Default::default()
204
},
205
..Default::default()
206
})
207
.unwrap();
208
209
assert!(!state.enabled(
210
log::RecordBuilder::new()
211
.level(Level::Debug)
212
.build()
213
.metadata(),
214
));
215
}
216
217
#[test]
218
fn log_should_be_enabled_if_filter_level_has_a_lower_or_equal_priority() {
219
let state = State::new(LogConfig {
220
log_args: LogArgs {
221
filter: String::from("info"),
222
..Default::default()
223
},
224
..Default::default()
225
})
226
.unwrap();
227
228
assert!(state.enabled(
229
log::RecordBuilder::new()
230
.level(Level::Info)
231
.build()
232
.metadata(),
233
));
234
assert!(state.enabled(
235
log::RecordBuilder::new()
236
.level(Level::Warn)
237
.build()
238
.metadata(),
239
));
240
}
241
242
#[test]
243
fn log_should_be_disabled_if_filter_level_has_a_higher_priority() {
244
let state = State::new(LogConfig {
245
log_args: LogArgs {
246
filter: String::from("info"),
247
..Default::default()
248
},
249
..Default::default()
250
})
251
.unwrap();
252
253
assert!(!state.enabled(
254
log::RecordBuilder::new()
255
.level(Level::Debug)
256
.build()
257
.metadata(),
258
));
259
}
260
261
#[test]
262
fn path_overides_should_apply_to_logs() {
263
let state = State::new(LogConfig {
264
log_args: LogArgs {
265
filter: String::from("info,test=debug"),
266
..Default::default()
267
},
268
..Default::default()
269
})
270
.unwrap();
271
272
assert!(!state.enabled(
273
log::RecordBuilder::new()
274
.level(Level::Debug)
275
.build()
276
.metadata(),
277
));
278
assert!(state.enabled(
279
log::RecordBuilder::new()
280
.level(Level::Debug)
281
.target("test")
282
.build()
283
.metadata(),
284
));
285
}
286
287
#[test]
288
fn longest_path_prefix_match_should_apply_if_multiple_filters_match() {
289
let state = State::new(LogConfig {
290
log_args: LogArgs {
291
filter: String::from("info,test=debug,test::silence=off"),
292
..Default::default()
293
},
294
..Default::default()
295
})
296
.unwrap();
297
298
assert!(!state.enabled(
299
log::RecordBuilder::new()
300
.level(Level::Debug)
301
.build()
302
.metadata(),
303
));
304
305
assert!(state.enabled(
306
log::RecordBuilder::new()
307
.level(Level::Debug)
308
.target("test")
309
.build()
310
.metadata(),
311
));
312
assert!(!state.enabled(
313
log::RecordBuilder::new()
314
.level(Level::Error)
315
.target("test::silence")
316
.build()
317
.metadata(),
318
));
319
}
320
321