Skip to content

Commit

Permalink
test(binaryinstall): Add initial tests
Browse files Browse the repository at this point in the history
  • Loading branch information
drager committed Jan 23, 2019
1 parent c8410f2 commit 2c263e4
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 14 deletions.
3 changes: 3 additions & 0 deletions binary-install/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ is_executable = "0.1.2"
siphasher = "0.2.3"
tar = "0.4.16"
zip = "0.5.0"

[dev-dependencies]
tempfile = "3.0.5"
97 changes: 83 additions & 14 deletions binary-install/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ use std::path::{Path, PathBuf};

/// Global cache for wasm-pack, currently containing binaries downloaded from
/// urls like wasm-bindgen and such.
#[derive(Debug)]
pub struct Cache {
destination: PathBuf,
}

/// Representation of a downloaded tarball/zip
#[derive(Debug)]
pub struct Download {
root: PathBuf,
}
Expand Down Expand Up @@ -81,22 +83,10 @@ impl Cache {
binaries: &[&str],
url: &str,
) -> Result<Option<Download>, Error> {
let mut hasher = SipHasher13::new();
url.hash(&mut hasher);
let result = hasher.finish();
let hex = hex::encode(&[
(result >> 0) as u8,
(result >> 8) as u8,
(result >> 16) as u8,
(result >> 24) as u8,
(result >> 32) as u8,
(result >> 40) as u8,
(result >> 48) as u8,
(result >> 56) as u8,
]);
let dirname = format!("{}-{}", name, hex);
let dirname = hashed_dirname(url, name);

let destination = self.destination.join(&dirname);

if destination.exists() {
return Ok(Some(Download { root: destination }));
}
Expand Down Expand Up @@ -270,3 +260,82 @@ fn curl(url: &str) -> Result<Vec<u8>, Error> {
)
}
}

fn hashed_dirname(url: &str, name: &str) -> String {
let mut hasher = SipHasher13::new();
url.hash(&mut hasher);
let result = hasher.finish();
let hex = hex::encode(&[
(result >> 0) as u8,
(result >> 8) as u8,
(result >> 16) as u8,
(result >> 24) as u8,
(result >> 32) as u8,
(result >> 40) as u8,
(result >> 48) as u8,
(result >> 56) as u8,
]);
format!("{}-{}", name, hex)
}

#[test]
fn it_returns_same_hash_for_same_name_and_url() {
let name = "wasm-pack";
let url = "http://localhost:7878/wasm-pack-v0.6.0.tar.gz";

let first = hashed_dirname(url, name);
let second = hashed_dirname(url, name);

assert!(!first.is_empty());
assert!(!second.is_empty());
assert_eq!(first, second);
}

#[test]
fn it_returns_different_hashes_for_different_urls() {
let name = "wasm-pack";
let url = "http://localhost:7878/wasm-pack-v0.5.1.tar.gz";
let second_url = "http://localhost:7878/wasm-pack-v0.6.0.tar.gz";

let first = hashed_dirname(url, name);
let second = hashed_dirname(second_url, name);

assert_ne!(first, second);
}

#[test]
fn it_returns_cache_dir() {
let name = "wasm-pack";
let cache = Cache::new(name);

let expected = dirs::cache_dir()
.unwrap()
.join(PathBuf::from(".".to_owned() + name));

assert!(cache.is_ok());
assert_eq!(cache.unwrap().destination, expected);
}

#[test]
fn it_returns_destination_if_binary_already_exists() {
use std::fs;

let binary_name = "wasm-pack";
let binaries = vec![binary_name];

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let url = &format!("{}/{}.tar.gz", "http://localhost:7878", binary_name);

let dirname = hashed_dirname(&url, &binary_name);
let full_path = dir.path().join(dirname);

// Create temporary directory and binary to simulate that
// a cached binary already exists.
fs::create_dir_all(full_path).unwrap();

let dl = cache.download(true, binary_name, &binaries, url);

assert!(dl.is_ok());
assert!(dl.unwrap().is_some())
}
132 changes: 132 additions & 0 deletions binary-install/tests/all/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use binary_install::Cache;
use utils;

#[test]
fn it_returns_none_if_install_is_not_permitted() {
let binary_name = "wasm-pack";
let binaries = vec![binary_name];

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());

let dl = cache.download(
false,
binary_name,
&binaries,
&format!("{}/{}.tar.gz", "", binary_name),
);

assert!(dl.is_ok());
assert!(dl.unwrap().is_none())
}

#[test]
fn it_downloads_tarball() {
let server_port = 7880;
let url = format!("http://{}:{}", utils::TEST_SERVER_HOST, server_port);
let binary_name = "wasm-pack";
let binaries = vec![binary_name];

// Create a temporary tarball.
let tarball = utils::create_tarball(binary_name).ok();

// Spin up a local TcpListener.
utils::start_server(server_port, tarball);

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());

