From 9e704977818cb59f1d980a22b458cb37e2a0e0d0 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 28 Nov 2016 09:53:16 -0800 Subject: [PATCH] add integration tests --- tests/client.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++ tests/server.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 tests/client.rs create mode 100644 tests/server.rs diff --git a/tests/client.rs b/tests/client.rs new file mode 100644 index 0000000..c6e8863 --- /dev/null +++ b/tests/client.rs @@ -0,0 +1,77 @@ +extern crate reqwest; + +#[macro_use] mod server; + +use std::io::Read; + +#[test] +fn test_get() { + let server = server! { + request: b"\ + GET /1 HTTP/1.1\r\n\ + Host: $HOST\r\n\ + User-Agent: $USERAGENT\r\n\ + \r\n\ + ", + response: b"\ + HTTP/1.1 200 OK\r\n\ + Server: test\r\n\ + Content-Length: 0\r\n\ + \r\n\ + " + }; + + let mut res = reqwest::get(&format!("http://{}/1", server.addr())).unwrap(); + assert_eq!(res.status(), &reqwest::StatusCode::Ok); + assert_eq!(res.version(), &reqwest::HttpVersion::Http11); + assert_eq!(res.headers().get(), Some(&reqwest::header::Server("test".to_string()))); + assert_eq!(res.headers().get(), Some(&reqwest::header::ContentLength(0))); + + let mut buf = [0; 1024]; + let n = res.read(&mut buf).unwrap(); + assert_eq!(n, 0) +} + +#[test] +fn test_redirect_302_changes_post_to_get() { + + let redirect = server! { + request: b"\ + POST /302 HTTP/1.1\r\n\ + Host: $HOST\r\n\ + User-Agent: $USERAGENT\r\n\ + Content-Length: 0\r\n\ + \r\n\ + ", + response: b"\ + HTTP/1.1 302 Found\r\n\ + Server: test-redirect\r\n\ + Content-Length: 0\r\n\ + Location: /dst\r\n\ + Connection: close\r\n\ + \r\n\ + ", + + request: b"\ + GET /dst HTTP/1.1\r\n\ + Host: $HOST\r\n\ + User-Agent: $USERAGENT\r\n\ + Referer: http://$HOST/302\r\n\ + \r\n\ + ", + response: b"\ + HTTP/1.1 200 OK\r\n\ + Server: test-dst\r\n\ + Content-Length: 0\r\n\ + \r\n\ + " + }; + + let client = reqwest::Client::new().unwrap(); + let res = client.post(&format!("http://{}/302", redirect.addr())) + .send() + .unwrap(); + assert_eq!(res.status(), &reqwest::StatusCode::Ok); + assert_eq!(res.headers().get(), Some(&reqwest::header::Server("test-dst".to_string()))); + +} diff --git a/tests/server.rs b/tests/server.rs new file mode 100644 index 0000000..33b75cc --- /dev/null +++ b/tests/server.rs @@ -0,0 +1,83 @@ +//! A server builder helper for the integration tests. + +use std::io::{Read, Write}; +use std::net; +use std::thread; + +pub struct Server { + addr: net::SocketAddr, +} + +impl Server { + pub fn addr(&self) -> net::SocketAddr { + self.addr + } +} + +static DEFAULT_USER_AGENT: &'static str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); + +pub fn spawn(txns: Vec<(Vec, Vec)>) -> Server { + let listener = net::TcpListener::bind("0.0.0.0:0").unwrap(); + let addr = listener.local_addr().unwrap(); + thread::spawn(move || { + for (mut expected, reply) in txns { + let (mut socket, _addr) = listener.accept().unwrap(); + replace_expected_vars(&mut expected, addr.to_string().as_ref(), DEFAULT_USER_AGENT.as_ref()); + let mut buf = [0; 4096]; + let n = socket.read(&mut buf).unwrap(); + + match (::std::str::from_utf8(&expected), ::std::str::from_utf8(&buf[..n])) { + (Ok(expected), Ok(received)) => assert_eq!(expected, received), + _ => assert_eq!(expected, &buf[..n]) + } + socket.write_all(&reply).unwrap(); + } + }); + + Server { + addr: addr, + } +} + +fn replace_expected_vars(bytes: &mut Vec, host: &[u8], ua: &[u8]) { + // plenty horrible, but these are just tests, and gets the job done + let mut index = 0; + loop { + if index == bytes.len() { + return; + } + + for b in (&bytes[index..]).iter() { + index += 1; + if *b == b'$' { + break; + } + } + + let has_host = (&bytes[index..]).starts_with(b"HOST"); + if has_host { + bytes.drain(index - 1..index + 4); + for (i, b) in host.iter().enumerate() { + bytes.insert(index - 1 + i, *b); + } + } else { + let has_ua = (&bytes[index..]).starts_with(b"USERAGENT"); + if has_ua { + bytes.drain(index - 1..index + 9); + for (i, b) in ua.iter().enumerate() { + bytes.insert(index - 1 + i, *b); + } + } + } + } +} + +#[macro_export] +macro_rules! server { + ($(request: $req:expr, response: $res:expr),*) => ({ + let txns = vec![ + $(((&$req[..]).into(), (&$res[..]).into()),)* + ]; + ::server::spawn(txns) + }) +}