我有一个应用程序,该应用程序可以启动另一个进程,并使用log
板条箱将其StdOut / StdErr传输到日志文件。我的应用程序逐行传输输出(buf_read.read_line()
)。由于它可以是任意进程,因此我的应用程序假设其他进程可能是恶意的,并且可能试图在没有单个换行符的情况下打印到stdout / sterr大量数据,从而导致我的应用程序出现OOM。因此,我的应用程序限制了BufReader
使用BufReader.take()
一次可以读取的字节数。
忽略有关分块输入的所有详细信息,如何测试用正确的参数将记录器调用X次?假设我的应用程序读了一大行,并且将其分为3部分,例如下面的MCVE。
use std::thread::JoinHandle;
fn main() {
let handle = start_transfer_thread(&|x| {
println!("X={}", x);
}).join();
}
fn start_transfer_thread<F>(logger: &'static F) -> JoinHandle<()> where F: Send + Sync + Fn(&str) -> () {
std::thread::spawn(move || {
logger("1");
logger("2");
logger("3");
})
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_logged_in_order() {
let result = start_transfer_thread(&|x| {
match x {
"1" => (),
"2" => (),
"3" => (),
x => panic!("unexpected token: {}", x)
}
}).join();
assert!(result.is_ok());
}
}
答案 0 :(得分:1)
我可以通过用特征对象替换函数/闭包来做到这一点:
trait Logger: Send + Sync {
fn log(&mut self, log_name: &str, data: &str);
}
struct StandardLogger;
impl Logger for StandardLogger {
fn log(&mut self, log_name: &str, data: &str) {
log::logger().log(
&log::Record::builder()
.level(log::Level::Info)
.target(log_name)
.args(format_args!("{}", data))
.build(),
);
}
}
对于测试,我使用另一种实现方式:
struct DummyLogger {
tx: Mutex<Sender<String>>,
}
impl DummyLogger {
pub fn new() -> (DummyLogger, Receiver<String>) {
let (tx, rx) = std::sync::mpsc::channel();
let logger = DummyLogger { tx: Mutex::new(tx) };
(logger, rx)
}
}
impl Logger for DummyLogger {
fn log(&mut self, log_name: &str, data: &str) {
let tx = self.tx.lock().unwrap();
tx.send(data.to_owned());
}
}
这可以让我验证两次调用的次数是否正确,并带有正确的参数:
let actual: Vec<String> = rx.iter().collect();
assert_eq!(actual, vec!["1", "2", "3", "4"]);