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_tcp_shutdown.rs | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.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_tcp_shutdown.rs')
-rw-r--r-- | third_party/rust/mio/test/test_tcp_shutdown.rs | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/third_party/rust/mio/test/test_tcp_shutdown.rs b/third_party/rust/mio/test/test_tcp_shutdown.rs new file mode 100644 index 0000000000..9363f83401 --- /dev/null +++ b/third_party/rust/mio/test/test_tcp_shutdown.rs @@ -0,0 +1,248 @@ +use std::collections::HashMap; +use std::net::{self, Shutdown}; +use std::time::{Duration, Instant}; + +use mio::{Token, Ready, PollOpt, Poll, Events}; +use mio::event::{Evented, Event}; +use mio::net::TcpStream; + +struct TestPoll { + poll: Poll, + events: Events, + buf: HashMap<Token, Ready>, +} + +impl TestPoll { + fn new() -> TestPoll { + TestPoll { + poll: Poll::new().unwrap(), + events: Events::with_capacity(1024), + buf: HashMap::new(), + } + } + + fn register<E: ?Sized>(&self, handle: &E, token: Token, interest: Ready, opts: PollOpt) + where E: Evented + { + self.poll.register(handle, token, interest, opts).unwrap(); + } + + fn wait_for(&mut self, token: Token, ready: Ready) -> Result<(), &'static str> { + let now = Instant::now(); + + loop { + if now.elapsed() > Duration::from_secs(1) { + return Err("not ready"); + } + + if let Some(curr) = self.buf.get(&token) { + if curr.contains(ready) { + break; + } + } + + self.poll.poll(&mut self.events, Some(Duration::from_millis(250))).unwrap(); + + for event in &self.events { + let curr = self.buf.entry(event.token()) + .or_insert(Ready::empty()); + + *curr |= event.readiness(); + } + } + + *self.buf.get_mut(&token).unwrap() -= ready; + Ok(()) + } + + fn check_idle(&mut self) -> Result<(), Event> { + self.poll.poll(&mut self.events, Some(Duration::from_millis(100))).unwrap(); + + if let Some(e) = self.events.iter().next() { + Err(e) + } else { + Ok(()) + } + } +} + +macro_rules! assert_ready { + ($poll:expr, $token:expr, $ready:expr) => {{ + match $poll.wait_for($token, $ready) { + Ok(_) => {} + Err(_) => panic!("not ready; token = {:?}; interest = {:?}", $token, $ready), + } + }} +} + +macro_rules! assert_not_ready { + ($poll:expr, $token:expr, $ready:expr) => {{ + match $poll.wait_for($token, $ready) { + Ok(_) => panic!("is ready; token = {:?}; interest = {:?}", $token, $ready), + Err(_) => {} + } + }} +} + +macro_rules! assert_hup_ready { + ($poll:expr) => { + #[cfg(unix)] + { + use mio::unix::UnixReady; + assert_ready!($poll, Token(0), Ready::from(UnixReady::hup())) + } + } +} + +macro_rules! assert_not_hup_ready { + ($poll:expr) => { + #[cfg(unix)] + { + use mio::unix::UnixReady; + assert_not_ready!($poll, Token(0), Ready::from(UnixReady::hup())) + } + } +} + +macro_rules! assert_idle { + ($poll:expr) => { + match $poll.check_idle() { + Ok(()) => {} + Err(e) => panic!("not idle; event = {:?}", e), + } + } +} + +// TODO: replace w/ assertive +// https://github.com/carllerche/assertive +macro_rules! assert_ok { + ($e:expr) => { + assert_ok!($e,) + }; + ($e:expr,) => {{ + use std::result::Result::*; + match $e { + Ok(v) => v, + Err(e) => panic!("assertion failed: error = {:?}", e), + } + }}; + ($e:expr, $($arg:tt)+) => {{ + use std::result::Result::*; + match $e { + Ok(v) => v, + Err(e) => panic!("assertion failed: error = {:?}: {}", e, format_args!($($arg)+)), + } + }}; +} + +#[test] +fn test_write_shutdown() { + use std::io::prelude::*; + + let mut poll = TestPoll::new(); + let mut buf = [0; 1024]; + + let listener = assert_ok!(net::TcpListener::bind("127.0.0.1:0")); + let addr = assert_ok!(listener.local_addr()); + + let mut client = assert_ok!(TcpStream::connect(&addr)); + poll.register(&client, + Token(0), + Ready::readable() | Ready::writable(), + PollOpt::edge()); + + let (socket, _) = assert_ok!(listener.accept()); + + assert_ready!(poll, Token(0), Ready::writable()); + + // Polling should not have any events + assert_idle!(poll); + + // Now, shutdown the write half of the socket. + assert_ok!(socket.shutdown(Shutdown::Write)); + + assert_ready!(poll, Token(0), Ready::readable()); + + assert_not_hup_ready!(poll); + + let n = assert_ok!(client.read(&mut buf)); + assert_eq!(n, 0); +} + +#[test] +fn test_graceful_shutdown() { + use std::io::prelude::*; + + let mut poll = TestPoll::new(); + let mut buf = [0; 1024]; + + let listener = assert_ok!(net::TcpListener::bind("127.0.0.1:0")); + let addr = assert_ok!(listener.local_addr()); + + let mut client = assert_ok!(TcpStream::connect(&addr)); + poll.register(&client, + Token(0), + Ready::readable() | Ready::writable(), + PollOpt::edge()); + + let (mut socket, _) = assert_ok!(listener.accept()); + + assert_ready!(poll, Token(0), Ready::writable()); + + // Polling should not have any events + assert_idle!(poll); + + // Now, shutdown the write half of the socket. + assert_ok!(client.shutdown(Shutdown::Write)); + + let n = assert_ok!(socket.read(&mut buf)); + assert_eq!(0, n); + drop(socket); + + assert_ready!(poll, Token(0), Ready::readable()); + #[cfg(not(any(target_os = "bitrig", target_os = "dragonfly", + target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd")))] + assert_hup_ready!(poll); + + let mut buf = [0; 1024]; + let n = assert_ok!(client.read(&mut buf)); + assert_eq!(n, 0); +} + +#[test] +fn test_abrupt_shutdown() { + use net2::TcpStreamExt; + use std::io::Read; + + let mut poll = TestPoll::new(); + let mut buf = [0; 1024]; + + let listener = assert_ok!(net::TcpListener::bind("127.0.0.1:0")); + let addr = assert_ok!(listener.local_addr()); + + let mut client = assert_ok!(TcpStream::connect(&addr)); + poll.register(&client, + Token(0), + Ready::readable() | Ready::writable(), + PollOpt::edge()); + + let (socket, _) = assert_ok!(listener.accept()); + assert_ok!(socket.set_linger(Some(Duration::from_millis(0)))); + // assert_ok!(socket.set_linger(None)); + + // Wait to be connected + assert_ready!(poll, Token(0), Ready::writable()); + + drop(socket); + + #[cfg(not(any(target_os = "bitrig", target_os = "dragonfly", + target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd")))] + assert_hup_ready!(poll); + assert_ready!(poll, Token(0), Ready::writable()); + assert_ready!(poll, Token(0), Ready::readable()); + + let res = client.read(&mut buf); + assert!(res.is_err(), "not err = {:?}", res); +} |