summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rwxr-xr-xintegration-tests.sh19
-rw-r--r--mullvad-tests/Cargo.toml1
-rw-r--r--mullvad-tests/src/lib.rs110
-rw-r--r--mullvad-tests/tests/account.rs2
-rw-r--r--mullvad-tests/tests/connection.rs2
-rw-r--r--mullvad-tests/tests/startup.rs9
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());