diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/mio/test/test_subprocess_pipe.rs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/mio/test/test_subprocess_pipe.rs')
-rw-r--r-- | third_party/rust/mio/test/test_subprocess_pipe.rs | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/third_party/rust/mio/test/test_subprocess_pipe.rs b/third_party/rust/mio/test/test_subprocess_pipe.rs new file mode 100644 index 0000000000..2bcf132486 --- /dev/null +++ b/third_party/rust/mio/test/test_subprocess_pipe.rs @@ -0,0 +1,249 @@ +use {TryRead, TryWrite}; +use std::mem; +use mio::*; +use std::io; +use mio::deprecated::{EventLoop, Handler}; +use mio::deprecated::unix::{PipeReader, PipeWriter}; +use std::process::{Command, Stdio, Child}; + + +struct SubprocessClient { + stdin: Option<PipeWriter>, + stdout: Option<PipeReader>, + stderr: Option<PipeReader>, + stdin_token : Token, + stdout_token : Token, + stderr_token : Token, + output : Vec<u8>, + output_stderr : Vec<u8>, + input : Vec<u8>, + input_offset : usize, + buf : [u8; 65536], +} + + +// Sends a message and expects to receive the same exact message, one at a time +impl SubprocessClient { + fn new(stdin: Option<PipeWriter>, stdout : Option<PipeReader>, stderr : Option<PipeReader>, data : &[u8]) -> SubprocessClient { + SubprocessClient { + stdin: stdin, + stdout: stdout, + stderr: stderr, + stdin_token : Token(0), + stdout_token : Token(1), + stderr_token : Token(2), + output : Vec::<u8>::new(), + output_stderr : Vec::<u8>::new(), + buf : [0; 65536], + input : data.to_vec(), + input_offset : 0, + } + } + + fn readable(&mut self, event_loop: &mut EventLoop<SubprocessClient>) -> io::Result<()> { + let mut eof = false; + match self.stdout { + None => unreachable!(), + Some (ref mut stdout) => match stdout.try_read(&mut self.buf[..]) { + Ok(None) => { + } + Ok(Some(r)) => { + if r == 0 { + eof = true; + } else { + self.output.extend(&self.buf[0..r]); + } + } + Err(e) => { + return Err(e); + } + } + }; + if eof { + drop(self.stdout.take()); + match self.stderr { + None => event_loop.shutdown(), + Some(_) => {}, + } + } + return Ok(()); + } + + fn readable_stderr(&mut self, event_loop: &mut EventLoop<SubprocessClient>) -> io::Result<()> { + let mut eof = false; + match self.stderr { + None => unreachable!(), + Some(ref mut stderr) => match stderr.try_read(&mut self.buf[..]) { + Ok(None) => { + } + Ok(Some(r)) => { + if r == 0 { + eof = true; + } else { + self.output_stderr.extend(&self.buf[0..r]); + } + } + Err(e) => { + return Err(e); + } + } + }; + if eof { + drop(self.stderr.take()); + match self.stdout { + None => event_loop.shutdown(), + Some(_) => {}, + } + } + return Ok(()); + } + + fn writable(&mut self, event_loop: &mut EventLoop<SubprocessClient>) -> io::Result<()> { + let mut ok = true; + match self.stdin { + None => unreachable!(), + Some(ref mut stdin) => match stdin.try_write(&(&self.input)[self.input_offset..]) { + Ok(None) => { + }, + Ok(Some(r)) => { + if r == 0 { + ok = false; + } else { + self.input_offset += r; + } + }, + Err(_) => { + ok = false; + }, + } + } + if self.input_offset == self.input.len() || !ok { + drop(self.stdin.take()); + match self.stderr { + None => match self.stdout { + None => event_loop.shutdown(), + Some(_) => {}, + }, + Some(_) => {}, + } + } + return Ok(()); + } + +} + +impl Handler for SubprocessClient { + type Timeout = usize; + type Message = (); + + fn ready(&mut self, event_loop: &mut EventLoop<SubprocessClient>, token: Token, + _: Ready) { + if token == self.stderr_token { + let _x = self.readable_stderr(event_loop); + } else { + let _x = self.readable(event_loop); + } + if token == self.stdin_token { + let _y = self.writable(event_loop); + } + } +} + + + + +const TEST_DATA : [u8; 1024 * 4096] = [42; 1024 * 4096]; +pub fn subprocess_communicate(mut process : Child, input : &[u8]) -> (Vec<u8>, Vec<u8>) { + let mut event_loop = EventLoop::<SubprocessClient>::new().unwrap(); + let stdin : Option<PipeWriter>; + let stdin_exists : bool; + match process.stdin { + None => stdin_exists = false, + Some(_) => stdin_exists = true, + } + if stdin_exists { + match PipeWriter::from_stdin(process.stdin.take().unwrap()) { + Err(e) => panic!(e), + Ok(pipe) => stdin = Some(pipe), + } + } else { + stdin = None; + } + let stdout_exists : bool; + let stdout : Option<PipeReader>; + match process.stdout { + None => stdout_exists = false, + Some(_) => stdout_exists = true, + } + if stdout_exists { + match PipeReader::from_stdout(process.stdout.take().unwrap()) { + Err(e) => panic!(e), + Ok(pipe) => stdout = Some(pipe), + } + } else { + stdout = None; + } + let stderr_exists : bool; + let stderr : Option<PipeReader>; + match process.stderr { + None => stderr_exists = false, + Some(_) => stderr_exists = true, + } + if stderr_exists { + match PipeReader::from_stderr(process.stderr.take().unwrap()) { + Err(e) => panic!(e), + Ok(pipe) => stderr = Some(pipe), + } + } else { + stderr = None + } + + let mut subprocess = SubprocessClient::new(stdin, + stdout, + stderr, + input); + match subprocess.stdout { + Some(ref sub_stdout) => event_loop.register(sub_stdout, subprocess.stdout_token, Ready::readable(), + PollOpt::level()).unwrap(), + None => {}, + } + + match subprocess.stderr { + Some(ref sub_stderr) => event_loop.register(sub_stderr, subprocess.stderr_token, Ready::readable(), + PollOpt::level()).unwrap(), + None => {}, + } + + // Connect to the server + match subprocess.stdin { + Some (ref sub_stdin) => event_loop.register(sub_stdin, subprocess.stdin_token, Ready::writable(), + PollOpt::level()).unwrap(), + None => {}, + } + + // Start the event loop + event_loop.run(&mut subprocess).unwrap(); + let _ = process.wait(); + + let ret_stdout = mem::replace(&mut subprocess.output, Vec::<u8>::new()); + let ret_stderr = mem::replace(&mut subprocess.output_stderr, Vec::<u8>::new()); + return (ret_stdout, ret_stderr); +} + +#[test] +fn test_subprocess_pipe() { + let process = + Command::new("/bin/cat") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn().unwrap(); + let (ret_stdout, ret_stderr) = subprocess_communicate(process, &TEST_DATA[..]); + assert_eq!(TEST_DATA.len(), ret_stdout.len()); + assert_eq!(0usize, ret_stderr.len()); + let mut i : usize = 0; + for item in TEST_DATA.iter() { + assert_eq!(*item, ret_stdout[i]); + i += 1; + } +} |