tests: Auto cleanup of download folders + multiple servers

Signed-off-by: Esteban Blanc <estblcsk@gmail.com>
This commit is contained in:
Esteban Blanc 2023-05-01 20:18:22 +02:00
parent 786503677a
commit 7f6c4c34a5
13 changed files with 185 additions and 205 deletions

29
Cargo.lock generated
View file

@ -892,6 +892,15 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "mktemp"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bdc1f74dd7bb717d39f784f844e490d935b3aa7e383008006dbbf29c1f7820a"
dependencies = [
"uuid",
]
[[package]]
name = "native-tls"
version = "0.2.11"
@ -1127,6 +1136,15 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "portpicker"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be97d76faf1bfab666e1375477b23fde79eccf0276e9b63b92a39d676a889ba9"
dependencies = [
"rand 0.8.5",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -1624,7 +1642,9 @@ dependencies = [
"kuchiki",
"lazy_static",
"md5",
"mktemp",
"pathdiff",
"portpicker",
"rand 0.8.5",
"regex",
"reqwest",
@ -1898,6 +1918,15 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
dependencies = [
"getrandom 0.2.9",
]
[[package]]
name = "vcpkg"
version = "0.2.15"

View file

@ -50,6 +50,8 @@ symlink = "^0.1.0"
[dev-dependencies]
tiny_http = "^0.12"
subprocess = "^0.2"
mktemp = "^0.5"
portpicker = "^0.1"
[profile.release]
lto = true

View file

@ -5,36 +5,26 @@ mod fixtures;
use std::fs::read_dir;
use std::process::Command;
use std::process::Stdio;
use std::sync::Once;
const PAGE: &'static str = "tests/fixtures/";
const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
#[test]
fn test_auth() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE, true, None);
});
// Tests below are grouped together as they depend on the local_http_server above.
auth_different_host();
auth_valid();
}
// Shouldn't supply credentials to a non-matching host
#[test]
fn auth_different_host() {
let output_dir = "w4";
let ip = fixtures::spawn_local_http_server(PAGE, true, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
&url,
"-o",
"w4",
output_dir,
"-a",
"username password example.com",
"-j",
"16",
])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
@ -44,25 +34,22 @@ fn auth_different_host() {
let status = cmd.wait().unwrap();
assert!(status.success());
let paths = read_dir(format!("{}/{}", output_dir, IP)).unwrap();
// Only the initial invalid response file should be present
assert_eq!(paths.count(), 1);
std::fs::remove_dir_all(output_dir).unwrap();
}
// Should authenticate with credentials to host (defaulting to origin host)
#[test]
fn auth_valid() {
let output_dir = "w5";
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
"w5",
"-a",
"username password",
"-j",
"16",
])
.args(&[&url, "-o", output_dir, "-a", "username password"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -70,11 +57,8 @@ fn auth_valid() {
let status = cmd.wait().unwrap();
assert!(status.success());
let paths = read_dir(format!("{}/{}", output_dir, IP)).unwrap();
// Should load multiple paths, not just the invalid auth response
let paths_count = paths.count();
println!("Paths.count() = {}", paths_count);
assert!(paths_count > 1);
std::fs::remove_dir_all(output_dir).unwrap();
assert!(paths.count() > 1);
}

View file

@ -9,18 +9,16 @@ use std::sync::Once;
const PAGE: &'static str = "tests/fixtures";
const PAGE_META: &'static str = "tests/fixtures/charset_test_html.html";
const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
#[test]
fn test_html_charset_found() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE, false, None);
});
let addr = fixtures::spawn_local_http_server(PAGE, false, None);
let output_dir = "charset_html_found";
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let file_dir = format!("{}/{}", output_dir, IP);
let url = format!("{}/charset_test_html.html", fixtures::HTTP_ADDR);
let url = format!("http://{}/charset_test_html.html", addr);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[&url, "-o", output_dir])
.stdout(Stdio::inherit())
@ -40,6 +38,4 @@ fn test_html_charset_found() {
let data_downloaded = fs::read(file_path).unwrap();
assert!(fixtures::do_vecs_match(&data_source, &data_downloaded));
fs::remove_dir_all(output_dir).unwrap();
}

