summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-03-08 00:56:42 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-04-03 10:18:40 -0300
commit5e1535b7362c0f4cf7a6dbba3f85ce84b11a19c7 (patch)
tree266919638c61509d1c17f8fa42d74afe536655ac
parent3960910e5c129d8caf38bdad6993a006e3563711 (diff)
downloadmullvadvpn-5e1535b7362c0f4cf7a6dbba3f85ce84b11a19c7.tar.xz
mullvadvpn-5e1535b7362c0f4cf7a6dbba3f85ce84b11a19c7.zip
Test RPC address file creation on daemon start-up
-rw-r--r--Cargo.lock2
-rw-r--r--mullvad-daemon/Cargo.toml2
-rw-r--r--mullvad-daemon/tests/common/mod.rs112
-rw-r--r--mullvad-daemon/tests/startup.rs59
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
+ }
+}