From 9b1a45cc6a15f5d2be17531dffc2f50d2b019646 Mon Sep 17 00:00:00 2001 From: Liran Ringel <5730310+liranringel@users.noreply.github.com> Date: Tue, 20 Nov 2018 18:10:36 +0200 Subject: tests: handle errors properly in examples (#748) --- examples/chat-combinator.rs | 14 +++++++----- examples/chat.rs | 7 +++--- examples/connect.rs | 48 +++++++++++++++++++++++----------------- examples/echo-udp.rs | 9 ++++---- examples/echo.rs | 7 +++--- examples/hello_world.rs | 6 +++-- examples/manual-runtime.rs | 5 +++-- examples/print_each_packet.rs | 7 +++--- examples/proxy.rs | 9 ++++---- examples/tinydb.rs | 7 +++--- examples/tinyhttp.rs | 51 ++++++++++++++++++++++++------------------- examples/udp-client.rs | 27 ++++++++++------------- examples/udp-codec.rs | 11 +++++----- 13 files changed, 114 insertions(+), 94 deletions(-) (limited to 'examples') diff --git a/examples/chat-combinator.rs b/examples/chat-combinator.rs index 11754183..0572afbd 100644 --- a/examples/chat-combinator.rs +++ b/examples/chat-combinator.rs @@ -34,12 +34,12 @@ use std::env; use std::io::{BufReader}; use std::sync::{Arc, Mutex}; -fn main() { +fn main() -> Result<(), Box> { // Create the TCP listener we'll accept connections on. let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string()); - let addr = addr.parse().unwrap(); + let addr = addr.parse()?; - let socket = TcpListener::bind(&addr).unwrap(); + let socket = TcpListener::bind(&addr)?; println!("Listening on: {}", addr); // This is running on the Tokio runtime, so it will be multi-threaded. The @@ -49,10 +49,10 @@ fn main() { // The server task asynchronously iterates over and processes each incoming // connection. let srv = socket.incoming() - .map_err(|e| println!("failed to accept socket; error = {:?}", e)) + .map_err(|e| {println!("failed to accept socket; error = {:?}", e); e}) .for_each(move |stream| { // The client's socket address - let addr = stream.peer_addr().unwrap(); + let addr = stream.peer_addr()?; println!("New Connection: {}", addr); @@ -143,8 +143,10 @@ fn main() { })); Ok(()) - }); + }) + .map_err(|err| println!("error occurred: {:?}", err)); // execute server tokio::run(srv); + Ok(()) } diff --git a/examples/chat.rs b/examples/chat.rs index bdc742c9..182af7c8 100644 --- a/examples/chat.rs +++ b/examples/chat.rs @@ -426,7 +426,7 @@ fn process(socket: TcpStream, state: Arc>) { tokio::spawn(connection); } -pub fn main() { +pub fn main() -> Result<(), Box> { // Create the shared state. This is how all the peers communicate. // // The server task will hold a handle to this. For every new client, the @@ -434,12 +434,12 @@ pub fn main() { // client connection. let state = Arc::new(Mutex::new(Shared::new())); - let addr = "127.0.0.1:6142".parse().unwrap(); + let addr = "127.0.0.1:6142".parse()?; // Bind a TCP listener to the socket address. // // Note that this is the Tokio TcpListener, which is fully async. - let listener = TcpListener::bind(&addr).unwrap(); + let listener = TcpListener::bind(&addr)?; // The server task asynchronously iterates over and processes each // incoming connection. @@ -471,4 +471,5 @@ pub fn main() { // In our example, we have not defined a shutdown strategy, so this will // block until `ctrl-c` is pressed at the terminal. tokio::run(server); + Ok(()) } diff --git a/examples/connect.rs b/examples/connect.rs index fa3824c4..93f55533 100644 --- a/examples/connect.rs +++ b/examples/connect.rs @@ -29,7 +29,7 @@ use std::thread; use tokio::prelude::*; use futures::sync::mpsc; -fn main() { +fn main() -> Result<(), Box> { // Determine if we're going to run in TCP or UDP mode let mut args = env::args().skip(1).collect::>(); let tcp = match args.iter().position(|a| a == "--udp") { @@ -41,10 +41,11 @@ fn main() { }; // Parse what address we're going to connect to - let addr = args.first().unwrap_or_else(|| { - panic!("this program requires at least one argument") - }); - let addr = addr.parse::().unwrap(); + let addr = match args.first() { + Some(addr) => addr, + None => Err("this program requires at least one argument")?, + }; + let addr = addr.parse::()?; // Right now Tokio doesn't support a handle to stdin running on the event // loop, so we farm out that work to a separate thread. This thread will @@ -52,15 +53,15 @@ fn main() { // loop over a standard futures channel. let (stdin_tx, stdin_rx) = mpsc::channel(0); thread::spawn(|| read_stdin(stdin_tx)); - let stdin_rx = stdin_rx.map_err(|_| panic!()); // errors not possible on rx + let stdin_rx = stdin_rx.map_err(|_| panic!("errors not possible on rx")); // Now that we've got our stdin read we either set up our TCP connection or // our UDP connection to get a stream of bytes we're going to emit to // stdout. let stdout = if tcp { - tcp::connect(&addr, Box::new(stdin_rx)) + tcp::connect(&addr, Box::new(stdin_rx))? } else { - udp::connect(&addr, Box::new(stdin_rx)) + udp::connect(&addr, Box::new(stdin_rx))? }; // And now with our stream of bytes to write to stdout, we execute that in @@ -77,6 +78,7 @@ fn main() { }) .map_err(|e| println!("error reading stdout; error = {:?}", e)) }); + Ok(()) } mod codec { @@ -127,12 +129,13 @@ mod tcp { use bytes::BytesMut; use codec::Bytes; + use std::error::Error; use std::io; use std::net::SocketAddr; pub fn connect(addr: &SocketAddr, stdin: Box, Error = io::Error> + Send>) - -> Box + Send> + -> Result + Send>, Box> { let tcp = TcpStream::connect(addr); @@ -151,22 +154,24 @@ mod tcp { // You'll also note that we *spawn* the work to read stdin and write it // to the TCP stream. This is done to ensure that happens concurrently // with us reading data from the stream. - Box::new(tcp.map(move |stream| { + let stream = Box::new(tcp.map(move |stream| { let (sink, stream) = Bytes.framed(stream).split(); tokio::spawn(stdin.forward(sink).then(|result| { if let Err(e) = result { - panic!("failed to write to socket: {}", e) + println!("failed to write to socket: {}", e) } Ok(()) })); stream - }).flatten_stream()) + }).flatten_stream()); + Ok(stream) } } mod udp { + use std::error::Error; use std::io; use std::net::SocketAddr; @@ -179,17 +184,19 @@ mod udp { pub fn connect(&addr: &SocketAddr, stdin: Box, Error = io::Error> + Send>) - -> Box + Send> + -> Result + Send>, Box> { // We'll bind our UDP socket to a local IP/port, but for now we // basically let the OS pick both of those. let addr_to_bind = if addr.ip().is_ipv4() { - "0.0.0.0:0".parse().unwrap() + "0.0.0.0:0".parse()? } else { - "[::]:0".parse().unwrap() + "[::]:0".parse()? + }; + let udp = match UdpSocket::bind(&addr_to_bind) { + Ok(udp) => udp, + Err(_) => Err("failed to bind socket")?, }; - let udp = UdpSocket::bind(&addr_to_bind) - .expect("failed to bind socket"); // Like above with TCP we use an instance of `Bytes` codec to transform // this UDP socket into a framed sink/stream which operates over @@ -203,7 +210,7 @@ mod udp { (chunk, addr) }).forward(sink).then(|result| { if let Err(e) = result { - panic!("failed to write to socket: {}", e) + println!("failed to write to socket: {}", e) } Ok(()) }); @@ -218,10 +225,11 @@ mod udp { } }); - Box::new(future::lazy(|| { + let stream = Box::new(future::lazy(|| { tokio::spawn(forward_stdin); future::ok(receive) - }).flatten_stream()) + }).flatten_stream()); + Ok(stream) } } diff --git a/examples/echo-udp.rs b/examples/echo-udp.rs index 89cc3d16..08a14563 100644 --- a/examples/echo-udp.rs +++ b/examples/echo-udp.rs @@ -50,12 +50,12 @@ impl Future for Server { } } -fn main() { +fn main() -> Result<(), Box> { let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string()); - let addr = addr.parse::().unwrap(); + let addr = addr.parse::()?; - let socket = UdpSocket::bind(&addr).unwrap(); - println!("Listening on: {}", socket.local_addr().unwrap()); + let socket = UdpSocket::bind(&addr)?; + println!("Listening on: {}", socket.local_addr()?); let server = Server { socket: socket, @@ -70,4 +70,5 @@ fn main() { // // `tokio::run` spawns the task on the Tokio runtime and starts running. tokio::run(server.map_err(|e| println!("server error = {:?}", e))); + Ok(()) } diff --git a/examples/echo.rs b/examples/echo.rs index 92d65a90..f33247cb 100644 --- a/examples/echo.rs +++ b/examples/echo.rs @@ -30,19 +30,19 @@ use tokio::prelude::*; use std::env; use std::net::SocketAddr; -fn main() { +fn main() -> Result<(), Box> { // Allow passing an address to listen on as the first argument of this // program, but otherwise we'll just set up our TCP listener on // 127.0.0.1:8080 for connections. let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string()); - let addr = addr.parse::().unwrap(); + let addr = addr.parse::()?; // Next up we create a TCP listener which will listen for incoming // connections. This TCP listener is bound to the address we determined // above and must be associated with an event loop, so we pass in a handle // to our event loop. After the socket's created we inform that we're ready // to go and start accepting connections. - let socket = TcpListener::bind(&addr).unwrap(); + let socket = TcpListener::bind(&addr)?; println!("Listening on: {}", addr); // Here we convert the `TcpListener` to a stream of incoming connections @@ -111,4 +111,5 @@ fn main() { // never completes (it just keeps accepting sockets), `tokio::run` blocks // forever (until ctrl-c is pressed). tokio::run(done); + Ok(()) } diff --git a/examples/hello_world.rs b/examples/hello_world.rs index c94ec53c..a05a8f22 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -19,8 +19,8 @@ use tokio::io; use tokio::net::TcpStream; use tokio::prelude::*; -pub fn main() { - let addr = "127.0.0.1:6142".parse().unwrap(); +pub fn main() -> Result<(), Box> { + let addr = "127.0.0.1:6142".parse()?; // Open a TCP stream to the socket address. // @@ -52,4 +52,6 @@ pub fn main() { println!("About to create the stream and write to it..."); tokio::run(client); println!("Stream has been created and written to."); + + Ok(()) } diff --git a/examples/manual-runtime.rs b/examples/manual-runtime.rs index 6cbb8cd4..8e3e1299 100644 --- a/examples/manual-runtime.rs +++ b/examples/manual-runtime.rs @@ -60,7 +60,7 @@ fn run>(f: F) -> Result<(), IoError> { Ok(()) } -fn main() { +fn main() -> Result<(), Box> { run(future::lazy(|| { // Here comes the application logic. It can spawn further tasks by tokio_current_thread::spawn(). // It also can use the default reactor and create timeouts. @@ -82,5 +82,6 @@ fn main() { // We can spawn on the default executor, which is also the local one. tokio::executor::spawn(deadline); Ok(()) - })).unwrap(); + }))?; + Ok(()) } diff --git a/examples/print_each_packet.rs b/examples/print_each_packet.rs index 644d144c..864d94bd 100644 --- a/examples/print_each_packet.rs +++ b/examples/print_each_packet.rs @@ -65,19 +65,19 @@ use tokio::codec::Decoder; use std::env; use std::net::SocketAddr; -fn main() { +fn main() -> Result<(), Box> { // Allow passing an address to listen on as the first argument of this // program, but otherwise we'll just set up our TCP listener on // 127.0.0.1:8080 for connections. let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string()); - let addr = addr.parse::().unwrap(); + let addr = addr.parse::()?; // Next up we create a TCP listener which will listen for incoming // connections. This TCP listener is bound to the address we determined // above and must be associated with an event loop, so we pass in a handle // to our event loop. After the socket's created we inform that we're ready // to go and start accepting connections. - let socket = TcpListener::bind(&addr).unwrap(); + let socket = TcpListener::bind(&addr)?; println!("Listening on: {}", addr); // Here we convert the `TcpListener` to a stream of incoming connections @@ -146,4 +146,5 @@ fn main() { // never completes (it just keeps accepting sockets), `tokio::run` blocks // forever (until ctrl-c is pressed). tokio::run(done); + Ok(()) } diff --git a/examples/proxy.rs b/examples/proxy.rs index bed8314a..1df115fd 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -33,15 +33,15 @@ use tokio::io::{copy, shutdown}; use tokio::net::{TcpListener, TcpStream}; use tokio::prelude::*; -fn main() { +fn main() -> Result<(), Box> { let listen_addr = env::args().nth(1).unwrap_or("127.0.0.1:8081".to_string()); - let listen_addr = listen_addr.parse::().unwrap(); + let listen_addr = listen_addr.parse::()?; let server_addr = env::args().nth(2).unwrap_or("127.0.0.1:8080".to_string()); - let server_addr = server_addr.parse::().unwrap(); + let server_addr = server_addr.parse::()?; // Create a TCP listener which will listen for incoming connections. - let socket = TcpListener::bind(&listen_addr).unwrap(); + let socket = TcpListener::bind(&listen_addr)?; println!("Listening on: {}", listen_addr); println!("Proxying to: {}", server_addr); @@ -94,6 +94,7 @@ fn main() { }); tokio::run(done); + Ok(()) } // This is a custom type used to have a custom implementation of the diff --git a/examples/tinydb.rs b/examples/tinydb.rs index 134d01b1..702704d3 100644 --- a/examples/tinydb.rs +++ b/examples/tinydb.rs @@ -74,12 +74,12 @@ enum Response { Error { msg: String }, } -fn main() { +fn main() -> Result<(), Box> { // Parse the address we're going to run this server on // and set up our TCP listener to accept connections. let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string()); - let addr = addr.parse::().unwrap(); - let listener = TcpListener::bind(&addr).expect("failed to bind"); + let addr = addr.parse::()?; + let listener = TcpListener::bind(&addr).map_err(|_| "failed to bind")?; println!("Listening on: {}", addr); // Create the shared state of this server that will be shared amongst all @@ -156,6 +156,7 @@ fn main() { }); tokio::run(done); + Ok(()) } impl Request { diff --git a/examples/tinyhttp.rs b/examples/tinyhttp.rs index 1e4f22bd..7a80d730 100644 --- a/examples/tinyhttp.rs +++ b/examples/tinyhttp.rs @@ -34,13 +34,13 @@ use bytes::BytesMut; use http::header::HeaderValue; use http::{Request, Response, StatusCode}; -fn main() { +fn main() -> Result<(), Box> { // Parse the arguments, bind the TCP socket we'll be listening to, spin up // our worker threads, and start shipping sockets to those worker threads. let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string()); - let addr = addr.parse::().unwrap(); + let addr = addr.parse::()?; - let listener = TcpListener::bind(&addr).expect("failed to bind"); + let listener = TcpListener::bind(&addr)?; println!("Listening on: {}", addr); tokio::run({ @@ -51,6 +51,7 @@ fn main() { Ok(()) }) }); + Ok(()) } fn process(socket: TcpStream) { @@ -84,28 +85,32 @@ fn process(socket: TcpStream) { fn respond(req: Request<()>) -> Box, Error = io::Error> + Send> { - let mut ret = Response::builder(); - let body = match req.uri().path() { - "/plaintext" => { - ret.header("Content-Type", "text/plain"); - "Hello, World!".to_string() - } - "/json" => { - ret.header("Content-Type", "application/json"); + let f = future::lazy(move || { + let mut response = Response::builder(); + let body = match req.uri().path() { + "/plaintext" => { + response.header("Content-Type", "text/plain"); + "Hello, World!".to_string() + } + "/json" => { + response.header("Content-Type", "application/json"); - #[derive(Serialize)] - struct Message { - message: &'static str, + #[derive(Serialize)] + struct Message { + message: &'static str, + } + serde_json::to_string(&Message { message: "Hello, World!" })? } - serde_json::to_string(&Message { message: "Hello, World!" }) - .unwrap() - } - _ => { - ret.status(StatusCode::NOT_FOUND); - String::new() - } - }; - Box::new(future::ok(ret.body(body).unwrap())) + _ => { + response.status(StatusCode::NOT_FOUND); + String::new() + } + }; + let response = response.body(body).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; + Ok(response) + }); + + Box::new(f) } struct Http; diff --git a/examples/udp-client.rs b/examples/udp-client.rs index 3af7c3be..d2d4bc99 100644 --- a/examples/udp-client.rs +++ b/examples/udp-client.rs @@ -35,29 +35,27 @@ use std::net::SocketAddr; use tokio::net::UdpSocket; use tokio::prelude::*; -fn get_stdin_data() -> Vec { +fn get_stdin_data() -> Result, Box> { let mut buf = Vec::new(); - stdin().read_to_end(&mut buf).unwrap(); - buf + stdin().read_to_end(&mut buf)?; + Ok(buf) } -fn main() { +fn main() -> Result<(), Box> { let remote_addr: SocketAddr = env::args() .nth(1) .unwrap_or("127.0.0.1:8080".into()) - .parse() - .unwrap(); + .parse()?; // We use port 0 to let the operating system allocate an available port for us. let local_addr: SocketAddr = if remote_addr.is_ipv4() { "0.0.0.0:0" } else { "[::]:0" - }.parse() - .unwrap(); - let socket = UdpSocket::bind(&local_addr).unwrap(); + }.parse()?; + let socket = UdpSocket::bind(&local_addr)?; const MAX_DATAGRAM_SIZE: usize = 65_507; - let processing = socket - .send_dgram(get_stdin_data(), &remote_addr) + socket + .send_dgram(get_stdin_data()?, &remote_addr) .and_then(|(socket, _)| socket.recv_dgram(vec![0u8; MAX_DATAGRAM_SIZE])) .map(|(_, data, len, _)| { println!( @@ -66,9 +64,6 @@ fn main() { String::from_utf8_lossy(&data[..len]) ) }) - .wait(); - match processing { - Ok(_) => {} - Err(e) => eprintln!("Encountered an error: {}", e), - } + .wait()?; + Ok(()) } diff --git a/examples/udp-codec.rs b/examples/udp-codec.rs index b273a360..837266ac 100644 --- a/examples/udp-codec.rs +++ b/examples/udp-codec.rs @@ -19,15 +19,15 @@ use tokio::prelude::*; use tokio::net::{UdpSocket, UdpFramed}; use tokio_codec::BytesCodec; -fn main() { +fn main() -> Result<(), Box> { let _ = env_logger::init(); - let addr: SocketAddr = "127.0.0.1:0".parse().unwrap(); + let addr: SocketAddr = "127.0.0.1:0".parse()?; // Bind both our sockets and then figure out what ports we got. - let a = UdpSocket::bind(&addr).unwrap(); - let b = UdpSocket::bind(&addr).unwrap(); - let b_addr = b.local_addr().unwrap(); + let a = UdpSocket::bind(&addr)?; + let b = UdpSocket::bind(&addr)?; + let b_addr = b.local_addr()?; // We're parsing each socket with the `BytesCodec` included in `tokio_io`, and then we // `split` each codec into the sink/stream halves. @@ -61,4 +61,5 @@ fn main() { .map(|_| ()) .map_err(|e| println!("error = {:?}", e)) }); + Ok(()) } -- cgit v1.2.3