From dfd0ecf931b68ea373be1e4e785421d48ca6fed5 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 24 Apr 2021 07:28:55 +0300 Subject: tests: Refactor! Remove duplicate code responsible for the initial setup and teardown of the test binary. This introduces `TestServer` as a resource manager for a running miniserve binary, which can be created with the fixtures `server()` and `server_no_stderr()` It also provides convenience function for handling server url. --- tests/fixtures/mod.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'tests/fixtures') diff --git a/tests/fixtures/mod.rs b/tests/fixtures/mod.rs index 1cf6c59..f143413 100644 --- a/tests/fixtures/mod.rs +++ b/tests/fixtures/mod.rs @@ -1,7 +1,12 @@ +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; /// Error type used by tests pub type Error = Box; @@ -76,3 +81,85 @@ pub fn tmpdir() -> TempDir { pub fn port() -> u16 { free_local_port().expect("Couldn't find a free local port") } + +/// 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(args=&[] as &[&str])] +#[allow(dead_code)] +pub fn server(args: impl IntoIterator) -> TestServer +where + S: AsRef, +{ + 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) + .stdout(Stdio::null()) + .spawn() + .expect("Couldn't run test binary"); + + sleep(Duration::from_secs(1)); + TestServer::new(port, tmpdir, child) +} + +/// Same as `server()` but ignore stderr +#[fixture(args=&[] as &[&str])] +#[allow(dead_code)] +pub fn server_no_stderr(args: impl IntoIterator) -> TestServer +where + S: AsRef, +{ + 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) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("Couldn't run test binary"); + + sleep(Duration::from_secs(1)); + TestServer::new(port, tmpdir, child) +} + +#[allow(dead_code)] +pub struct TestServer { + port: u16, + tmpdir: TempDir, + child: Child, +} + +#[allow(dead_code)] +impl TestServer { + pub fn new(port: u16, tmpdir: TempDir, child: Child) -> Self { + Self { + port, + tmpdir, + child, + } + } + pub fn url(&self) -> Url { + Url::parse(&format!("http://localhost:{}", self.port)).unwrap() + } + pub fn path(&self) -> &std::path::Path { + self.tmpdir.path() + } + pub fn port(&self) -> u16 { + self.port + } +} + +impl Drop for TestServer { + fn drop(&mut self) { + self.child.kill().expect("Couldn't kill test server"); + /* TODO may need .wait() ? */ + } +} -- cgit v1.2.3 From 509ee380d188dcca9f9f7ba23e07e3c426382184 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Thu, 26 Aug 2021 17:03:20 +0300 Subject: address comments --- tests/fixtures/mod.rs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'tests/fixtures') diff --git a/tests/fixtures/mod.rs b/tests/fixtures/mod.rs index f143413..a227f84 100644 --- a/tests/fixtures/mod.rs +++ b/tests/fixtures/mod.rs @@ -6,7 +6,7 @@ use reqwest::Url; use rstest::fixture; use std::process::{Child, Command, Stdio}; use std::thread::sleep; -use std::time::Duration; +use std::time::{Duration, Instant}; /// Error type used by tests pub type Error = Box; @@ -84,11 +84,12 @@ 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(args=&[] as &[&str])] +#[fixture] #[allow(dead_code)] -pub fn server(args: impl IntoIterator) -> TestServer +pub fn server(#[default(&[] as &[&str])] args: I) -> TestServer where - S: AsRef, + I: IntoIterator, + I::Item: AsRef, { let port = port(); let tmpdir = tmpdir(); @@ -102,16 +103,17 @@ where .spawn() .expect("Couldn't run test binary"); - sleep(Duration::from_secs(1)); + wait_for_port(port); TestServer::new(port, tmpdir, child) } /// Same as `server()` but ignore stderr -#[fixture(args=&[] as &[&str])] +#[fixture] #[allow(dead_code)] -pub fn server_no_stderr(args: impl IntoIterator) -> TestServer +pub fn server_no_stderr(#[default(&[] as &[&str])] args: I) -> TestServer where - S: AsRef, + I: IntoIterator, + I::Item: AsRef, { let port = port(); let tmpdir = tmpdir(); @@ -126,10 +128,23 @@ where .spawn() .expect("Couldn't run test binary"); - sleep(Duration::from_secs(1)); + wait_for_port(port); TestServer::new(port, tmpdir, child) } +/// Wait a max of 1s for the port to become available. +fn wait_for_port(port: u16) { + let start_wait = Instant::now(); + + while !port_check::is_port_reachable(format!("localhost:{}", port)) { + sleep(Duration::from_millis(100)); + + if start_wait.elapsed().as_secs() > 1 { + panic!("timeout waiting for port {}", port); + } + } +} + #[allow(dead_code)] pub struct TestServer { port: u16, @@ -160,6 +175,6 @@ impl TestServer { impl Drop for TestServer { fn drop(&mut self) { self.child.kill().expect("Couldn't kill test server"); - /* TODO may need .wait() ? */ + self.child.wait().unwrap(); } } -- cgit v1.2.3