diff options
Diffstat (limited to 'vendor/curl/tests/multi.rs')
-rw-r--r-- | vendor/curl/tests/multi.rs | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/vendor/curl/tests/multi.rs b/vendor/curl/tests/multi.rs new file mode 100644 index 0000000..7fbfd24 --- /dev/null +++ b/vendor/curl/tests/multi.rs @@ -0,0 +1,299 @@ +#![cfg(unix)] + +use std::collections::HashMap; +use std::io::{Cursor, Read}; +use std::time::Duration; + +use curl::easy::{Easy, List}; +use curl::multi::Multi; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + } + }; +} + +use crate::server::Server; +mod server; + +#[test] +fn smoke() { + let m = Multi::new(); + let mut e = Easy::new(); + + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + t!(e.url(&s.url("/"))); + let _e = t!(m.add(e)); + while t!(m.perform()) > 0 { + t!(m.wait(&mut [], Duration::from_secs(1))); + } +} + +#[test] +fn smoke2() { + let m = Multi::new(); + + let s1 = Server::new(); + s1.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s1.send("HTTP/1.1 200 OK\r\n\r\n"); + + let s2 = Server::new(); + s2.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s2.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut e1 = Easy::new(); + t!(e1.url(&s1.url("/"))); + let _e1 = t!(m.add(e1)); + let mut e2 = Easy::new(); + t!(e2.url(&s2.url("/"))); + let _e2 = t!(m.add(e2)); + + while t!(m.perform()) > 0 { + t!(m.wait(&mut [], Duration::from_secs(1))); + } + + let mut done = 0; + m.messages(|msg| { + msg.result().unwrap().unwrap(); + done += 1; + }); + assert_eq!(done, 2); +} + +#[test] +// test disabled due to flakyness +#[cfg(any())] +fn upload_lots() { + use curl::multi::{Events, Socket, SocketEvents}; + + #[derive(Debug)] + enum Message { + Timeout(Option<Duration>), + Wait(Socket, SocketEvents, usize), + } + + let mut m = Multi::new(); + let poll = t!(mio::Poll::new()); + let (tx, rx) = mio_extras::channel::channel(); + let tx2 = tx.clone(); + t!(m.socket_function(move |socket, events, token| { + t!(tx2.send(Message::Wait(socket, events, token))); + })); + t!(m.timer_function(move |dur| { + t!(tx.send(Message::Timeout(dur))); + true + })); + + let s = Server::new(); + s.receive(&format!( + "\ + PUT / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 131072\r\n\ + \r\n\ + {}\n", + vec!["a"; 128 * 1024 - 1].join("") + )); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut data = vec![b'a'; 128 * 1024 - 1]; + data.push(b'\n'); + let mut data = Cursor::new(data); + let mut list = List::new(); + t!(list.append("Expect:")); + let mut h = Easy::new(); + t!(h.url(&s.url("/"))); + t!(h.put(true)); + t!(h.read_function(move |buf| Ok(data.read(buf).unwrap()))); + t!(h.in_filesize(128 * 1024)); + t!(h.upload(true)); + t!(h.http_headers(list)); + + t!(poll.register(&rx, mio::Token(0), mio::Ready::all(), mio::PollOpt::level())); + + let e = t!(m.add(h)); + + assert!(t!(m.perform()) > 0); + let mut next_token = 1; + let mut token_map = HashMap::new(); + let mut cur_timeout = None; + let mut events = mio::Events::with_capacity(128); + let mut running = true; + + while running { + let n = t!(poll.poll(&mut events, cur_timeout)); + + if n == 0 && t!(m.timeout()) == 0 { + running = false; + } + + for event in events.iter() { + while event.token() == mio::Token(0) { + match rx.try_recv() { + Ok(Message::Timeout(dur)) => cur_timeout = dur, + Ok(Message::Wait(socket, events, token)) => { + let evented = mio::unix::EventedFd(&socket); + if events.remove() { + token_map.remove(&token).unwrap(); + } else { + let mut e = mio::Ready::empty(); + if events.input() { + e |= mio::Ready::readable(); + } + if events.output() { + e |= mio::Ready::writable(); + } + if token == 0 { + let token = next_token; + next_token += 1; + t!(m.assign(socket, token)); + token_map.insert(token, socket); + t!(poll.register( + &evented, + mio::Token(token), + e, + mio::PollOpt::level() + )); + } else { + t!(poll.reregister( + &evented, + mio::Token(token), + e, + mio::PollOpt::level() + )); + } + } + } + Err(_) => break, + } + } + + if event.token() == mio::Token(0) { + continue; + } + + let token = event.token(); + let socket = token_map[&token.into()]; + let mut e = Events::new(); + if event.readiness().is_readable() { + e.input(true); + } + if event.readiness().is_writable() { + e.output(true); + } + if mio::unix::UnixReady::from(event.readiness()).is_error() { + e.error(true); + } + let remaining = t!(m.action(socket, &e)); + if remaining == 0 { + running = false; + } + } + } + + let mut done = 0; + m.messages(|m| { + m.result().unwrap().unwrap(); + done += 1; + }); + assert_eq!(done, 1); + + let mut e = t!(m.remove(e)); + assert_eq!(t!(e.response_code()), 200); +} + +// Tests passing raw file descriptors to Multi::wait. The test is limited to Linux only as the +// semantics of the underlying poll(2) system call used by curl apparently differ on other +// platforms, making the test fail. +#[cfg(target_os = "linux")] +#[test] +fn waitfds() { + use curl::multi::WaitFd; + use std::fs::File; + use std::os::unix::io::AsRawFd; + + let filenames = ["/dev/null", "/dev/zero", "/dev/urandom"]; + let files: Vec<File> = filenames + .iter() + .map(|filename| File::open(filename).unwrap()) + .collect(); + let mut waitfds: Vec<WaitFd> = files + .iter() + .map(|f| { + let mut waitfd = WaitFd::new(); + waitfd.set_fd(f.as_raw_fd()); + waitfd.poll_on_read(true); + waitfd + }) + .collect(); + + let m = Multi::new(); + let events = t!(m.wait(&mut waitfds, Duration::from_secs(1))); + assert_eq!(events, 3); + for waitfd in waitfds { + assert!(waitfd.received_read()); + } +} + +// Tests passing raw file descriptors to Multi::wait. The test is limited to Linux only as the +// semantics of the underlying poll(2) system call used by curl apparently differ on other +// platforms, making the test fail. +#[cfg(feature = "poll_7_68_0")] +#[cfg(target_os = "linux")] +#[test] +fn pollfds() { + use curl::multi::WaitFd; + use std::fs::File; + use std::os::unix::io::AsRawFd; + + let filenames = ["/dev/null", "/dev/zero", "/dev/urandom"]; + let files: Vec<File> = filenames + .iter() + .map(|filename| File::open(filename).unwrap()) + .collect(); + let mut waitfds: Vec<WaitFd> = files + .iter() + .map(|f| { + let mut waitfd = WaitFd::new(); + waitfd.set_fd(f.as_raw_fd()); + waitfd.poll_on_read(true); + waitfd + }) + .collect(); + + let m = Multi::new(); + let events = t!(m.poll(&mut waitfds, Duration::from_secs(1))); + assert_eq!(events, 3); + for waitfd in waitfds { + assert!(waitfd.received_read()); + } +} |