diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-07-23 14:15:36 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2018-07-23 14:15:36 -0300 |
| commit | 5c6ad51401c835c7d5d0794d33b4bf2a2de006c7 (patch) | |
| tree | d66d9649cd535a71b73dbd71fb9287f9535ef4ec | |
| parent | 5cafc4510eb2a1998d910647d39518a5048b9e18 (diff) | |
| parent | 2114e5b5bbfb1141e88244ece771d77fafa4aa0d (diff) | |
| download | mullvadvpn-5c6ad51401c835c7d5d0794d33b4bf2a2de006c7.tar.xz mullvadvpn-5c6ad51401c835c7d5d0794d33b4bf2a2de006c7.zip | |
Merge branch 'win-integration-tests'
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rwxr-xr-x | integration-tests.sh | 19 | ||||
| -rw-r--r-- | mullvad-tests/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-tests/src/lib.rs | 110 | ||||
| -rw-r--r-- | mullvad-tests/tests/account.rs | 2 | ||||
| -rw-r--r-- | mullvad-tests/tests/connection.rs | 2 | ||||
| -rw-r--r-- | mullvad-tests/tests/startup.rs | 9 |
7 files changed, 86 insertions, 58 deletions
diff --git a/Cargo.lock b/Cargo.lock index d3586e4253..5579f9ba7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -923,7 +923,6 @@ dependencies = [ "mullvad-types 0.1.0", "notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "openvpn-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "os_pipe 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "talpid-ipc 0.1.0", "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/integration-tests.sh b/integration-tests.sh index f69614109f..4de1085972 100755 --- a/integration-tests.sh +++ b/integration-tests.sh @@ -1,8 +1,21 @@ #!/usr/bin/env bash -if [ "$UID" -ne 0 ]; then - echo "WARNING: Not running as root, some tests may fail" >&2 -fi +case "$(uname -s)" in + Linux*) + if [ "$UID" -ne 0 ]; then + echo "WARNING: Not running as root, some tests may fail" >&2 + fi + ;; + MINGW*) + if ! net session &> /dev/null; then + echo "WARNING: Not running as administrator, some tests may fail" >&2 + fi + ;; + *) + echo "ERROR: Platform $OSTYPE not supported" + exit 1 + ;; +esac MULLVAD_DIR="$(cd "$(dirname "$0")"; pwd -P)" diff --git a/mullvad-tests/Cargo.toml b/mullvad-tests/Cargo.toml index 5760be7d49..d1e9c7f44f 100644 --- a/mullvad-tests/Cargo.toml +++ b/mullvad-tests/Cargo.toml @@ -15,7 +15,6 @@ mullvad-paths = { path = "../mullvad-paths" } mullvad-types = { path = "../mullvad-types" } notify = "4.0" openvpn-plugin = { version = "0.3", features = ["serde"] } -os_pipe = "0.6" talpid-ipc = { path = "../talpid-ipc" } tempfile = "3.0" diff --git a/mullvad-tests/src/lib.rs b/mullvad-tests/src/lib.rs index a6a229c969..0e2f404258 100644 --- a/mullvad-tests/src/lib.rs +++ b/mullvad-tests/src/lib.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - #[macro_use] extern crate duct; #[cfg(unix)] @@ -8,7 +6,6 @@ extern crate mullvad_ipc_client; extern crate mullvad_paths; extern crate notify; extern crate openvpn_plugin; -extern crate os_pipe; extern crate talpid_ipc; extern crate tempfile; @@ -16,17 +13,15 @@ pub mod mock_openvpn; use std::collections::HashMap; use std::fs::{self, File}; -use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; -use std::sync::{mpsc, Arc, Mutex}; -use std::thread; +use std::sync::{mpsc, Arc}; use std::time::{Duration, Instant}; +use std::{cmp, thread}; use mullvad_ipc_client::DaemonRpcClient; use mullvad_paths::resources::API_CA_FILENAME; use notify::{RawEvent, RecommendedWatcher, RecursiveMode, Watcher}; use openvpn_plugin::types::OpenVpnPluginEvent; -use os_pipe::{pipe, PipeReader}; use talpid_ipc::WsIpcClient; use tempfile::TempDir; @@ -114,6 +109,10 @@ impl PathWatcher { assert_eq!(self.next(), Some(watch_event::CREATE)); assert_eq!(self.next(), Some(watch_event::WRITE)); + #[cfg(not(target_os = "linux"))] + self.wait_for_burst_of_events(Duration::from_secs(1)); + + #[cfg(target_os = "linux")] loop { match self.next() { Some(watch_event::WRITE) => continue, @@ -124,6 +123,37 @@ impl PathWatcher { } } } + + /// Waits for a burst of file events. + /// + /// Here, a burst of events is defined as a series of events that are emitted with less than one + /// second between each of them. + /// + /// The `max_wait_time` defines the maximum time to wait for all of the events. If a burst of + /// events is emitted that is longer than the specified time, the function will return before + /// all events have been received. + pub fn wait_for_burst_of_events(&mut self, max_wait_time: Duration) { + const EVENT_INTERVAL: Duration = Duration::from_secs(1); + + let start = Instant::now(); + let original_timeout = self.timeout; + + // We wait at most for the maximum waiting time for the first event to arrive + self.timeout = max_wait_time; + + if self.next().is_some() { + while let Some(remaining_time) = max_wait_time.checked_sub(start.elapsed()) { + // Avoid exceeding the maximum wait time + self.timeout = cmp::min(EVENT_INTERVAL, remaining_time); + + if self.next().is_none() { + break; + } + } + } + + self.timeout = original_timeout; + } } impl Iterator for PathWatcher { @@ -152,6 +182,23 @@ impl Iterator for PathWatcher { } } +pub fn wait_for_file<P: AsRef<Path>>(file_path: P) { + let file_path = file_path.as_ref(); + let mut watcher = PathWatcher::watch(&file_path).expect(&format!( + "Failed to watch file for changes: {}", + file_path.display() + )); + + if !file_path.exists() { + // No event has been emitted yet. Wait for the initial create event. + assert_eq!(watcher.next(), Some(watch_event::CREATE)); + } + + // The file was created, so at least one event was emitted. Assume the write burst has started + // and wait for a short amount of time until it completes. + watcher.wait_for_burst_of_events(Duration::from_secs(1)); +} + fn prepare_test_dirs() -> (TempDir, PathBuf, PathBuf, PathBuf) { let temp_dir = TempDir::new().expect("Failed to create temporary daemon directory"); let cache_dir = temp_dir.path().join("cache"); @@ -213,7 +260,6 @@ fn prepare_relay_list<T: AsRef<Path>>(path: T) { pub struct DaemonRunner { process: Option<duct::Handle>, - output: Arc<Mutex<BufReader<PipeReader>>>, mock_openvpn_args_file: PathBuf, rpc_address_file: PathBuf, _temp_dir: TempDir, @@ -237,15 +283,14 @@ impl DaemonRunner { mullvad_paths::get_rpc_address_path().expect("Failed to build RPC connection file path") }; - let (reader, writer) = pipe().expect("Failed to open pipe to connect to daemon"); let mut expression = cmd!(DAEMON_EXECUTABLE_PATH, "-v", "--disable-log-to-file") .dir("..") .env("MULLVAD_CACHE_DIR", cache_dir) .env("MULLVAD_RESOURCE_DIR", resource_dir) .env("MULLVAD_SETTINGS_DIR", settings_dir) .env("MOCK_OPENVPN_ARGS_FILE", mock_openvpn_args_file.clone()) - .stderr_to_stdout() - .stdout_handle(writer); + .stdout_null() + .stderr_null(); if mock_rpc_address_file { expression = expression.env( @@ -258,7 +303,6 @@ impl DaemonRunner { DaemonRunner { process: Some(process), - output: Arc::new(Mutex::new(BufReader::new(reader))), mock_openvpn_args_file, rpc_address_file, _temp_dir: temp_dir, @@ -269,42 +313,8 @@ impl DaemonRunner { &self.mock_openvpn_args_file } - 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"); - } - } - pub fn rpc_client(&mut self) -> Result<DaemonRpcClient> { - if !self.rpc_address_file.exists() { - let _ = PathWatcher::watch(&self.rpc_address_file).map(|mut events| { - events - .set_timeout(Duration::from_secs(10)) - .find(|&event| event == watch_event::CLOSE_WRITE) - }); - } + wait_for_file(&self.rpc_address_file); DaemonRpcClient::with_insecure_rpc_address_file(&self.rpc_address_file) .map_err(|error| format!("Failed to create RPC client: {}", error)) @@ -384,7 +394,13 @@ impl MockOpenVpnPluginRpcClient { pub fn up(&mut self) -> Result<()> { let mut env: HashMap<String, String> = HashMap::new(); + #[cfg(target_os = "linux")] env.insert("dev".to_owned(), "lo".to_owned()); + #[cfg(target_os = "macos")] + env.insert("dev".to_owned(), "lo0".to_owned()); + #[cfg(target_os = "windows")] + env.insert("dev".to_owned(), "loopback".to_owned()); + env.insert("ifconfig_local".to_owned(), "10.0.0.10".to_owned()); env.insert("route_vpn_gateway".to_owned(), "10.0.0.1".to_owned()); diff --git a/mullvad-tests/tests/account.rs b/mullvad-tests/tests/account.rs index 4d7c2bdcea..35e8baa6cf 100644 --- a/mullvad-tests/tests/account.rs +++ b/mullvad-tests/tests/account.rs @@ -1,4 +1,4 @@ -#![cfg(all(target_os = "linux", feature = "integration-tests"))] +#![cfg(feature = "integration-tests")] extern crate mullvad_tests; diff --git a/mullvad-tests/tests/connection.rs b/mullvad-tests/tests/connection.rs index 653d783aed..88e8a88c74 100644 --- a/mullvad-tests/tests/connection.rs +++ b/mullvad-tests/tests/connection.rs @@ -1,4 +1,4 @@ -#![cfg(all(target_os = "linux", feature = "integration-tests"))] +#![cfg(feature = "integration-tests")] extern crate mullvad_ipc_client; extern crate mullvad_tests; diff --git a/mullvad-tests/tests/startup.rs b/mullvad-tests/tests/startup.rs index 379755536a..3bf47430cc 100644 --- a/mullvad-tests/tests/startup.rs +++ b/mullvad-tests/tests/startup.rs @@ -1,4 +1,4 @@ -#![cfg(all(target_os = "linux", feature = "integration-tests"))] +#![cfg(feature = "integration-tests")] extern crate mullvad_paths; extern crate mullvad_tests; @@ -8,7 +8,7 @@ use std::fs::{self, Metadata}; use std::io; use std::time::Duration; -use mullvad_tests::DaemonRunner; +use mullvad_tests::{DaemonRunner, PathWatcher}; use mullvad_types::states::{DaemonState, SecurityState, TargetState}; use platform_specific::*; @@ -25,9 +25,10 @@ fn rpc_info_file_permissions() { assert!(!rpc_file.exists()); - let mut daemon = DaemonRunner::spawn_with_real_rpc_address_file(); + let mut rpc_file_watcher = PathWatcher::watch(&rpc_file).unwrap(); + let _daemon = DaemonRunner::spawn_with_real_rpc_address_file(); - daemon.assert_output("Wrote RPC connection info to", Duration::from_secs(10)); + rpc_file_watcher.wait_for_burst_of_events(Duration::from_secs(10)); assert!(rpc_file.exists()); |