View file

@ -4,29 +4,30 @@ mod fixtures;
use std::fs;
use std::process::{Command, Stdio};
use std::sync::Once;
const PAGE: &'static str = "tests/fixtures/";
const PAGE_NO_META: &'static str = "tests/fixtures/charset_test_html_no_meta.html";
const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
#[test]
fn test_html_charset_not_found() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE_NO_META, false, None);
});
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let output_dir = "charset_html_not_found";
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
// Spawn a single instance of a local http server usable by all tests in this module.
let file_dir = format!("{}/{}", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[fixtures::HTTP_ADDR, "-o", output_dir])
.args(&[&url, "-o", output_dir])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.unwrap();
let status = cmd.wait().unwrap();
assert!(status.success());
let file_path = fs::read_dir(file_dir)
.unwrap()
.next()
@ -38,6 +39,4 @@ fn test_html_charset_not_found() {
let data_downloaded = fs::read(file_path).unwrap();
assert!(!fixtures::do_vecs_match(&data_source, &data_downloaded));
fs::remove_dir_all(output_dir).unwrap();
}

View file

@ -4,14 +4,12 @@ mod fixtures;
use std::fs;
use std::process::{Command, Stdio};
use std::sync::Once;
use lazy_static::lazy_static;
const PAGE: &'static str = "tests/fixtures/";
const PAGE_NO_META: &'static str = "tests/fixtures/charset_test_html_no_meta.html";
const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
lazy_static! {
static ref CHARSET_HEADER: Vec<(&'static str, &'static str)> =
@ -20,14 +18,13 @@ lazy_static! {
#[test]
fn test_http_charset_found() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE, false, Some(&CHARSET_HEADER));
});
let ip = fixtures::spawn_local_http_server(PAGE, false, Some(&CHARSET_HEADER));
let url = format!("http://{}/charset_test_html_no_meta.html", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let output_dir = "charset_html_found";
let file_dir = format!("{}/{}", output_dir, IP);
let url = format!("{}/charset_test_html_no_meta.html", fixtures::HTTP_ADDR);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[&url, "-o", output_dir])
.stdout(Stdio::inherit())
@ -36,6 +33,7 @@ fn test_http_charset_found() {
.unwrap();
let status = cmd.wait().unwrap();
assert!(status.success());
let file_path = fs::read_dir(file_dir)
.unwrap()
.next()
@ -47,6 +45,4 @@ fn test_http_charset_found() {
let data_downloaded = fs::read(file_path).unwrap();
assert!(fixtures::do_vecs_match(&data_source, &data_downloaded));
fs::remove_dir_all(output_dir).unwrap();
}

View file

@ -4,29 +4,30 @@ mod fixtures;
use std::fs;
use std::process::{Command, Stdio};
use std::sync::Once;
const PAGE: &'static str = "tests/fixtures/";
const PAGE_NO_META: &'static str = "tests/fixtures/charset_test_html_no_meta.html";
const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
#[test]
fn test_http_charset_found() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE_NO_META, false, None);
});
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let output_dir = "charset_html_found";
let file_dir = format!("{}/{}", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[fixtures::HTTP_ADDR, "-o", output_dir])
.args(&[&url, "-o", output_dir])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.unwrap();
let status = cmd.wait().unwrap();
assert!(status.success());
let file_path = fs::read_dir(file_dir)
.unwrap()
.next()
@ -38,6 +39,4 @@ fn test_http_charset_found() {
let data_downloaded = fs::read(file_path).unwrap();
assert!(!fixtures::do_vecs_match(&data_source, &data_downloaded));
fs::remove_dir_all(output_dir).unwrap();
}

View file

