aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/archive.rs18
-rw-r--r--tests/auth.rs147
-rw-r--r--tests/auth_file.rs49
-rw-r--r--tests/bind.rs10
-rw-r--r--tests/cli.rs8
-rw-r--r--tests/create_directories.rs29
-rw-r--r--tests/fixtures/mod.rs72
-rw-r--r--tests/header.rs14
-rw-r--r--tests/navigation.rs38
-rw-r--r--tests/qrcode.rs15
-rw-r--r--tests/raw.rs51
-rw-r--r--tests/readme.rs52
-rw-r--r--tests/serve_request.rs67
-rw-r--r--tests/tls.rs7
-rw-r--r--tests/upload_files.rs16
-rw-r--r--tests/utils/mod.rs4
-rw-r--r--tests/webdav.rs150
17 files changed, 428 insertions, 319 deletions
diff --git a/tests/archive.rs b/tests/archive.rs
index e6d0263..a8b5ed2 100644
--- a/tests/archive.rs
+++ b/tests/archive.rs
@@ -1,10 +1,10 @@
-mod fixtures;
-
-use fixtures::{server, Error, TestServer};
-use reqwest::StatusCode;
+use reqwest::StatusCode;
use rstest::rstest;
-use select::document::Document;
-use select::predicate::Text;
+use select::{document::Document, predicate::Text};
+
+mod fixtures;
+
+use crate::fixtures::{server, Error, TestServer};
#[rstest]
fn archives_are_disabled(server: TestServer) -> Result<(), Error> {
@@ -58,8 +58,10 @@ fn test_tar_archives(#[with(&["-g"])] server: TestServer) -> Result<(), Error> {
}
#[rstest]
-#[case(server(&["--disable-indexing", "--enable-tar-gz", "--enable-tar", "--enable-zip"]))]
-fn archives_are_disabled_when_indexing_disabled(#[case] server: TestServer) -> Result<(), Error> {
+fn archives_are_disabled_when_indexing_disabled(
+ #[with(&["--disable-indexing", "--enable-tar-gz", "--enable-tar", "--enable-zip"])]
+ server: TestServer,
+) -> Result<(), Error> {
// Ensure the links to the archives are not present
let body = reqwest::blocking::get(server.url())?;
let parsed = Document::from_read(body)?;
diff --git a/tests/auth.rs b/tests/auth.rs
index 920f738..efa7827 100644
--- a/tests/auth.rs
+++ b/tests/auth.rs
@@ -1,31 +1,28 @@
-mod fixtures;
-
-use fixtures::{server, server_no_stderr, Error, FILES};
use pretty_assertions::assert_eq;
-use reqwest::blocking::Client;
-use reqwest::StatusCode;
+use reqwest::{blocking::Client, StatusCode};
use rstest::rstest;
-use select::document::Document;
-use select::predicate::Text;
-
-#[rstest(
- cli_auth_arg, client_username, client_password,
- case("testuser:testpassword", "testuser", "testpassword"),
- case(
- "testuser:sha256:9f735e0df9a1ddc702bf0a1a7b83033f9f7153a00c29de82cedadc9957289b05",
- "testuser",
- "testpassword"
- ),
- case(
- "testuser:sha512:e9e633097ab9ceb3e48ec3f70ee2beba41d05d5420efee5da85f97d97005727587fda33ef4ff2322088f4c79e8133cc9cd9f3512f4d3a303cbdb5bc585415a00",
- "testuser",
- "testpassword"
- ),
+use select::{document::Document, predicate::Text};
+
+mod fixtures;
+
+use crate::fixtures::{server, Error, FILES};
+
+#[rstest]
+#[case("testuser:testpassword", "testuser", "testpassword")]
+#[case(
+ "testuser:sha256:9f735e0df9a1ddc702bf0a1a7b83033f9f7153a00c29de82cedadc9957289b05",
+ "testuser",
+ "testpassword"
+)]
+#[case(
+ "testuser:sha512:e9e633097ab9ceb3e48ec3f70ee2beba41d05d5420efee5da85f97d97005727587fda33ef4ff2322088f4c79e8133cc9cd9f3512f4d3a303cbdb5bc585415a00",
+ "testuser",
+ "testpassword"
)]
fn auth_accepts(
- cli_auth_arg: &str,
- client_username: &str,
- client_password: &str,
+ #[case] cli_auth_arg: &str,
+ #[case] client_username: &str,
+ #[case] client_password: &str,
) -> Result<(), Error> {
let server = server(&["-a", cli_auth_arg]);
let client = Client::new();
@@ -46,37 +43,35 @@ fn auth_accepts(
Ok(())
}
-#[rstest(
- cli_auth_arg, client_username, client_password,
- case("rightuser:rightpassword", "wronguser", "rightpassword"),
- case(
- "rightuser:sha256:314eee236177a721d0e58d3ca4ff01795cdcad1e8478ba8183a2e58d69c648c0",
- "wronguser",
- "rightpassword"
- ),
- case(
- "rightuser:sha512:84ec4056571afeec9f5b59453305877e9a66c3f9a1d91733fde759b370c1d540b9dc58bfc88c5980ad2d020c3a8ee84f21314a180856f5a82ba29ecba29e2cab",
- "wronguser",
- "rightpassword"
- ),
- case("rightuser:rightpassword", "rightuser", "wrongpassword"),
- case(
- "rightuser:sha256:314eee236177a721d0e58d3ca4ff01795cdcad1e8478ba8183a2e58d69c648c0",
- "rightuser",
- "wrongpassword"
- ),
- case(
- "rightuser:sha512:84ec4056571afeec9f5b59453305877e9a66c3f9a1d91733fde759b370c1d540b9dc58bfc88c5980ad2d020c3a8ee84f21314a180856f5a82ba29ecba29e2cab",
- "rightuser",
- "wrongpassword"
- ),
+#[rstest]
+#[case("rightuser:rightpassword", "wronguser", "rightpassword")]
+#[case(
+ "rightuser:sha256:314eee236177a721d0e58d3ca4ff01795cdcad1e8478ba8183a2e58d69c648c0",
+ "wronguser",
+ "rightpassword"
+)]
+#[case(
+ "rightuser:sha512:84ec4056571afeec9f5b59453305877e9a66c3f9a1d91733fde759b370c1d540b9dc58bfc88c5980ad2d020c3a8ee84f21314a180856f5a82ba29ecba29e2cab",
+ "wronguser",
+ "rightpassword"
+)]
+#[case("rightuser:rightpassword", "rightuser", "wrongpassword")]
+#[case(
+ "rightuser:sha256:314eee236177a721d0e58d3ca4ff01795cdcad1e8478ba8183a2e58d69c648c0",
+ "rightuser",
+ "wrongpassword"
+)]
+#[case(
+ "rightuser:sha512:84ec4056571afeec9f5b59453305877e9a66c3f9a1d91733fde759b370c1d540b9dc58bfc88c5980ad2d020c3a8ee84f21314a180856f5a82ba29ecba29e2cab",
+ "rightuser",
+ "wrongpassword"
)]
fn auth_rejects(
- cli_auth_arg: &str,
- client_username: &str,
- client_password: &str,
+ #[case] cli_auth_arg: &str,
+ #[case] client_username: &str,
+ #[case] client_password: &str,
) -> Result<(), Error> {
- let server = server_no_stderr(&["-a", cli_auth_arg]);
+ let server = server(&["-a", cli_auth_arg]);
let client = Client::new();
let status = client
.get(server.url())
@@ -106,17 +101,17 @@ static ACCOUNTS: &[&str] = &[
// pwd5
];
-#[rstest(
- username,
- password,
- case("usr0", "pwd0"),
- case("usr1", "pwd1"),
- case("usr2", "pwd2"),
- case("usr3", "pwd3"),
- case("usr4", "pwd4"),
- case("usr5", "pwd5")
-)]
-fn auth_multiple_accounts_pass(username: &str, password: &str) -> Result<(), Error> {
+#[rstest]
+#[case("usr0", "pwd0")]
+#[case("usr1", "pwd1")]
+#[case("usr2", "pwd2")]
+#[case("usr3", "pwd3")]
+#[case("usr4", "pwd4")]
+#[case("usr5", "pwd5")]
+fn auth_multiple_accounts_pass(
+ #[case] username: &str,
+ #[case] password: &str,
+) -> Result<(), Error> {
let server = server(ACCOUNTS);
let client = Client::new();
@@ -139,7 +134,7 @@ fn auth_multiple_accounts_pass(username: &str, password: &str) -> Result<(), Err
#[rstest]
fn auth_multiple_accounts_wrong_username() -> Result<(), Error> {
- let server = server_no_stderr(ACCOUNTS);
+ let server = server(ACCOUNTS);
let client = Client::new();
let status = client
@@ -153,18 +148,18 @@ fn auth_multiple_accounts_wrong_username() -> Result<(), Error> {
Ok(())
}
-#[rstest(
- username,
- password,
- case("usr0", "pwd5"),
- case("usr1", "pwd4"),
- case("usr2", "pwd3"),
- case("usr3", "pwd2"),
- case("usr4", "pwd1"),
- case("usr5", "pwd0")
-)]
-fn auth_multiple_accounts_wrong_password(username: &str, password: &str) -> Result<(), Error> {
- let server = server_no_stderr(ACCOUNTS);
+#[rstest]
+#[case("usr0", "pwd5")]
+#[case("usr1", "pwd4")]
+#[case("usr2", "pwd3")]
+#[case("usr3", "pwd2")]
+#[case("usr4", "pwd1")]
+#[case("usr5", "pwd0")]
+fn auth_multiple_accounts_wrong_password(
+ #[case] username: &str,
+ #[case] password: &str,
+) -> Result<(), Error> {
+ let server = server(ACCOUNTS);
let client = Client::new();
let status = client
diff --git a/tests/auth_file.rs b/tests/auth_file.rs
index ddc9e25..5632d46 100644
--- a/tests/auth_file.rs
+++ b/tests/auth_file.rs
@@ -1,26 +1,20 @@
+use reqwest::{blocking::Client, StatusCode};
+use rstest::rstest;
+use select::{document::Document, predicate::Text};
+
mod fixtures;
-use fixtures::{server, server_no_stderr, Error, FILES};
-use http::StatusCode;
-use reqwest::blocking::Client;
-use rstest::rstest;
-use select::document::Document;
-use select::predicate::Text;
+use crate::fixtures::{server, Error, TestServer, FILES};
-#[rstest(
- cli_auth_file_arg,
- client_username,
- client_password,
- case("tests/data/auth1.txt", "joe", "123"),
- case("tests/data/auth1.txt", "bob", "123"),
- case("tests/data/auth1.txt", "bill", "")
-)]
+#[rstest]
+#[case("joe", "123")]
+#[case("bob", "123")]
+#[case("bill", "")]
fn auth_file_accepts(
- cli_auth_file_arg: &str,
- client_username: &str,
- client_password: &str,
+ #[with(&["--auth-file", "tests/data/auth1.txt"])] server: TestServer,
+ #[case] client_username: &str,
+ #[case] client_password: &str,
) -> Result<(), Error> {
- let server = server(&["--auth-file", cli_auth_file_arg]);
let client = Client::new();
let response = client
.get(server.url())
@@ -39,20 +33,15 @@ fn auth_file_accepts(
Ok(())
}
-#[rstest(
- cli_auth_file_arg,
- client_username,
- client_password,
- case("tests/data/auth1.txt", "joe", "wrongpassword"),
- case("tests/data/auth1.txt", "bob", ""),
- case("tests/data/auth1.txt", "nonexistentuser", "wrongpassword")
-)]
+#[rstest]
+#[case("joe", "wrongpassword")]
+#[case("bob", "")]
+#[case("nonexistentuser", "wrongpassword")]
fn auth_file_rejects(
- cli_auth_file_arg: &str,
- client_username: &str,
- client_password: &str,
+ #[with(&["--auth-file", "tests/data/auth1.txt"])] server: TestServer,
+ #[case] client_username: &str,
+ #[case] client_password: &str,
) -> Result<(), Error> {
- let server = server_no_stderr(&["--auth-file", cli_auth_file_arg]);
let client = Client::new();
let status = client
.get(server.url())
diff --git a/tests/bind.rs b/tests/bind.rs
index 0fa914e..e6c448a 100644
--- a/tests/bind.rs
+++ b/tests/bind.rs
@@ -1,12 +1,14 @@
-mod fixtures;
+use std::io::{BufRead, BufReader};
+use std::process::{Command, Stdio};
use assert_cmd::prelude::*;
use assert_fs::fixture::TempDir;
-use fixtures::{port, server, tmpdir, Error, TestServer};
use regex::Regex;
use rstest::rstest;
-use std::io::{BufRead, BufReader};
-use std::process::{Command, Stdio};
+
+mod fixtures;
+
+use crate::fixtures::{port, server, tmpdir, Error, TestServer};
#[rstest]
#[case(&["-i", "12.123.234.12"])]
diff --git a/tests/cli.rs b/tests/cli.rs
index 8ec03a8..7c53698 100644
--- a/tests/cli.rs
+++ b/tests/cli.rs
@@ -1,10 +1,12 @@
-mod fixtures;
+use std::process::Command;
use assert_cmd::prelude::*;
use clap::{crate_name, crate_version, ValueEnum};
use clap_complete::Shell;
-use fixtures::Error;
-use std::process::Command;
+
+mod fixtures;
+
+use crate::fixtures::Error;
#[test]
/// Show help and exit.
diff --git a/tests/create_directories.rs b/tests/create_directories.rs
index 380c796..bd9259f 100644
--- a/tests/create_directories.rs
+++ b/tests/create_directories.rs
@@ -1,14 +1,13 @@
-mod fixtures;
-
-use fixtures::{server, Error, TestServer, DIRECTORIES};
use reqwest::blocking::{multipart, Client};
use rstest::rstest;
-use select::document::Document;
-use select::predicate::{Attr, Text};
-#[cfg(unix)]
-use std::os::unix::fs::symlink as symlink_dir;
-#[cfg(windows)]
-use std::os::windows::fs::symlink_dir;
+use select::{
+ document::Document,
+ predicate::{Attr, Text},
+};
+
+mod fixtures;
+
+use crate::fixtures::{server, Error, TestServer, DIRECTORY_SYMLINK};
/// This should work because the flags for uploading files and creating directories
/// are set, and the directory name and path are valid.
@@ -96,20 +95,14 @@ fn creating_directories_is_prevented(server: TestServer) -> Result<(), Error> {
fn creating_directories_through_symlinks_is_prevented(
#[with(&["--upload-files", "--mkdir", "--no-symlinks"])] server: TestServer,
) -> Result<(), Error> {
- // Make symlinks
- let symlink_directory_str = "symlink";
- let symlink_directory = server.path().join(symlink_directory_str);
- let symlinked_direcotry = server.path().join(DIRECTORIES[0]);
- symlink_dir(symlinked_direcotry, symlink_directory).unwrap();
-
// Before attempting to create, ensure the symlink does not exist.
let body = reqwest::blocking::get(server.url())?.error_for_status()?;
let parsed = Document::from_read(body)?;
- assert!(parsed.find(Text).all(|x| x.text() != symlink_directory_str));
+ assert!(parsed.find(Text).all(|x| x.text() != DIRECTORY_SYMLINK));
// Attempt to perform directory creation.
let form = multipart::Form::new();
- let part = multipart::Part::text(symlink_directory_str);
+ let part = multipart::Part::text(DIRECTORY_SYMLINK);
let form = form.part("mkdir", part);
// This should fail
@@ -117,7 +110,7 @@ fn creating_directories_through_symlinks_is_prevented(
.post(
server
.url()
- .join(format!("/upload?path=/{symlink_directory_str}").as_str())?
+ .join(format!("/upload?path=/{DIRECTORY_SYMLINK}").as_str())?
)
.multipart(form)
.send()?
diff --git a/tests/fixtures/mod.rs b/tests/fixtures/mod.rs
index 96b8002..f2869b7 100644
--- a/tests/fixtures/mod.rs
+++ b/tests/fixtures/mod.rs
@@ -1,18 +1,18 @@
+use std::process::{Child, Command, Stdio};
+use std::thread::sleep;
+use std::time::{Duration, Instant};
+
use assert_cmd::prelude::*;
use assert_fs::fixture::TempDir;
use assert_fs::prelude::*;
use port_check::free_local_port;
use reqwest::Url;
use rstest::fixture;
-use std::process::{Child, Command, Stdio};
-use std::thread::sleep;
-use std::time::{Duration, Instant};
/// Error type used by tests
pub type Error = Box<dyn std::error::Error>;
/// File names for testing purpose
-#[allow(dead_code)]
pub static FILES: &[&str] = &[
"test.txt",
"test.html",
@@ -31,25 +31,29 @@ pub static FILES: &[&str] = &[
];
/// Hidden files for testing purpose
-#[allow(dead_code)]
pub static HIDDEN_FILES: &[&str] = &[".hidden_file1", ".hidden_file2"];
/// Directory names for testing purpose
-#[allow(dead_code)]
pub static DIRECTORIES: &[&str] = &["dira/", "dirb/", "dirc/"];
/// Hidden directories for testing purpose
-#[allow(dead_code)]
pub static HIDDEN_DIRECTORIES: &[&str] = &[".hidden_dir1/", ".hidden_dir2/"];
/// Name of a deeply nested file
-#[allow(dead_code)]
pub static DEEPLY_NESTED_FILE: &str = "very/deeply/nested/test.rs";
+/// Name of a symlink pointing to a directory
+pub static DIRECTORY_SYMLINK: &str = "dir_symlink/";
+
+/// Name of a symlink pointing to a file
+pub static FILE_SYMLINK: &str = "file_symlink";
+
+/// Name of a symlink pointing to a path that doesn't exist
+pub static BROKEN_SYMLINK: &str = "broken_symlink";
+
/// Test fixture which creates a temporary directory with a few files and directories inside.
/// The directories also contain files.
#[fixture]
-#[allow(dead_code)]
pub fn tmpdir() -> TempDir {
let tmpdir = assert_fs::TempDir::new().expect("Couldn't create a temp dir for tests");
let mut files = FILES.to_vec();
@@ -76,12 +80,27 @@ pub fn tmpdir() -> TempDir {
.child(DEEPLY_NESTED_FILE)
.write_str("File in a deeply nested directory.")
.expect("Couldn't write to file");
+
+ tmpdir
+ .child(DIRECTORY_SYMLINK.strip_suffix("/").unwrap())
+ .symlink_to_dir(DIRECTORIES[0].strip_suffix("/").unwrap())
+ .expect("Couldn't create symlink to dir");
+
+ tmpdir
+ .child(FILE_SYMLINK)
+ .symlink_to_file(FILES[0])
+ .expect("Couldn't create symlink to file");
+
+ tmpdir
+ .child(BROKEN_SYMLINK)
+ .symlink_to_file("broken_symlink")
+ .expect("Couldn't create broken symlink");
+
tmpdir
}
/// Get a free port.
#[fixture]
-#[allow(dead_code)]
pub fn port() -> u16 {
free_local_port().expect("Couldn't find a free local port")
}
@@ -89,7 +108,6 @@ pub fn port() -> u16 {
/// Run miniserve as a server; Start with a temporary directory, a free port and some
/// optional arguments then wait for a while for the server setup to complete.
#[fixture]
-#[allow(dead_code)]
pub fn server<I>(#[default(&[] as &[&str])] args: I) -> TestServer
where
I: IntoIterator + Clone,
@@ -103,35 +121,8 @@ where
.arg("-p")
.arg(port.to_string())
.args(args.clone())
- .stdout(Stdio::null())
- .spawn()
- .expect("Couldn't run test binary");
- let is_tls = args
- .into_iter()
- .any(|x| x.as_ref().to_str().unwrap().contains("tls"));
-
- wait_for_port(port);
- TestServer::new(port, tmpdir, child, is_tls)
-}
-
-/// Same as `server()` but ignore stderr
-#[fixture]
-#[allow(dead_code)]
-pub fn server_no_stderr<I>(#[default(&[] as &[&str])] args: I) -> TestServer
-where
- I: IntoIterator + Clone,
- I::Item: AsRef<std::ffi::OsStr>,
-{
- let port = port();
- let tmpdir = tmpdir();
- let child = Command::cargo_bin("miniserve")
- .expect("Couldn't find test binary")
- .arg(tmpdir.path())
- .arg("-p")
- .arg(port.to_string())
- .args(args.clone())
- .stdout(Stdio::null())
- .stderr(Stdio::null())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
.spawn()
.expect("Couldn't run test binary");
let is_tls = args
@@ -155,7 +146,6 @@ fn wait_for_port(port: u16) {
}
}
-#[allow(dead_code)]
pub struct TestServer {
port: u16,
tmpdir: TempDir,
diff --git a/tests/header.rs b/tests/header.rs
index 4ac38b1..443f2ba 100644
--- a/tests/header.rs
+++ b/tests/header.rs
@@ -1,13 +1,13 @@
+use rstest::rstest;
+
mod fixtures;
-use fixtures::{server, Error};
-use rstest::rstest;
+use crate::fixtures::{server, Error};
-#[rstest(headers,
- case(vec!["x-info: 123".to_string()]),
- case(vec!["x-info1: 123".to_string(), "x-info2: 345".to_string()])
-)]
-fn custom_header_set(headers: Vec<String>) -> Result<(), Error> {
+#[rstest]
+#[case(vec!["x-info: 123".to_string()])]
+#[case(vec!["x-info1: 123".to_string(), "x-info2: 345".to_string()])]
+fn custom_header_set(#[case] headers: Vec<String>) -> Result<(), Error> {
let server = server(headers.iter().flat_map(|h| vec!["--header", h]));
let resp = reqwest::blocking::get(server.url())?;
diff --git a/tests/navigation.rs b/tests/navigation.rs
index 8c21beb..1bd8e81 100644
--- a/tests/navigation.rs
+++ b/tests/navigation.rs
@@ -1,24 +1,26 @@
-mod fixtures;
-mod utils;
+use std::process::{Command, Stdio};
-use fixtures::{server, Error, TestServer, DEEPLY_NESTED_FILE, DIRECTORIES};
use pretty_assertions::{assert_eq, assert_ne};
use rstest::rstest;
use select::document::Document;
-use std::process::{Command, Stdio};
-use utils::get_link_from_text;
-use utils::get_link_hrefs_with_prefix;
-
-#[rstest(
- input,
- expected,
- case("", "/"),
- case("/dira", "/dira/"),
- case("/dirb/", "/dirb/"),
- case("/very/deeply/nested", "/very/deeply/nested/")
-)]
+
+mod fixtures;
+mod utils;
+
+use crate::fixtures::{server, Error, TestServer, DEEPLY_NESTED_FILE, DIRECTORIES};
+use crate::utils::{get_link_from_text, get_link_hrefs_with_prefix};
+
+#[rstest]
+#[case("", "/")]
+#[case("/dira", "/dira/")]
+#[case("/dirb/", "/dirb/")]
+#[case("/very/deeply/nested", "/very/deeply/nested/")]
/// Directories get a trailing slash.
-fn index_gets_trailing_slash(server: TestServer, input: &str, expected: &str) -> Result<(), Error> {
+fn index_gets_trailing_slash(
+ server: TestServer,
+ #[case] input: &str,
+ #[case] expected: &str,
+) -> Result<(), Error> {
let resp = reqwest::blocking::get(server.url().join(input)?)?;
assert!(resp.url().as_str().ends_with(expected));
@@ -52,11 +54,11 @@ fn can_navigate_into_dirs_and_back(server: TestServer) -> Result<(), Error> {
let initial_parsed = Document::from_read(initial_body)?;
for &directory in DIRECTORIES {
let dir_elem = get_link_from_text(&initial_parsed, directory).expect("Dir not found.");
- let body = reqwest::blocking::get(&format!("{base_url}{dir_elem}"))?.error_for_status()?;
+ let body = reqwest::blocking::get(format!("{base_url}{dir_elem}"))?.error_for_status()?;
let parsed = Document::from_read(body)?;
let back_link =
get_link_from_text(&parsed, "Parent directory").expect("Back link not found.");
- let resp = reqwest::blocking::get(&format!("{base_url}{back_link}"))?;
+ let resp = reqwest::blocking::get(format!("{base_url}{back_link}"))?;
// Now check that we can actually get back to the original location we came from using the
// link.
diff --git a/tests/qrcode.rs b/tests/qrcode.rs
index 48fa8c8..6951d7a 100644
--- a/tests/qrcode.rs
+++ b/tests/qrcode.rs
@@ -1,14 +1,15 @@
-mod fixtures;
+use std::process::{Command, Stdio};
+use std::thread::sleep;
+use std::time::Duration;
use assert_cmd::prelude::CommandCargoExt;
use assert_fs::TempDir;
-use fixtures::{port, server, tmpdir, Error, TestServer};
use rstest::rstest;
-use select::document::Document;
-use select::predicate::Attr;
-use std::process::{Command, Stdio};
-use std::thread::sleep;
-use std::time::Duration;
+use select::{document::Document, predicate::Attr};
+
+mod fixtures;
+
+use crate::fixtures::{port, server, tmpdir, Error, TestServer};
#[rstest]
fn webpage_hides_qrcode_when_disabled(server: TestServer) -> Result<(), Error> {
diff --git a/tests/raw.rs b/tests/raw.rs
index 95100d2..051c3e3 100644
--- a/tests/raw.rs
+++ b/tests/raw.rs
@@ -1,30 +1,27 @@
-mod fixtures;
-mod utils;
-
-use crate::fixtures::TestServer;
-use fixtures::{server, Error};
use pretty_assertions::assert_eq;
use reqwest::blocking::Client;
use rstest::rstest;
-use select::document::Document;
-use select::predicate::Class;
-use select::predicate::Name;
+use select::{
+ document::Document,
+ predicate::{Class, Name},
+};
+
+mod fixtures;
+
+use crate::fixtures::{server, Error, TestServer};
/// The footer displays the correct wget command to download the folder recursively
// This test can't test all aspects of the wget footer,
// a more detailed unit test is available
-#[rstest(
- depth,
- dir,
- case(0, ""),
- case(1, "dira/"),
- case(2, "very/deeply/"),
- case(3, "very/deeply/nested/")
-)]
+#[rstest]
+#[case(0, "")]
+#[case(1, "dira/")]
+#[case(2, "very/deeply/")]
+#[case(3, "very/deeply/nested/")]
fn ui_displays_wget_element(
- depth: u8,
- dir: &str,
- #[with(&["-W"])] server: TestServer,
+ #[case] depth: u8,
+ #[case] dir: &str,
+ #[with(&["--show-wget-footer"])] server: TestServer,
) -> Result<(), Error> {
let client = Client::new();
@@ -62,16 +59,14 @@ fn ui_displays_wget_element(
}
/// All hrefs in raw mode are links to directories or files & directories end with ?raw=true
-#[rstest(
- dir,
- case(""),
- case("very/"),
- case("very/deeply/"),
- case("very/deeply/nested/")
-)]
+#[rstest]
+#[case("")]
+#[case("very/")]
+#[case("very/deeply/")]
+#[case("very/deeply/nested/")]
fn raw_mode_links_to_directories_end_with_raw_true(
- dir: &str,
- #[with(&["-W"])] server: TestServer,
+ #[case] dir: &str,
+ #[with(&["--show-wget-footer"])] server: TestServer,
) -> Result<(), Error> {
fn verify_a_tags(parsed: Document) {
// Ensure all links end with ?raw=true or are files
diff --git a/tests/readme.rs b/tests/readme.rs
index c8138b4..cafff3d 100644
--- a/tests/readme.rs
+++ b/tests/readme.rs
@@ -1,12 +1,14 @@
-mod fixtures;
+use std::fs::{remove_file, File};
+use std::io::Write;
+use std::path::PathBuf;
-use fixtures::{server, Error, TestServer, DIRECTORIES, FILES};
use rstest::rstest;
use select::predicate::Attr;
use select::{document::Document, node::Node};
-use std::fs::{remove_file, File};
-use std::io::Write;
-use std::path::PathBuf;
+
+mod fixtures;
+
+use fixtures::{server, Error, TestServer, DIRECTORIES, FILES};
fn write_readme_contents(path: PathBuf, filename: &str) -> PathBuf {
let readme_path = path.join(filename);
@@ -67,17 +69,15 @@ fn no_readme_contents(server: TestServer) -> Result<(), Error> {
}
/// Show readme contents when told to if there is a readme file in the root
-#[rstest(
- readme_name,
- case("Readme.md"),
- case("readme.md"),
- case("README.md"),
- case("README.MD"),
- case("ReAdMe.Md")
-)]
+#[rstest]
+#[case("Readme.md")]
+#[case("readme.md")]
+#[case("README.md")]
+#[case("README.MD")]
+#[case("ReAdMe.Md")]
fn show_root_readme_contents(
#[with(&["--readme"])] server: TestServer,
- readme_name: &str,
+ #[case] readme_name: &str,
) -> Result<(), Error> {
let readme_path = write_readme_contents(server.path().to_path_buf(), readme_name);
let body = reqwest::blocking::get(server.url())?.error_for_status()?;
@@ -94,21 +94,19 @@ fn show_root_readme_contents(
}
/// Show readme contents when told to if there is a readme file in any of the directories
-#[rstest(
- readme_name,
- case("Readme.md"),
- case("readme.md"),
- case("README.md"),
- case("README.MD"),
- case("ReAdMe.Md"),
- case("Readme.txt"),
- case("README.txt"),
- case("README"),
- case("ReAdMe")
-)]
+#[rstest]
+#[case("Readme.md")]
+#[case("readme.md")]
+#[case("README.md")]
+#[case("README.MD")]
+#[case("ReAdMe.Md")]
+#[case("Readme.txt")]
+#[case("README.txt")]
+#[case("README")]
+#[case("ReAdMe")]
fn show_nested_readme_contents(
#[with(&["--readme"])] server: TestServer,
- readme_name: &str,
+ #[case] readme_name: &str,
) -> Result<(), Error> {
for dir in DIRECTORIES {
let readme_path = write_readme_contents(server.path().join(dir), readme_name);
diff --git a/tests/serve_request.rs b/tests/serve_request.rs
index b7359c3..f840efd 100644
--- a/tests/serve_request.rs
+++ b/tests/serve_request.rs
@@ -1,23 +1,21 @@
-mod fixtures;
+use std::process::{Command, Stdio};
+use std::thread::sleep;
+use std::time::Duration;
use assert_cmd::prelude::*;
use assert_fs::fixture::TempDir;
-use fixtures::{
- port, server, server_no_stderr, tmpdir, Error, TestServer, DIRECTORIES, FILES,
- HIDDEN_DIRECTORIES, HIDDEN_FILES,
-};
-use http::StatusCode;
+use fixtures::BROKEN_SYMLINK;
use regex::Regex;
+use reqwest::StatusCode;
use rstest::rstest;
use select::{document::Document, node::Node, predicate::Attr};
-use std::process::{Command, Stdio};
-use std::thread::sleep;
-use std::time::Duration;
-#[cfg(unix)]
-use std::os::unix::fs::{symlink as symlink_dir, symlink as symlink_file};
-#[cfg(windows)]
-use std::os::windows::fs::{symlink_dir, symlink_file};
+mod fixtures;
+
+use crate::fixtures::{
+ port, server, tmpdir, Error, TestServer, DIRECTORIES, DIRECTORY_SYMLINK, FILES, FILE_SYMLINK,
+ HIDDEN_DIRECTORIES, HIDDEN_FILES,
+};
#[rstest]
fn serves_requests_with_no_options(tmpdir: TempDir) -> Result<(), Error> {
@@ -131,23 +129,10 @@ fn serves_requests_symlinks(
#[case] show_symlink_info: bool,
#[case] server: TestServer,
) -> Result<(), Error> {
- let file = "symlink-file.html";
- let dir = "symlink-dir/";
- let broken = "symlink broken";
-
- // Set up some basic symlinks:
- // to dir, to file, to non-existent location
- let orig = DIRECTORIES[0].strip_suffix('/').unwrap();
- let link = server.path().join(dir.strip_suffix('/').unwrap());
- symlink_dir(orig, link).expect("Couldn't create symlink");
- symlink_file(FILES[0], server.path().join(file)).expect("Couldn't create symlink");
- symlink_file("should-not-exist.xxx", server.path().join(broken))
- .expect("Couldn't create symlink");
-
let body = reqwest::blocking::get(server.url())?.error_for_status()?;
let parsed = Document::from_read(body)?;
- for &entry in &[file, dir] {
+ for &entry in &[FILE_SYMLINK, DIRECTORY_SYMLINK] {
let status = reqwest::blocking::get(server.url().join(entry)?)?.status();
// We expect a 404 here for when `no_symlinks` is `true`.
if no_symlinks {
@@ -161,6 +146,7 @@ fn serves_requests_symlinks(
.next();
// If symlinks are deactivated, none should be shown in the listing.
+ dbg!(&node);
assert_eq!(node.is_none(), no_symlinks);
if node.is_some() && show_symlink_info {
assert_eq!(node.unwrap().attr("class").unwrap(), "symlink");
@@ -186,7 +172,10 @@ fn serves_requests_symlinks(
assert_eq!(node.unwrap().attr("class").unwrap(), "file");
}
}
- assert!(parsed.find(|x: &Node| x.text() == broken).next().is_none());
+ assert!(parsed
+ .find(|x: &Node| x.text() == BROKEN_SYMLINK)
+ .next()
+ .is_none());
Ok(())
}
@@ -240,8 +229,8 @@ fn serves_requests_custom_index_notice(tmpdir: TempDir, port: u16) -> Result<(),
}
#[rstest]
-#[case(server_no_stderr(&["--index", FILES[0]]))]
-#[case(server_no_stderr(&["--index", "does-not-exist.html"]))]
+#[case(server(&["--index", FILES[0]]))]
+#[case(server(&["--index", "does-not-exist.html"]))]
fn index_fallback_to_listing(#[case] server: TestServer) -> Result<(), Error> {
// If index file is not found, show directory listing instead both cases should return `Ok`
reqwest::blocking::get(server.url())?.error_for_status()?;
@@ -250,9 +239,9 @@ fn index_fallback_to_listing(#[case] server: TestServer) -> Result<(), Error> {
}
#[rstest]
-#[case(server_no_stderr(&["--spa", "--index", FILES[0]]), "/")]
-#[case(server_no_stderr(&["--spa", "--index", FILES[0]]), "/spa-route")]
-#[case(server_no_stderr(&["--index", FILES[0]]), "/")]
+#[case(server(&["--spa", "--index", FILES[0]]), "/")]
+#[case(server(&["--spa", "--index", FILES[0]]), "/spa-route")]
+#[case(server(&["--index", FILES[0]]), "/")]
fn serve_index_instead_of_404_in_spa_mode(
#[case] server: TestServer,
#[case] url: &str,
@@ -268,9 +257,9 @@ fn serve_index_instead_of_404_in_spa_mode(
}
#[rstest]
-#[case(server_no_stderr(&["--pretty-urls", "--index", FILES[1]]), "/")]
-#[case(server_no_stderr(&["--pretty-urls", "--index", FILES[1]]), "test.html")]
-#[case(server_no_stderr(&["--pretty-urls", "--index", FILES[1]]), "test")]
+#[case(server(&["--pretty-urls", "--index", FILES[1]]), "/")]
+#[case(server(&["--pretty-urls", "--index", FILES[1]]), "test.html")]
+#[case(server(&["--pretty-urls", "--index", FILES[1]]), "test")]
fn serve_file_instead_of_404_in_pretty_urls_mode(
#[case] server: TestServer,
#[case] url: &str,
@@ -301,9 +290,9 @@ fn serves_requests_with_route_prefix(#[case] server: TestServer) -> Result<(), E
}
#[rstest]
-#[case(server_no_stderr(&[] as &[&str]), "/[a-f0-9]+")]
-#[case(server_no_stderr(&["--random-route"]), "/[a-f0-9]+")]
-#[case(server_no_stderr(&["--route-prefix", "foobar"]), "/foobar/[a-f0-9]+")]
+#[case(server(&[] as &[&str]), "/__miniserve_internal/[a-z.]+")]
+#[case(server(&["--random-route"]), "/__miniserve_internal/[a-z.]+")]
+#[case(server(&["--route-prefix", "foobar"]), "/foobar/__miniserve_internal/[a-z.]+")]
fn serves_requests_static_file_check(
#[case] server: TestServer,
#[case] static_file_pattern: String,
diff --git a/tests/tls.rs b/tests/tls.rs
index 7750c82..9cc441c 100644
--- a/tests/tls.rs
+++ b/tests/tls.rs
@@ -1,12 +1,13 @@
-mod fixtures;
-
use assert_cmd::Command;
-use fixtures::{server, Error, TestServer, FILES};
use predicates::str::contains;
use reqwest::blocking::ClientBuilder;
use rstest::rstest;
use select::{document::Document, node::Node};
+mod fixtures;
+
+use crate::fixtures::{server, Error, TestServer, FILES};
+
/// Can start the server with TLS and receive encrypted responses.
#[rstest]
#[case(server(&[
diff --git a/tests/upload_files.rs b/tests/upload_files.rs
index 77a9dc3..5fdf2cf 100644
--- a/tests/upload_files.rs
+++ b/tests/upload_files.rs
@@ -1,13 +1,15 @@
-mod fixtures;
+use std::fs::create_dir_all;
+use std::path::Path;
use assert_fs::fixture::TempDir;
-use fixtures::{server, server_no_stderr, tmpdir, Error, TestServer};
use reqwest::blocking::{multipart, Client};
use rstest::rstest;
use select::document::Document;
use select::predicate::{Attr, Text};
-use std::fs::create_dir_all;
-use std::path::Path;
+
+mod fixtures;
+
+use crate::fixtures::{server, tmpdir, Error, TestServer};
#[rstest]
fn uploading_files_works(#[with(&["-u"])] server: TestServer) -> Result<(), Error> {
@@ -85,8 +87,8 @@ fn uploading_files_is_prevented(server: TestServer) -> Result<(), Error> {
/// This test runs the server with --allowed-upload-dir argument and
/// checks that file upload to a different directory is actually prevented.
#[rstest]
-#[case(server_no_stderr(&["-u", "someDir"]))]
-#[case(server_no_stderr(&["-u", "someDir/some_sub_dir"]))]
+#[case(server(&["-u", "someDir"]))]
+#[case(server(&["-u", "someDir/some_sub_dir"]))]
fn uploading_files_is_restricted(#[case] server: TestServer) -> Result<(), Error> {
let test_file_name = "uploaded test file.txt";
@@ -219,7 +221,7 @@ fn prevent_path_traversal_attacks(
/// See https://github.com/svenstaro/miniserve/issues/466
#[rstest]
#[case(server(&["-u"]), true)]
-#[case(server_no_stderr(&["-u", "--no-symlinks"]), false)]
+#[case(server(&["-u", "--no-symlinks"]), false)]
fn upload_to_symlink_directory(
#[case] server: TestServer,
#[case] ok: bool,
diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs
index baffc29..792b070 100644
--- a/tests/utils/mod.rs
+++ b/tests/utils/mod.rs
@@ -1,5 +1,3 @@
-#![allow(dead_code)]
-
use select::document::Document;
use select::node::Node;
use select::predicate::Name;
@@ -26,5 +24,5 @@ pub fn get_link_hrefs_with_prefix(document: &Document, prefix: &str) -> Vec<Stri
}
}
- return vec;
+ vec
}
diff --git a/tests/webdav.rs b/tests/webdav.rs
new file mode 100644
index 0000000..09d04e9
--- /dev/null
+++ b/tests/webdav.rs
@@ -0,0 +1,150 @@
+use std::process::Command;
+
+use assert_cmd::prelude::*;
+use assert_fs::TempDir;
+use predicates::str::contains;
+use reqwest::{blocking::Client, Method};
+use reqwest_dav::{
+ list_cmd::{ListEntity, ListFile, ListFolder},
+ ClientBuilder as DavClientBuilder,
+};
+use rstest::rstest;
+
+mod fixtures;
+
+use crate::fixtures::{
+ server, tmpdir, Error, TestServer, DIRECTORIES, DIRECTORY_SYMLINK, FILES, FILE_SYMLINK,
+ HIDDEN_DIRECTORIES, HIDDEN_FILES,
+};
+
+#[rstest]
+#[case(server(&["--enable-webdav"]), true)]
+#[case(server(&[] as &[&str]), false)]
+fn webdav_flag_works(
+ #[case] server: TestServer,
+ #[case] should_respond: bool,
+) -> Result<(), Error> {
+ let client = Client::new();
+ let response = client
+ .request(Method::from_bytes(b"PROPFIND").unwrap(), server.url())
+ .header("Depth", "1")
+ .send()?;
+
+ assert_eq!(should_respond, response.status().is_success());
+
+ Ok(())
+}
+
+#[rstest]
+fn webdav_advertised_in_options(
+ #[with(&["--enable-webdav"])] server: TestServer,
+) -> Result<(), Error> {
+ let response = Client::new()
+ .request(Method::OPTIONS, server.url())
+ .send()?
+ .error_for_status()?;
+
+ let headers = response.headers();
+ let allow = headers.get("allow").unwrap().to_str()?;
+
+ assert!(allow.contains("OPTIONS") && allow.contains("PROPFIND"));
+ assert!(headers.get("dav").is_some());
+
+ Ok(())
+}
+
+fn list_webdav(url: url::Url, path: &str) -> Result<Vec<ListEntity>, reqwest_dav::Error> {
+ let client = DavClientBuilder::new().set_host(url.to_string()).build()?;
+
+ let rt = tokio::runtime::Runtime::new().unwrap();
+
+ rt.block_on(async { client.list(path, reqwest_dav::Depth::Number(1)).await })
+}
+
+#[rstest]
+#[case(server(&["--enable-webdav"]), false)]
+#[case(server(&["--enable-webdav", "--hidden"]), true)]
+fn webdav_respects_hidden_flag(
+ #[case] server: TestServer,
+ #[case] hidden_should_show: bool,
+) -> Result<(), Error> {
+ let list = list_webdav(server.url(), "/")?;
+
+ assert_eq!(
+ hidden_should_show,
+ list.iter().any(|el|
+ matches!(el, ListEntity::File(ListFile { href, .. }) if href.contains(HIDDEN_FILES[0]))
+ )
+ );
+
+ assert_eq!(
+ hidden_should_show,
+ list.iter().any(|el|
+ matches!(el, ListEntity::Folder(ListFolder { href, .. }) if href.contains(HIDDEN_DIRECTORIES[0]))
+ )
+ );
+
+ Ok(())
+}
+
+#[rstest]
+#[case(server(&["--enable-webdav"]), true)]
+#[should_panic]
+#[case(server(&["--enable-webdav", "--no-symlinks"]), false)]
+fn webdav_respects_no_symlink_flag(#[case] server: TestServer, #[case] symlinks_should_show: bool) {
+ let list = list_webdav(server.url(), "/").unwrap();
+
+ assert_eq!(
+ symlinks_should_show,
+ list.iter().any(|el|
+ matches!(el, ListEntity::File(ListFile { href, .. }) if href.contains(FILE_SYMLINK))
+ ),
+ );
+
+ assert_eq!(
+ symlinks_should_show,
+ list.iter().any(|el|
+ matches!(el, ListEntity::Folder(ListFolder { href, .. }) if href.contains(DIRECTORY_SYMLINK))
+ ),
+ );
+
+ let list_linked = list_webdav(server.url(), &format!("/{}", DIRECTORY_SYMLINK));
+
+ assert_eq!(symlinks_should_show, list_linked.is_ok());
+}
+
+#[rstest]
+fn webdav_works_with_route_prefix(
+ #[with(&["--enable-webdav", "--route-prefix", "test-prefix"])] server: TestServer,
+) -> Result<(), Error> {
+ let prefixed_list = list_webdav(server.url().join("test-prefix")?, "/")?;
+
+ assert!(
+ prefixed_list.iter().any(|el|
+ matches!(el, ListEntity::Folder(ListFolder { href, .. }) if href.contains(DIRECTORIES[0]))
+ )
+ );
+
+ let root_list = list_webdav(server.url(), "/");
+
+ assert!(root_list.is_err());
+
+ Ok(())
+}
+
+// timeout is used in case the binary does not exit as expected and starts waiting for requests
+#[rstest]
+#[timeout(std::time::Duration::from_secs(1))]
+fn webdav_single_file_refuses_starting(tmpdir: TempDir) {
+ Command::cargo_bin("miniserve")
+ .unwrap()
+ .current_dir(tmpdir.path())
+ .arg(FILES[0])
+ .arg("--enable-webdav")
+ .assert()
+ .failure()
+ .stderr(contains(format!(
+ "Error: The --enable-webdav option was provided, but the serve path '{}' is a file",
+ FILES[0]
+ )));
+}