commands: add unit tests for piping logic
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I21f6f6f1402d870fce7cdca27c3a2e706a6a6964
This commit is contained in:
parent
5fe3bc61c6
commit
49a0becfdf
1 changed files with 136 additions and 0 deletions
|
|
@ -37,6 +37,7 @@ impl LogInterceptor for StdIoInterceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum PipeEvent {
|
enum PipeEvent {
|
||||||
Stdout(Vec<u8>),
|
Stdout(Vec<u8>),
|
||||||
Stderr(Vec<u8>),
|
Stderr(Vec<u8>),
|
||||||
|
|
@ -330,3 +331,138 @@ pub fn handle_nix_command(
|
||||||
intercept_env,
|
intercept_env,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io::{Cursor, Error};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_pipe_stdout() {
|
||||||
|
let data = b"hello world";
|
||||||
|
let cursor = Cursor::new(data);
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
read_pipe(cursor, tx_clone, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(tx);
|
||||||
|
|
||||||
|
let events: Vec<PipeEvent> = rx.iter().take(10).collect();
|
||||||
|
assert!(!events.is_empty());
|
||||||
|
|
||||||
|
let stdout_events: Vec<_> = events
|
||||||
|
.iter()
|
||||||
|
.filter(|e| matches!(e, PipeEvent::Stdout(_)))
|
||||||
|
.collect();
|
||||||
|
assert!(!stdout_events.is_empty());
|
||||||
|
|
||||||
|
let combined: Vec<u8> = events
|
||||||
|
.iter()
|
||||||
|
.filter_map(|e| {
|
||||||
|
match e {
|
||||||
|
PipeEvent::Stdout(b) => Some(b.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
assert_eq!(combined, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_pipe_stderr() {
|
||||||
|
let data = b"error output";
|
||||||
|
let cursor = Cursor::new(data);
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
read_pipe(cursor, tx_clone, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(tx);
|
||||||
|
|
||||||
|
let events: Vec<PipeEvent> = rx.iter().take(10).collect();
|
||||||
|
|
||||||
|
let stderr_events: Vec<_> = events
|
||||||
|
.iter()
|
||||||
|
.filter(|e| matches!(e, PipeEvent::Stderr(_)))
|
||||||
|
.collect();
|
||||||
|
assert!(!stderr_events.is_empty());
|
||||||
|
|
||||||
|
let combined: Vec<u8> = events
|
||||||
|
.iter()
|
||||||
|
.filter_map(|e| {
|
||||||
|
match e {
|
||||||
|
PipeEvent::Stderr(b) => Some(b.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
assert_eq!(combined, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_pipe_empty() {
|
||||||
|
let cursor = Cursor::new(b"");
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
read_pipe(cursor, tx_clone, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(tx);
|
||||||
|
|
||||||
|
let events: Vec<PipeEvent> = rx.iter().take(10).collect();
|
||||||
|
assert!(events.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_pipe_error() {
|
||||||
|
struct ErrorReader;
|
||||||
|
impl Read for ErrorReader {
|
||||||
|
fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
Err(std::io::Error::other("test error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let reader = ErrorReader;
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
read_pipe(reader, tx_clone, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(tx);
|
||||||
|
|
||||||
|
let events: Vec<PipeEvent> = rx.iter().take(10).collect();
|
||||||
|
|
||||||
|
let error_events: Vec<_> = events
|
||||||
|
.iter()
|
||||||
|
.filter(|e| matches!(e, PipeEvent::Error(_)))
|
||||||
|
.collect();
|
||||||
|
assert!(!error_events.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pipe_event_debug() {
|
||||||
|
let stdout_event = PipeEvent::Stdout(b"test".to_vec());
|
||||||
|
let stderr_event = PipeEvent::Stderr(b"error".to_vec());
|
||||||
|
let error_event = PipeEvent::Error(Error::other("test"));
|
||||||
|
|
||||||
|
let debug_stdout = format!("{:?}", stdout_event);
|
||||||
|
let debug_stderr = format!("{:?}", stderr_event);
|
||||||
|
let debug_error = format!("{:?}", error_event);
|
||||||
|
|
||||||
|
assert!(debug_stdout.contains("Stdout"));
|
||||||
|
assert!(debug_stderr.contains("Stderr"));
|
||||||
|
assert!(debug_error.contains("Error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue