From 1b3247b089061128f51da7d23598ba06777db35e Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 21 Mar 2024 16:42:38 +0800 Subject: [PATCH] [WIP] Add a test to reproduce error --- spdlog/Cargo.toml | 5 ++ spdlog/tests/global_async_pool_sink.rs | 106 +++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 spdlog/tests/global_async_pool_sink.rs diff --git a/spdlog/Cargo.toml b/spdlog/Cargo.toml index 58a2364b..79c01742 100644 --- a/spdlog/Cargo.toml +++ b/spdlog/Cargo.toml @@ -80,6 +80,11 @@ tracing-appender = "=0.2.2" [build-dependencies] rustc_version = "0.4.0" +[[test]] +name = "global_async_pool_sink" +harness = false +required-features = ["multi-thread"] + [[bench]] name = "compare_with_cpp_spdlog" harness = false diff --git a/spdlog/tests/global_async_pool_sink.rs b/spdlog/tests/global_async_pool_sink.rs new file mode 100644 index 00000000..b9773b7c --- /dev/null +++ b/spdlog/tests/global_async_pool_sink.rs @@ -0,0 +1,106 @@ +use std::{ + env, + os::raw::c_int, + process, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; + +use spdlog::{ + formatter::Formatter, + prelude::*, + sink::{AsyncPoolSink, Sink}, + ErrorHandler, +}; + +static IS_FLUSHED: AtomicBool = AtomicBool::new(false); + +struct SetFlagSink; + +impl Sink for SetFlagSink { + fn log(&self, _record: &spdlog::Record) -> error::Result<()> { + Ok(()) + } + + fn flush(&self) -> error::Result<()> { + IS_FLUSHED.store(true, Ordering::SeqCst); + Ok(()) + } + + fn level_filter(&self) -> LevelFilter { + LevelFilter::All + } + + fn set_level_filter(&self, _level_filter: LevelFilter) { + unimplemented!() + } + + fn set_formatter(&self, _formatter: Box) { + unimplemented!() + } + + fn set_error_handler(&self, _handler: Option) { + unimplemented!() + } +} + +fn run_test() { + { + extern "C" fn check() { + assert!(IS_FLUSHED.load(Ordering::SeqCst)); + } + // Setup `atexit`` to check the flag at the end of the program + extern "C" { + fn atexit(cb: extern "C" fn()) -> c_int; + } + assert_eq!(unsafe { atexit(check) }, 0); + + let async_pool_sink = Arc::new( + AsyncPoolSink::builder() + .sink(Arc::new(SetFlagSink)) + .build() + .unwrap(), + ); + + let logger = Arc::new(Logger::builder().sink(async_pool_sink).build().unwrap()); + logger.set_flush_level_filter(LevelFilter::All); + spdlog::set_default_logger(logger); + } + + info!("hello async_pool_sink"); + + // Workaround, adding these 2 lines at the end of `main` function + // + // std::thread::sleep(std::time::Duration::from_millis(100)); + // spdlog::default_logger().flush(); +} + +fn main() { + // https://github.com/SpriteOvO/spdlog-rs/issues/64 + + // This is a flaky test, it only has a certain probability of failing, so we run + // it multiple times to make sure it's really working properly. + { + let args = env::args().collect::>(); + // If this is the parent process (no additional arguments) + if args.len() == 1 { + for _ in 0..1000 { + let status = process::Command::new(&args[0]) + .arg("child") + .spawn() + .unwrap() + .wait() + .unwrap(); + assert!(status.success()); + } + return; + } + + // Run the test after leaving the scope, so the main function ends + // without dropping additional variables, thus exiting faster. This + // should increase the probability of reproducing the error. + } + run_test(); +}