@ -10,35 +10,21 @@ use std::sync::Once;
const PAGE: &'static str = "tests/fixtures/";
const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
#[test]
fn test_external_download() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE, false, None);
});
// Tests below are grouped together as they depend on the local_http_server above.
with_external();
without_external();
}
// Test to use include flag for downloading pages only matching the given pattern.
#[test]
fn with_external() {
let output_dir = "w1";
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let local = format!("{}/{}/", output_dir, IP);
let external = format!("{}/{}/", output_dir, "google.com");
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"-d",
"0",
"--ext-depth",
"1",
])
.args(&[&url, "-o", output_dir, "-d", "0", "--ext-depth", "1"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -50,23 +36,19 @@ fn with_external() {
let path_external = read_dir(&external).unwrap();
assert_eq!(path_local.count() + path_external.count(), 2);
std::fs::remove_dir_all(output_dir).unwrap();
}
#[test]
fn without_external() {
let output_dir = "w2";
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let external = format!("{}/{}/", output_dir, "google.com");
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"-d",
"0",
"--ext-depth",
"0",
])
.args(&[&url, "-o", output_dir, "-d", "0", "--ext-depth", "0"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -77,6 +59,4 @@ fn without_external() {
let path_external = read_dir(&external);
assert!(path_external.is_err());
std::fs::remove_dir_all(output_dir).unwrap();
}

View file

@ -13,38 +13,50 @@ const IP: &'static str = "0.0.0.0";
static START: Once = Once::new();
#[test]
fn test_include_exclude() {
// Spawn a single instance of a local http server usable by all tests in this module.
START.call_once(|| {
fixtures::spawn_local_http_server(PAGE, false, None);
});
fn visit_filter_is_download_filter() {
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
// Tests below are grouped together as they depend on the local_http_server above.
download_include_filter();
download_include_multiple_filters();
download_exclude_filter();
visit_include_filter();
visit_include_multiple_filters();
visit_exclude_filter();
}
// Test to use include flag for visiting pages only matching the given pattern.
fn visit_include_filter() {
let output_dir = "w2";
let _ = std::fs::remove_dir_all(output_dir);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
&url,
"-o",
output_dir,
"--include-visit",
"mp[3-4]",
"-j",
"16",
"-v",
"-e",
"no_download_no_visit.html",
"--visit-filter-is-download-filter",
])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let result = cmd.wait_with_output().unwrap();
let stdout_str = unsafe { String::from_utf8_unchecked(result.stdout) };
assert!(result.status.success());
let paths = read_dir(&files_dir).unwrap();
assert!(!stdout_str.contains("should_not_get_visited.html"));
}
// Test to use include flag for visiting pages only matching the given pattern.
#[test]
fn visit_include_filter() {
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[&url, "-o", output_dir, "--include-visit", "mp[3-4]"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -58,26 +70,20 @@ fn visit_include_filter() {
paths.count() - 1, // minus one because of index.html which is downloaded unconditionally
get_file_count_with_pattern(".mp3", &files_dir).unwrap()
);
std::fs::remove_dir_all(output_dir).unwrap();
}
// Test demonstrating usage of multiple include patterns for visiting pages only matching the given pattern.
#[test]
fn visit_include_multiple_filters() {
let output_dir = "w1";
let _ = std::fs::remove_dir_all(output_dir);
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"--include-visit",
"(mp[3-4])|(txt)",
"-j",
"16",
])
.args(&[&url, "-o", output_dir, "--include-visit", "(mp[3-4])|(txt)"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -91,26 +97,20 @@ fn visit_include_multiple_filters() {
paths.count() - 1, // minus one because of index.html which is downloaded unconditionally
mp3_count + txt_count
);
std::fs::remove_dir_all(output_dir).unwrap();
}
// Test to use exclude flag for excluding pages matching the given pattern.
#[test]
fn visit_exclude_filter() {
let output_dir = "w3";
let _ = std::fs::remove_dir_all(output_dir);
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"--exclude-visit",
"jpe?g",
"-j",
"16",
])
.args(&[&url, "-o", output_dir, "--exclude-visit", "jpe?g"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -118,29 +118,23 @@ fn visit_exclude_filter() {
let status = cmd.wait().unwrap();
assert!(status.success());
let paths = read_dir(&files_dir).unwrap();
let jpeg_count = get_file_count_with_pattern(".jpe?g", &files_dir).unwrap();
assert_eq!(jpeg_count, 0);
std::fs::remove_dir_all(output_dir).unwrap();
}
// Test to use include flag for downloading pages only matching the given pattern.
#[test]
fn download_include_filter() {
let output_dir = "w2";
let _ = std::fs::remove_dir_all(output_dir);
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"-i",
"mp[3-4]",
"-j",
"16",
])
.args(&[&url, "-o", output_dir, "-i", "mp[3-4]"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -159,51 +153,42 @@ fn download_include_filter() {
}
// Test demonstrating usage of multiple include patterns for downloading pages only matching the given pattern.
#[test]
fn download_include_multiple_filters() {
let output_dir = "w1";
let _ = std::fs::remove_dir_all(output_dir);
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"-i",
"(mp[3-4])|(txt)",
"-j",
"16",
])
.args(&[&url, "-o", output_dir, "-i", "(mp[3-4])|(txt)"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.unwrap();
let status = cmd.wait().unwrap();
assert!(status.success());
let paths = read_dir(&files_dir).unwrap();
let mp3_count = get_file_count_with_pattern(".mp3", &files_dir).unwrap();
let txt_count = get_file_count_with_pattern(".txt", &files_dir).unwrap();
assert_eq!(paths.count(), mp3_count + txt_count);
std::fs::remove_dir_all(output_dir).unwrap();
}
// Test to use exclude flag for excluding pages matching the given pattern.
#[test]
fn download_exclude_filter() {
let output_dir = "w3";
let _ = std::fs::remove_dir_all(output_dir);
let ip = fixtures::spawn_local_http_server(PAGE, false, None);
let url = format!("http://{}", ip);
let tempdir = mktemp::Temp::new_dir().unwrap();
let output_dir = tempdir.to_str().unwrap();
let files_dir = format!("{}/{}/", output_dir, IP);
let mut cmd = Command::new(env!("CARGO_BIN_EXE_suckit"))
.args(&[
fixtures::HTTP_ADDR,
"-o",
output_dir,
"-e",
"jpe?g",
"-j",
"16",
])
.args(&[&url, "-o", output_dir, "-e", "jpe?g"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
@ -214,6 +199,4 @@ fn download_exclude_filter() {
let paths = read_dir(&files_dir).unwrap();
let jpeg_count = get_file_count_with_pattern(".jpe?g", &files_dir).unwrap();
assert_eq!(jpeg_count, 0);
std::fs::remove_dir_all(output_dir).unwrap();
}

View file

@ -10,5 +10,6 @@
<a href="mp3.mp3" download="">MP3 File</a>
<a href="file.txt" download="">Text File</a>
<a href="https://google.com" download="">Google</a>
<a href="no_download_no_visit.html">No download</a>
</body>
</html>

13
tests/fixtures/mod.rs vendored
View file

@ -1,11 +1,10 @@
use std::fs::File;
use std::thread;
use portpicker;
use subprocess::Exec;
use tiny_http::{Header, Response, Server};
pub const HTTP_ADDR: &'static str = "http://0.0.0.0:8000";
const ADDR: &'static str = "0.0.0.0:8000";
const AUTH_HEADER: &str = "Authorization";
const AUTH_CREDENTIALS: &str = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="; // base64-encoded "username:password"
@ -13,9 +12,10 @@ pub fn spawn_local_http_server(
page: &'static str,
requires_auth: bool,
headers: Option<&'static Vec<(&'static str, &'static str)>>,
) {
let server = Server::http(ADDR).unwrap();
println!("Spawning http server");
) -> String {
let port = portpicker::pick_unused_port().unwrap();
let addr = format!("0.0.0.0:{}", port);
let server = Server::http(&addr).unwrap();
thread::spawn(move || {
for request in server.incoming_requests() {
// Authenticate request from headers if provided
@ -35,6 +35,7 @@ pub fn spawn_local_http_server(
"/" => format!("{}{}", page, "index.html"),
other => format!("{}{}", page, other),
};
// panic!("File = {}", file);
Response::from_file(File::open(file).unwrap()).boxed()
};
@ -56,6 +57,8 @@ pub fn spawn_local_http_server(
request.respond(response).unwrap();
}
});
return addr;
}
fn check_auth_credentials(auth_header: Option<&Header>) -> bool {

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<a href="should_not_get_visited.html">Link</a>
</body>
</html>

View file