Skip to content

Commit 4a2f3be

Browse files
committed
Add integration test for wrapping slog -> log
TODO: Add log -> slog test
1 parent 07aa6dc commit 4a2f3be

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ log = { version = "0.4.11", features = ["std"] }
4242
[dev-dependencies]
4343
slog-term = "2"
4444
slog-async = "2"
45+
# Used for tests
46+
fragile = "2"
47+

tests/log2slog.rs.disabled

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::sync::atomic::{AtomicBool, Ordering};
2+
use std::fmt;
3+
use std::collections::HashMap;
4+
5+
struct ExpectedValue {
6+
value: String,
7+
seen: AtomicBool,
8+
}
9+
struct SlogExpectSerialize {
10+
expected: HashMap<slog::Key, ExpectedValue>,
11+
}
12+
impl slog::Serializer for SlogExpectSerialize {
13+
fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
14+
if let Some(expected_value) = self.expected.get(&key) {
15+
let was_seen = expected_value.seen.compare_exchange(
16+
false, true,
17+
Ordering::SeqCst, Ordering::SeqCst
18+
).unwrap_or_else(std::convert::identity);
19+
assert!(!was_seen, "Already saw {key:?}");
20+
assert_eq!(expected_value.value, fmt::format(*val));
21+
Ok(())
22+
} else {
23+
panic!("Got unexpected key {key:?} = {val}");
24+
}
25+
}
26+
}
27+
impl SlogExpectSerialize {
28+
fn check_finished(&self) {
29+
for (key, value) in self.expected {
30+
if !value.seen.load(Ordering::SeqCst) {
31+
panic!("Did not see value for key = {key:?}")
32+
}
33+
}
34+
}
35+
}
36+
impl fmt::Debug for SlogExpectSerialize {
37+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38+
f.debug_map().entries(self.expected.iter().map(|(ref key, ref value)| {
39+
let key: &str = key.as_ref();
40+
(key, &*value.value)
41+
})).finish()
42+
}
43+
}
44+
45+
struct SlogAssertExpected {
46+
_fo: std::convert::Infallible,
47+
}
48+
impl slog::Drain for SlogAssertExpected {
49+
type Ok = ();
50+
type Err = slog::Error;
51+
fn log(&self, record: &slog::Record<'_>, values: &slog::OwnedKVList) -> Result<(), slog::Error> {
52+
todo!()
53+
}
54+
}
55+
impl SlogAssertExpected {
56+
fn assert_finished(&self) {
57+
todo!()
58+
}
59+
}
60+
61+
compile_error!("Not Yet Implemented");

tests/slog2log.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::sync::Mutex;
2+
use std::sync::atomic::{AtomicUsize, Ordering};
3+
4+
use slog::Drain;
5+
use log::RecordBuilder;
6+
use fragile::Fragile;
7+
8+
struct StdLogAssertExpected<'a> {
9+
expected: Mutex<Vec<Fragile<log::Record<'a>>>>,
10+
current_index: AtomicUsize,
11+
}
12+
impl log::Log for StdLogAssertExpected<'_> {
13+
fn enabled(&self, _: &log::Metadata) -> bool {
14+
true
15+
}
16+
fn log(&self, actual: &log::Record<'_>) {
17+
let expected = {
18+
let expected = self.expected.lock().unwrap();
19+
// NOTE: I think load fence is implied by the lock
20+
let old_index = self.current_index.load(Ordering::Relaxed);
21+
match expected.get(old_index) {
22+
Some(e) => {
23+
assert_eq!(
24+
old_index,
25+
// Do we need a store fence, or is that implied as well?
26+
self.current_index.fetch_add(1, Ordering::Acquire)
27+
);
28+
e.get().clone()
29+
},
30+
None => panic!("Expected no more log records. but got {:?}", actual)
31+
}
32+
};
33+
assert_eq!(expected.metadata(), actual.metadata());
34+
assert_eq!(expected.args().to_string(), actual.args().to_string());
35+
assert_eq!(expected.level(), actual.level());
36+
assert_eq!(expected.target(), actual.target());
37+
assert_eq!(expected.module_path(), actual.module_path());
38+
assert_eq!(expected.file(), actual.file());
39+
// NOTE: Intentionally ignored `line`
40+
if cfg!(feature = "kv_unstable") {
41+
todo!("Structure not currently used. See PR #26");
42+
}
43+
}
44+
fn flush(&self) {}
45+
}
46+
impl StdLogAssertExpected<'_> {
47+
fn assert_finished(&self) {
48+
let expected = self.expected.lock().unwrap();
49+
// load fence implied (I think)
50+
let remaining = expected.len() - self.current_index.load(Ordering::Relaxed);
51+
assert!(
52+
remaining == 0,
53+
"Expected {remaining} more values (first={first:?}) {maybeLast}",
54+
first = expected.first().unwrap(),
55+
maybeLast = if remaining >= 2 {
56+
format!("(last={:?})", expected.last().unwrap())
57+
} else {
58+
String::new()
59+
}
60+
);
61+
}
62+
}
63+
64+
macro_rules! record {
65+
($level:ident, $fmt:expr) => {
66+
RecordBuilder::new()
67+
.args(format_args!($fmt))
68+
.level(log::Level::$level)
69+
.file(Some(file!()))
70+
.module_path(Some(module_path!()))
71+
.target(module_path!())
72+
.build()
73+
}
74+
}
75+
76+
#[test]
77+
fn test_slog2log() {
78+
let expected = vec![
79+
record!(Info, "Hello World!"),
80+
record!(Debug, "Hello World, I am 100 years old")
81+
].into_iter().map(Fragile::new).collect::<Vec<Fragile<log::Record>>>();
82+
let std_logger = Box::leak(Box::new(StdLogAssertExpected {
83+
expected: Mutex::new(expected),
84+
current_index: 0.into(),
85+
}));
86+
log::set_logger(std_logger).unwrap();
87+
let sl = slog::Logger::root(slog_stdlog::StdLog.fuse(), slog::o!());
88+
slog::info!(sl, "Hello {}", "World!");
89+
slog::debug!(sl, "Hello {}, I am {} years old", "World", 100);
90+
std_logger.assert_finished();
91+
}

0 commit comments

Comments
 (0)