let dl = cache.download(
true,
binary_name,
&binaries,
&format!("{}/{}.tar.gz", &url, binary_name),
);

assert!(dl.is_ok());
assert!(dl.unwrap().is_some())
}

#[test]
fn it_returns_error_that_it_failed_to_download() {
let server_port = 7881;
let url = format!("http://{}:{}", utils::TEST_SERVER_HOST, server_port);
let binary_name = "wasm-pack";
let binaries = vec![binary_name];

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let full_url = &format!("{}/{}.tar.gz", &url, binary_name);

let dl = cache.download(true, binary_name, &binaries, full_url);

assert!(dl.is_err());
assert_eq!(
&format!("failed to download from {}", full_url),
&format!("{}", dl.unwrap_err())
);
}

#[test]
fn it_returns_error_when_it_failed_to_extract_tarball() {
let server_port = 7882;
let url = format!("http://{}:{}", utils::TEST_SERVER_HOST, server_port);
let binary_name = "wasm-pack";
let binaries = vec![binary_name];

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let full_url = &format!("{}/{}.tar.gz", &url, binary_name);

// Spin up a local TcpListener.
utils::start_server(server_port, None);

let dl = cache.download(true, binary_name, &binaries, full_url);

assert!(dl.is_err());
assert_eq!(
&format!("failed to extract tarball from {}", full_url),
&format!("{}", dl.unwrap_err())
);
}

#[test]
fn it_returns_error_when_it_failed_to_extract_zip() {
let server_port = 7883;
let url = format!("http://{}:{}", utils::TEST_SERVER_HOST, server_port);
let binary_name = "wasm-pack";
let binaries = vec![binary_name];

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let full_url = &format!("{}/{}.zip", &url, binary_name);

// Spin up a local TcpListener.
utils::start_server(server_port, None);

let dl = cache.download(true, binary_name, &binaries, full_url);

assert!(dl.is_err());
assert_eq!(
&format!("failed to extract zip from {}", full_url),
&format!("{}", dl.unwrap_err())
);
}

#[test]
#[should_panic(expected = "don't know how to extract http://localhost:7884/wasm-pack.bin")]
fn it_panics_if_not_tarball_or_zip() {
let server_port = 7884;
let url = format!("http://{}:{}", utils::TEST_SERVER_HOST, server_port);
let binary_name = "wasm-pack";
let binaries = vec![binary_name];

let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let full_url = &format!("{}/{}.bin", &url, binary_name);

// Spin up a local TcpListener.
utils::start_server(server_port, None);

let _ = cache.download(true, binary_name, &binaries, full_url);
}
6 changes: 6 additions & 0 deletions binary-install/tests/all/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern crate binary_install;
extern crate flate2;
extern crate tar;

pub mod cache;
pub mod utils;
67 changes: 67 additions & 0 deletions binary-install/tests/all/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use flate2::write::GzEncoder;
use flate2::Compression;
use std::fs::{File, OpenOptions};
use std::io::{self, Read, Write};
use std::net::TcpListener;
use std::thread;

pub const TEST_SERVER_HOST: &'static str = "localhost";

pub fn start_server(port: u32, tarball: Option<Vec<u8>>) -> thread::JoinHandle<TcpListener> {
thread::spawn(move || {
let listener = TcpListener::bind(format!("{}:{}", TEST_SERVER_HOST, port)).unwrap();

for stream in listener.incoming() {
let mut stream = stream.unwrap();

let mut buffer = [0; 512];

stream.read(&mut buffer).unwrap();

let response = "HTTP/1.1 200 OK\r\n\r\n";

stream.write(response.as_bytes()).unwrap();

match tarball.to_owned() {
Some(tar) => {
stream.write(tar.as_ref()).unwrap();
}
None => {}
}

stream.flush().unwrap();
}
listener
})
}

pub fn create_tarball(binary_name: &str) -> Result<Vec<u8>, io::Error> {
let temp_dir = tempfile::TempDir::new().unwrap();
let full_path = temp_dir.path().join(binary_name.to_owned() + ".tar.gz");

let tar = OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(&full_path)?;

let mut file = OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(temp_dir.path().join(binary_name))?;

let mut encoder = GzEncoder::new(tar, Compression::default());
{
let mut archive = tar::Builder::new(&mut encoder);
archive.append_file(binary_name, &mut file)?;
}

let mut contents = vec![];

encoder.finish()?;

File::open(temp_dir.path().join(&full_path))?.read_to_end(&mut contents)?;

Ok(contents)
}

0 comments on commit 2c263e4

Please sign in to comment.