diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-03-08 00:56:42 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-04-03 10:18:40 -0300 |
| commit | 5e1535b7362c0f4cf7a6dbba3f85ce84b11a19c7 (patch) | |
| tree | 266919638c61509d1c17f8fa42d74afe536655ac | |
| parent | 3960910e5c129d8caf38bdad6993a006e3563711 (diff) | |
| download | mullvadvpn-5e1535b7362c0f4cf7a6dbba3f85ce84b11a19c7.tar.xz mullvadvpn-5e1535b7362c0f4cf7a6dbba3f85ce84b11a19c7.zip | |
Test RPC address file creation on daemon start-up
| -rw-r--r-- | Cargo.lock | 2 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 2 | ||||
| -rw-r--r-- | mullvad-daemon/tests/common/mod.rs | 112 | ||||
| -rw-r--r-- | mullvad-daemon/tests/startup.rs | 59 |
4 files changed, 175 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock index 56e31e40bd..4f4f3b0431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -633,6 +633,7 @@ dependencies = [ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "duct 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "fern 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -645,6 +646,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mullvad-rpc 0.1.0", "mullvad-types 0.1.0", + "os_pipe 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml index f8b16e94e4..3ff37cbaf9 100644 --- a/mullvad-daemon/Cargo.toml +++ b/mullvad-daemon/Cargo.toml @@ -42,3 +42,5 @@ ctrlc = "3.0" [dev-dependencies] assert_matches = "1.0" +duct = "0.10" +os_pipe = "0.6" diff --git a/mullvad-daemon/tests/common/mod.rs b/mullvad-daemon/tests/common/mod.rs new file mode 100644 index 0000000000..45b48c3db7 --- /dev/null +++ b/mullvad-daemon/tests/common/mod.rs @@ -0,0 +1,112 @@ +#![allow(dead_code)] + +use std::fs::File; +use std::io::{BufRead, BufReader, Write}; +use std::path::{Path, PathBuf}; +use std::sync::{mpsc, Arc, Mutex}; +use std::thread; +use std::time::Duration; + +use duct; +use os_pipe::{pipe, PipeReader}; + +pub use self::platform_specific::*; + +#[cfg(unix)] +mod platform_specific { + use super::*; + + pub static DAEMON_EXECUTABLE_PATH: &str = "../target/debug/mullvad-daemon"; + + pub fn rpc_file_path() -> PathBuf { + Path::new("/tmp/.mullvad_rpc_address").to_path_buf() + } +} + +#[cfg(not(unix))] +mod platform_specific { + use super::*; + + pub static DAEMON_EXECUTABLE_PATH: &str = r"..\target\debug\mullvad-daemon.exe"; + + pub fn rpc_file_path() -> PathBuf { + ::std::env::temp_dir().join(".mullvad_rpc_address") + } +} + +fn prepare_relay_list<T: AsRef<Path>>(path: T) { + let path = path.as_ref(); + + if !path.exists() { + File::create(path) + .expect("failed to create relay list file") + .write_all(b"{ \"countries\": [] }") + .expect("failed to write relay list"); + } +} + +pub struct DaemonRunner { + process: duct::Handle, + output: Arc<Mutex<BufReader<PipeReader>>>, +} + +impl DaemonRunner { + pub fn spawn() -> Self { + prepare_relay_list("../dist-assets/relays.json"); + + let (reader, writer) = pipe().expect("failed to open pipe to connect to daemon"); + let process = cmd!( + DAEMON_EXECUTABLE_PATH, + "-v", + "--resource-dir", + "dist-assets" + ).dir("..") + .stderr_to_stdout() + .stdout_handle(writer) + .start() + .expect("failed to start daemon"); + + DaemonRunner { + process, + output: Arc::new(Mutex::new(BufReader::new(reader))), + } + } + + pub fn assert_output(&mut self, pattern: &'static str, timeout: Duration) { + let (tx, rx) = mpsc::channel(); + let stdout = self.output.clone(); + + thread::spawn(move || { + Self::wait_for_output(stdout, pattern); + tx.send(()).expect("failed to report search result"); + }); + + rx.recv_timeout(timeout) + .expect(&format!("failed to search for {:?}", pattern)); + } + + fn wait_for_output(output: Arc<Mutex<BufReader<PipeReader>>>, pattern: &str) { + let mut output = output + .lock() + .expect("another thread panicked while holding a lock to the process output"); + + let mut line = String::new(); + + while !line.contains(pattern) { + line.clear(); + output + .read_line(&mut line) + .expect("failed to read line from daemon stdout"); + } + } +} + +#[cfg(unix)] +impl Drop for DaemonRunner { + fn drop(&mut self) { + use duct::unix::HandleExt; + use libc; + + let _ = self.process.send_signal(libc::SIGTERM); + } +} diff --git a/mullvad-daemon/tests/startup.rs b/mullvad-daemon/tests/startup.rs new file mode 100644 index 0000000000..2f93bd0f99 --- /dev/null +++ b/mullvad-daemon/tests/startup.rs @@ -0,0 +1,59 @@ +#[macro_use] +extern crate duct; +#[cfg(unix)] +extern crate libc; +extern crate os_pipe; + +mod common; + +use std::fs::{self, Metadata}; +use std::io; +use std::time::Duration; + +use common::{rpc_file_path, DaemonRunner}; + +use platform_specific::*; + +#[test] +fn rpc_info_file_permissions() { + let rpc_file = rpc_file_path(); + + if let Err(error) = fs::remove_file(&rpc_file) { + if error.kind() != io::ErrorKind::NotFound { + panic!("failed to remove existing RPC address file"); + } + } + + assert!(!rpc_file.exists()); + + let mut daemon = DaemonRunner::spawn(); + + daemon.assert_output("Wrote RPC connection info to", Duration::from_secs(10)); + + assert!(rpc_file.exists()); + + ensure_only_admin_can_write( + fs::metadata(&rpc_file).expect("failed to read RPC address file metadata"), + ); +} + +#[cfg(unix)] +mod platform_specific { + use super::*; + use std::os::unix::fs::MetadataExt; + + pub fn ensure_only_admin_can_write(metadata: Metadata) { + let process_uid = unsafe { libc::getuid() }; + assert_eq!(metadata.uid(), process_uid); + assert_eq!(metadata.mode() & 0o022, 0); + } +} + +#[cfg(not(unix))] +mod platform_specific { + use super::*; + + pub fn ensure_only_admin_can_write(_metadata: Metadata) { + // TODO: Test when correctly implemented on Windows + } +} |
