diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2021-12-13 14:43:06 +0000 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2021-12-13 14:43:06 +0000 |
| commit | 785254150f39e42256cf36fbf2d2901694dc6e7c (patch) | |
| tree | 05834634b4ad06375cf1bdf05c2378750750d037 | |
| parent | caa111d2e374a340f63b9e8e059afb1103e402c8 (diff) | |
| parent | b150de5b501b368e11dcb8cdc6aa26761352c538 (diff) | |
| download | mullvadvpn-785254150f39e42256cf36fbf2d2901694dc6e7c.tar.xz mullvadvpn-785254150f39e42256cf36fbf2d2901694dc6e7c.zip | |
Merge branch 'remove-mullvad-tests'
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rwxr-xr-x | integration-tests.sh | 30 | ||||
| -rw-r--r-- | mullvad-tests/Cargo.toml | 38 | ||||
| -rw-r--r-- | mullvad-tests/build.rs | 5 | ||||
| -rw-r--r-- | mullvad-tests/src/bin/mock_openvpn.rs | 84 | ||||
| -rw-r--r-- | mullvad-tests/src/lib.rs | 435 | ||||
| -rw-r--r-- | mullvad-tests/src/mock_openvpn/mod.rs | 24 | ||||
| -rw-r--r-- | mullvad-tests/tests/account.rs | 81 | ||||
| -rw-r--r-- | mullvad-tests/tests/connection.rs | 276 | ||||
| -rw-r--r-- | mullvad-tests/tests/startup.rs | 14 |
11 files changed, 0 insertions, 995 deletions
diff --git a/Cargo.toml b/Cargo.toml index a2ac2f12cb..0078b2b3a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "mullvad-paths", "mullvad-types", "mullvad-rpc", -# "mullvad-tests", "mullvad-exclude", "talpid-openvpn-plugin", "talpid-core", @@ -577,13 +577,6 @@ the version of the app you are going to release. For example `2018.3-beta1` or ` Please pay attention to the output at the end of the script and make sure the version it says it built matches what you want to release. -## Running Integration Tests - -The integration tests are located in the `mullvad-tests` crate. It uses a mock OpenVPN binary to -test the `mullvad-daemon`. To run the tests, the `mullvad-daemon` binary must be built first. -Afterwards, the tests should be executed with the `integration-tests` feature enabled. To simplify -this procedure, the `integration-tests.sh` script can be used to run all integration tests. - ## Command line tools for Electron GUI app development diff --git a/integration-tests.sh b/integration-tests.sh deleted file mode 100755 index 4de1085972..0000000000 --- a/integration-tests.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -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)" - -pushd "$MULLVAD_DIR" - -cargo build \ - && cd mullvad-tests \ - && cargo test --features "integration-tests" -- --test-threads=1 - -RESULT="$?" -popd -exit "$RESULT" diff --git a/mullvad-tests/Cargo.toml b/mullvad-tests/Cargo.toml deleted file mode 100644 index 5bc1a230a4..0000000000 --- a/mullvad-tests/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "mullvad-tests" -version = "0.1.0" -authors = ["Mullvad VPN"] -description = "Mullvad test specific modules and binaries" -license = "GPL-3.0" -edition = "2021" -publish = false - -[features] -integration-tests = [] - -[dependencies] -duct = "0.13" -mullvad-paths = { path = "../mullvad-paths" } -mullvad-rpc = { path = "../mullvad-rpc" } -mullvad-types = { path = "../mullvad-types" } -notify = "4.0" -openvpn-plugin = { git = "https://github.com/mullvad/openvpn-plugin-rs", branch = "auth-failed-event", features = ["serde"] } -talpid-types = { path = "../talpid-types" } -tempfile = "3.0" -jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs", rev = "68aac55b" } -jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs", rev = "68aac55b" } -jsonrpc-client-pubsub = { git = "https://github.com/mullvad/jsonrpc-client-rs", rev = "68aac55b" } -futures = "0.1.23" -tokio01 = { package = "tokio", version = "0.1" } -tokio-timer = "0.1" -tokio = { version = "1.8", features = [ "io-util", "process", "rt", "rt-multi-thread", "fs"] } -tonic = "0.5" -tower = "0.4" -prost = "0.8" -parity-tokio-ipc = "0.9" - -[build-dependencies] -tonic-build = { version = "0.5", default-features = false, features = ["transport", "prost"] } - -[target.'cfg(unix)'.dependencies] -libc = "0.2" diff --git a/mullvad-tests/build.rs b/mullvad-tests/build.rs deleted file mode 100644 index 71c9068925..0000000000 --- a/mullvad-tests/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - const OPENVPN_PROTO_FILE: &str = "../talpid-openvpn-plugin/proto/openvpn_plugin.proto"; - tonic_build::compile_protos(OPENVPN_PROTO_FILE).unwrap(); - println!("cargo:rerun-if-changed={}", OPENVPN_PROTO_FILE); -} diff --git a/mullvad-tests/src/bin/mock_openvpn.rs b/mullvad-tests/src/bin/mock_openvpn.rs deleted file mode 100644 index 03d38a4a09..0000000000 --- a/mullvad-tests/src/bin/mock_openvpn.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::mock_openvpn::run; - -fn main() { - run(); -} - -#[cfg(target_os = "android")] -mod mock_openvpn { - pub fn run() {} -} - -#[cfg(not(target_os = "android"))] -mod mock_openvpn { - use mullvad_tests::{watch_event, PathWatcher}; - use std::{ - env, - fs::{self, File}, - io::{self, Read, Write}, - path::PathBuf, - sync::mpsc, - thread, - time::Duration, - }; - - const MAX_EVENT_TIME: Duration = Duration::from_secs(60); - - pub fn run() { - let (file, path) = create_args_file(); - let (finished_tx, finished_rx) = mpsc::channel(); - let watcher = PathWatcher::watch(&path).expect("Failed to watch file for events"); - - write_command_line(file); - - wait_thread(wait_for_stdin_to_be_closed, finished_tx.clone()); - wait_thread( - move || wait_for_file_to_be_deleted(watcher, MAX_EVENT_TIME), - finished_tx, - ); - - let _ = finished_rx.recv(); - let _ = fs::remove_file(path); - } - - fn create_args_file() -> (File, PathBuf) { - let path = PathBuf::from( - env::var_os("MOCK_OPENVPN_ARGS_FILE") - .expect("Missing mock OpenVPN arguments file path"), - ); - let file = File::create(&path).expect("Failed to create mock OpenVPN arguments file"); - - (file, path) - } - - fn write_command_line(mut file: File) { - for argument in env::args() { - let escaped_argument = argument - .replace("\\", "\\\\") - .replace("\n", "\\n") - .replace("\r", "\\r"); - - writeln!(file, "{}", escaped_argument).expect("Failed to write argument to file"); - } - } - - fn wait_thread<F>(function: F, finished_tx: mpsc::Sender<()>) - where - F: FnOnce() + Send + 'static, - { - thread::spawn(move || { - function(); - let _ = finished_tx.send(()); - }); - } - - fn wait_for_stdin_to_be_closed() { - let _ignore_bytes = io::stdin().bytes().last(); - } - - fn wait_for_file_to_be_deleted(mut watcher: PathWatcher, timeout: Duration) { - let _ignore_event = watcher - .set_timeout(timeout) - .find(|&event| event == watch_event::REMOVE); - } -} diff --git a/mullvad-tests/src/lib.rs b/mullvad-tests/src/lib.rs deleted file mode 100644 index ad0d85bf89..0000000000 --- a/mullvad-tests/src/lib.rs +++ /dev/null @@ -1,435 +0,0 @@ -#![cfg(not(target_os = "android"))] - -use self::{mock_openvpn::MOCK_OPENVPN_ARGS_FILE, platform_specific::*}; -use jsonrpc_client_ipc::IpcTransport; -use mullvad_ipc_client::DaemonRpcClient; -use mullvad_rpc::API_IP_CACHE_FILENAME; -use notify::{RawEvent, RecommendedWatcher, RecursiveMode, Watcher}; -use std::{ - cmp, - collections::HashMap, - fs::{self, File}, - path::{Path, PathBuf}, - sync::{mpsc, Arc}, - thread, - time::{Duration, Instant}, -}; -use tempfile::TempDir; - -pub use notify::op::{self as watch_event, Op as WatchEvent}; - -use parity_tokio_ipc::Endpoint as IpcEndpoint; -use tonic::{ - self, - transport::{Endpoint, Uri}, -}; -use tower::service_fn; - -mod openvpn_proto { - tonic::include_proto!("talpid_openvpn_plugin"); -} -use openvpn_proto::openvpn_event_proxy_client::OpenvpnEventProxyClient; - -pub mod mock_openvpn; - -type Result<T> = std::result::Result<T, String>; - -pub const ASSETS_DIR: &str = "../dist-assets"; - -#[cfg(unix)] -mod platform_specific { - pub const DAEMON_EXECUTABLE_PATH: &str = "../target/debug/mullvad-daemon"; - pub const MOCK_OPENVPN_EXECUTABLE_PATH: &str = "../target/debug/mock_openvpn"; - pub const OPENVPN_EXECUTABLE_FILE: &str = "openvpn"; - #[cfg(target_os = "linux")] - pub const TALPID_OPENVPN_PLUGIN_FILE: &str = "libtalpid_openvpn_plugin.so"; - #[cfg(target_os = "macos")] - pub const TALPID_OPENVPN_PLUGIN_FILE: &str = "libtalpid_openvpn_plugin.dylib"; -} - -#[cfg(not(unix))] -mod platform_specific { - pub const DAEMON_EXECUTABLE_PATH: &str = r"..\target\debug\mullvad-daemon.exe"; - pub const MOCK_OPENVPN_EXECUTABLE_PATH: &str = "../target/debug/mock_openvpn.exe"; - pub const OPENVPN_EXECUTABLE_FILE: &str = "openvpn.exe"; - pub const TALPID_OPENVPN_PLUGIN_FILE: &str = "talpid_openvpn_plugin.dll"; -} - -pub struct PathWatcher { - events: mpsc::Receiver<RawEvent>, - path: PathBuf, - timeout: Duration, - _watcher: RecommendedWatcher, -} - -impl PathWatcher { - pub fn watch<P: AsRef<Path>>(file_path: P) -> Result<Self> { - let file_path = file_path.as_ref(); - let parent_dir = file_path - .parent() - .ok_or_else(|| "Missing file parent directory")?; - - let absolute_parent_dir = parent_dir - .canonicalize() - .map_err(|_| "Failed to get absolute path to watch")?; - let file_name = file_path - .file_name() - .ok_or_else(|| "Missing file name of file path to watch")?; - let absolute_file_path = absolute_parent_dir.join(file_name); - - let (tx, rx) = mpsc::channel(); - let mut watcher = notify::raw_watcher(tx).map_err(|_| { - format!( - "Failed to create watcher of file system events to watch {}", - file_path.display() - ) - })?; - - watcher - .watch(absolute_parent_dir, RecursiveMode::Recursive) - .map_err(|_| { - format!( - "Failed to start watching for file system events from {}", - file_path.display() - ) - })?; - - Ok(PathWatcher { - events: rx, - path: absolute_file_path, - timeout: Duration::from_secs(5), - _watcher: watcher, - }) - } - - pub fn set_timeout(&mut self, timeout: Duration) -> &mut Self { - self.timeout = timeout; - self - } - - pub fn assert_create_write_close_sequence(&mut self) { - 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, - event => { - assert_eq!(event, Some(watch_event::CLOSE_WRITE)); - break; - } - } - } - } - - /// 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 { - type Item = WatchEvent; - - fn next(&mut self) -> Option<Self::Item> { - let start = Instant::now(); - - while let Some(remaining_time) = self.timeout.checked_sub(start.elapsed()) { - match self.events.recv_timeout(remaining_time) { - Ok(RawEvent { - path: Some(path), - op: Ok(op), - .. - }) => { - if path == self.path { - return Some(op); - } else { - continue; - } - } - Ok(_) => continue, - Err(_) => return None, - } - } - - None - } -} - -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"); - let resource_dir = temp_dir.path().join("resource-dir"); - let settings_dir = temp_dir.path().join("settings"); - - fs::create_dir(&cache_dir).expect("Failed to create cache directory"); - fs::create_dir(&resource_dir).expect("Failed to create resource directory"); - fs::create_dir(&settings_dir).expect("Failed to create settings directory"); - - prepare_resource_dir(&resource_dir); - prepare_cache_dir(&cache_dir); - - (temp_dir, cache_dir, resource_dir, settings_dir) -} - -fn prepare_resource_dir(resource_dir: &Path) { - let openvpn_binary = resource_dir.join(OPENVPN_EXECUTABLE_FILE); - let talpid_openvpn_plugin = resource_dir.join(TALPID_OPENVPN_PLUGIN_FILE); - - fs::copy(MOCK_OPENVPN_EXECUTABLE_PATH, openvpn_binary) - .expect("Failed to copy mock OpenVPN binary"); - File::create(talpid_openvpn_plugin).expect("Failed to create mock Talpid OpenVPN plugin"); -} - -fn prepare_cache_dir(cache_dir: &Path) { - prepare_relay_list(cache_dir.join("relays.json")); - - fs::write(cache_dir.join(API_IP_CACHE_FILENAME), "192.168.0.123") - .expect("Failed to cache API IP"); -} - -fn prepare_relay_list<T: AsRef<Path>>(path: T) { - fs::write( - path, - r#"{ - "countries": [{ - "name": "Sweden", - "code": "se", - "cities": [{ - "name": "Gothenburg", - "code": "got", - "latitude": 57.70887, - "longitude": 11.97456, - "relays": [{ - "hostname": "fakehost", - "ipv4_addr_in": "192.168.0.100", - "ipv6_addr_in": null, - "include_in_country": true, - "active": true, - "owned": false, - "provider": "M247", - "weight": 100, - "tunnels": { - "openvpn": [ { "port": 1000, "protocol": "udp" } ], - "wireguard": [] - } - }], - "location": { - "country": "Sweden", - "country_code": "se", - "city": "Gothenburg", - "city_code": "got", - "latitude": 57.70887, - "longitude": 11.97456 - } - }] - }] - }"#, - ) - .expect("Failed to create mock relay list file"); -} - -pub struct DaemonRunner { - process: Option<duct::Handle>, - mock_openvpn_args_file: PathBuf, - rpc_socket_path: PathBuf, - _temp_dir: TempDir, -} - -impl DaemonRunner { - pub fn spawn() -> Self { - Self::spawn_internal() - } - - fn spawn_internal() -> Self { - let (temp_dir, cache_dir, resource_dir, settings_dir) = prepare_test_dirs(); - let mock_openvpn_args_file = temp_dir.path().join(MOCK_OPENVPN_ARGS_FILE); - - let rpc_socket_path = temp_dir.path().join("rpc_socket"); - - let expression = duct::cmd!(DAEMON_EXECUTABLE_PATH, "-v", "--disable-log-to-file") - .dir("..") - .env("MULLVAD_CACHE_DIR", cache_dir) - .env("MULLVAD_RPC_SOCKET_PATH", rpc_socket_path.clone()) - .env("MULLVAD_RESOURCE_DIR", resource_dir) - .env("MULLVAD_SETTINGS_DIR", settings_dir) - .env("MOCK_OPENVPN_ARGS_FILE", mock_openvpn_args_file.clone()) - .stdout_null() - .stderr_null(); - - - let process = expression.start().expect("Failed to start daemon"); - - DaemonRunner { - process: Some(process), - mock_openvpn_args_file, - rpc_socket_path, - _temp_dir: temp_dir, - } - } - - pub fn mock_openvpn_args_file(&self) -> &Path { - &self.mock_openvpn_args_file - } - - pub fn rpc_client(&mut self) -> Result<DaemonRpcClient> { - wait_for_file(&self.rpc_socket_path); - let socket_path: String = self.rpc_socket_path.to_string_lossy().to_string(); - mullvad_ipc_client::new_standalone_transport(socket_path, |path| { - IpcTransport::new(&path, &tokio01::reactor::Handle::default()) - }) - .map_err(|e| e.to_string()) - .map_err(|e| format!("Failed to construct an RPC client - {}", e)) - } - - #[cfg(unix)] - fn request_clean_shutdown(&mut self, process: &mut duct::Handle) -> bool { - use duct::unix::HandleExt; - - process.send_signal(libc::SIGTERM).is_ok() - } - - #[cfg(not(unix))] - fn request_clean_shutdown(&mut self, _: &mut duct::Handle) -> bool { - if let Ok(mut rpc_client) = self.rpc_client() { - rpc_client.shutdown().is_ok() - } else { - false - } - } -} - -impl Drop for DaemonRunner { - fn drop(&mut self) { - if let Some(mut process) = self.process.take() { - if self.request_clean_shutdown(&mut process) { - let process = Arc::new(process); - let wait_handle = process.clone(); - let (finished_tx, finished_rx) = mpsc::channel(); - - thread::spawn(move || finished_tx.send(wait_handle.wait().map(|_| ())).unwrap()); - - let has_finished = finished_rx - .recv_timeout(Duration::from_secs(5)) - .map_err(|_| ()) - .and_then(|result| result.map_err(|_| ())) - .is_ok(); - - if !has_finished { - process.kill().unwrap(); - } - } else { - process.kill().unwrap(); - } - } - } -} - -pub struct MockOpenVpnPluginRpcClient { - runtime: tokio::runtime::Runtime, - rpc: OpenvpnEventProxyClient<tonic::transport::Channel>, -} - -impl MockOpenVpnPluginRpcClient { - async fn spawn_event_loop( - address: String, - ) -> Result<OpenvpnEventProxyClient<tonic::transport::Channel>> { - // The URI will be ignored - let channel = Endpoint::from_static("lttp://[::]:50051") - .connect_with_connector(service_fn(move |_: Uri| { - IpcEndpoint::connect(address.clone()) - })) - .await - .map_err(|e| format!("Failed to construct an RPC client - {}", e.to_string()))?; - - Ok(OpenvpnEventProxyClient::new(channel)) - } - - pub fn new(address: String) -> Result<Self> { - let mut runtime = tokio::runtime::Runtime::new().unwrap(); - - let rpc = runtime.block_on(Self::spawn_event_loop(address))?; - Ok(MockOpenVpnPluginRpcClient { runtime, rpc }) - } - - 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()); - - self.send_event(openvpn_plugin::EventType::RouteUp, env) - } - - pub fn route_predown(&mut self) -> Result<()> { - self.send_event(openvpn_plugin::EventType::RoutePredown, HashMap::new()) - } - - fn send_event( - &mut self, - event: openvpn_plugin::EventType, - env: HashMap<String, String>, - ) -> Result<()> { - self.runtime - .block_on(self.rpc.event(openvpn_proto::EventType { - event: event as i16 as i32, - env, - })) - .map(|_| ()) - .map_err(|error| format!("Failed to send mock OpenVPN event {:?}: {}", event, error)) - } -} diff --git a/mullvad-tests/src/mock_openvpn/mod.rs b/mullvad-tests/src/mock_openvpn/mod.rs deleted file mode 100644 index 9c84496e66..0000000000 --- a/mullvad-tests/src/mock_openvpn/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::{ - fs::File, - io::{self, BufRead, BufReader}, - path::Path, -}; - -pub const MOCK_OPENVPN_ARGS_FILE: &str = "mock_openvpn_args"; - -pub fn search_openvpn_args<P: AsRef<Path>>( - openvpn_args_file_path: P, - search_item: &'static str, -) -> impl Iterator<Item = io::Result<String>> { - let args_file_path = openvpn_args_file_path.as_ref(); - let args_file = File::open(&args_file_path).expect(&format!( - "Failed to open mock OpenVPN arguments file: {}", - args_file_path.display(), - )); - - let args = BufReader::new(args_file).lines(); - - args.skip_while(move |element| { - element.is_ok() && !element.as_ref().unwrap().contains(search_item) - }) -} diff --git a/mullvad-tests/tests/account.rs b/mullvad-tests/tests/account.rs deleted file mode 100644 index e4cff3b4b9..0000000000 --- a/mullvad-tests/tests/account.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![cfg(feature = "integration-tests")] - -use mullvad_tests::{mock_openvpn::search_openvpn_args, watch_event, DaemonRunner, PathWatcher}; -use std::{ - fs::File, - io::{BufRead, BufReader}, - path::Path, -}; - -#[test] -fn uses_account_token() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - - let specified_account = "123456"; - rpc_client - .set_account(Some(specified_account.to_owned())) - .unwrap(); - rpc_client.connect().unwrap(); - - openvpn_args_file_events.assert_create_write_close_sequence(); - - let account_token_sent_to_plugin = read_account_token(openvpn_args_file).unwrap(); - - assert_eq!(account_token_sent_to_plugin, specified_account); -} - -#[test] -fn uses_updated_account_token() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - - let first_account_specified = "123456"; - rpc_client - .set_account(Some(first_account_specified.to_owned())) - .unwrap(); - rpc_client.connect().unwrap(); - - openvpn_args_file_events.assert_create_write_close_sequence(); - - let second_account_specified = "654321"; - rpc_client - .set_account(Some(second_account_specified.to_owned())) - .unwrap(); - - assert_eq!(openvpn_args_file_events.next(), Some(watch_event::REMOVE)); - openvpn_args_file_events.assert_create_write_close_sequence(); - - let account_token_sent_to_plugin = read_account_token(openvpn_args_file).unwrap(); - - assert_eq!(account_token_sent_to_plugin, second_account_specified); -} - -fn read_account_token<P: AsRef<Path>>(openvpn_args_file_path: P) -> Result<String, String> { - let account_token_file_path = search_openvpn_args(openvpn_args_file_path, "--auth-user-pass") - .skip(1) - .next() - .ok_or_else(|| "Missing account token file parameter to Talpid OpenVPN plugin".to_owned())? - .map_err(|error| { - format!( - "Failed to read from mock OpenVPN command line file: {}", - error - ) - })?; - - let account_token_file = File::open(account_token_file_path) - .map_err(|error| format!("Failed to open account token file: {}", error))?; - - let mut reader = BufReader::new(account_token_file); - let mut account = String::new(); - - reader - .read_line(&mut account) - .map_err(|error| format!("Failed to read from account token file: {}", error))?; - - Ok(account.trim().to_owned()) -} diff --git a/mullvad-tests/tests/connection.rs b/mullvad-tests/tests/connection.rs deleted file mode 100644 index 2d294232ef..0000000000 --- a/mullvad-tests/tests/connection.rs +++ /dev/null @@ -1,276 +0,0 @@ -#![cfg(feature = "integration-tests")] - -use futures::{stream::Stream, Future}; -use mullvad_tests::{ - mock_openvpn::search_openvpn_args, watch_event, DaemonRunner, MockOpenVpnPluginRpcClient, - PathWatcher, -}; -use mullvad_types::{location::GeoIpLocation, states::TunnelState, DaemonEvent}; -use std::{fs, path::Path, time::Duration}; -use talpid_types::{ - net::{Endpoint, TransportProtocol, TunnelEndpoint, TunnelType}, - tunnel::ActionAfterDisconnect, -}; - -#[cfg(target_os = "linux")] -const OPENVPN_PLUGIN_NAME: &str = "libtalpid_openvpn_plugin.so"; - -#[cfg(windows)] -const OPENVPN_PLUGIN_NAME: &str = "talpid_openvpn_plugin.dll"; - -#[test] -fn spawns_openvpn() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - - assert!(!openvpn_args_file.exists()); - - rpc_client.set_account(Some("123456".to_owned())).unwrap(); - rpc_client.connect().unwrap(); - - openvpn_args_file_events.assert_create_write_close_sequence(); -} - -#[test] -fn respawns_openvpn_if_it_crashes() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - - openvpn_args_file_events.set_timeout(Duration::from_secs(10)); - - assert!(!openvpn_args_file.exists()); - - rpc_client.set_account(Some("123456".to_owned())).unwrap(); - rpc_client.connect().unwrap(); - - openvpn_args_file_events.assert_create_write_close_sequence(); - - // Stop OpenVPN by removing the mock OpenVPN arguments file - fs::remove_file(&openvpn_args_file).expect("Failed to remove the mock OpenVPN arguments file"); - assert_eq!(openvpn_args_file_events.next(), Some(watch_event::REMOVE)); - - openvpn_args_file_events.assert_create_write_close_sequence(); -} - -#[test] -fn changes_to_connecting_state() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let state_events = rpc_client.daemon_event_subscribe().wait().unwrap(); - - rpc_client.set_account(Some("123456".to_owned())).unwrap(); - rpc_client.connect().unwrap(); - - let _ = assert_state_event( - state_events, - TunnelState::Connecting { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - assert_eq!( - rpc_client.get_state().unwrap(), - TunnelState::Connecting { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); -} - -#[test] -fn changes_to_connected_state() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - let state_events = rpc_client.daemon_event_subscribe().wait().unwrap(); - - rpc_client.set_account(Some("123456".to_owned())).unwrap(); - rpc_client.connect().unwrap(); - - let state_events = assert_state_event( - state_events, - TunnelState::Connecting { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - openvpn_args_file_events.assert_create_write_close_sequence(); - - let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file); - - mock_plugin_client.up().unwrap(); - - assert_state_event( - state_events, - TunnelState::Connected { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - assert_eq!( - rpc_client.get_state().unwrap(), - TunnelState::Connected { - endpoint: get_default_endpoint(), - location: get_default_location(), - } - ); -} - -#[test] -fn returns_to_connecting_state() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - let state_events = rpc_client.daemon_event_subscribe().wait().unwrap(); - - rpc_client.set_account(Some("123456".to_owned())).unwrap(); - rpc_client.connect().unwrap(); - - let state_events = assert_state_event( - state_events, - TunnelState::Connecting { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - openvpn_args_file_events.assert_create_write_close_sequence(); - - let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file); - - mock_plugin_client.up().unwrap(); - - let state_events = assert_state_event( - state_events, - TunnelState::Connected { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - - mock_plugin_client.route_predown().unwrap(); - - // Wait for new OpenVPN instance - assert_eq!(openvpn_args_file_events.next(), Some(watch_event::REMOVE)); - openvpn_args_file_events.assert_create_write_close_sequence(); - - let _ = assert_state_event( - state_events, - TunnelState::Disconnecting(ActionAfterDisconnect::Reconnect), - ); -} - -#[test] -fn disconnects() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().unwrap(); - let openvpn_args_file = daemon.mock_openvpn_args_file(); - let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap(); - let state_events = rpc_client.daemon_event_subscribe().wait().unwrap(); - - rpc_client.set_account(Some("123456".to_owned())).unwrap(); - rpc_client.connect().unwrap(); - - let state_events = assert_state_event( - state_events, - TunnelState::Connecting { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - openvpn_args_file_events.assert_create_write_close_sequence(); - - let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file); - - mock_plugin_client.up().unwrap(); - - let state_events = assert_state_event( - state_events, - TunnelState::Connected { - endpoint: get_default_endpoint(), - location: get_default_location(), - }, - ); - - rpc_client.disconnect().unwrap(); - - let state_events = assert_state_event( - state_events, - TunnelState::Disconnecting(ActionAfterDisconnect::Nothing), - ); - let _ = assert_state_event(state_events, TunnelState::Disconnected); -} - -fn get_default_endpoint() -> TunnelEndpoint { - TunnelEndpoint { - endpoint: Endpoint { - address: "192.168.0.100:1000".parse().unwrap(), - protocol: TransportProtocol::Udp, - }, - tunnel_type: TunnelType::OpenVpn, - proxy: None, - } -} - -fn get_default_location() -> Option<GeoIpLocation> { - Some(GeoIpLocation { - ipv4: None, - ipv6: None, - country: "Sweden".to_string(), - city: Some("Gothenburg".to_string()), - latitude: 57.70887, - longitude: 11.97456, - mullvad_exit_ip: true, - hostname: Some("fakehost".to_string()), - bridge_hostname: None, - }) -} - -fn assert_state_event< - S: Stream<Item = DaemonEvent, Error = jsonrpc_client_core::Error> + std::fmt::Debug, ->( - mut receiver: S, - expected_state: TunnelState, -) -> S { - use futures::future::Either; - - let mut transition = None; - while transition.is_none() { - let timer = tokio_timer::Timer::default(); - let timeout = timer.sleep(Duration::from_secs(3)); - let (event, receiver2) = match receiver.into_future().select2(timeout).wait() { - Ok(Either::A((stream_result, _timer))) => stream_result, - _ => panic!("Timed out waiting for tunnel state transition"), - }; - receiver = receiver2; - if let DaemonEvent::TunnelState(new_state) = event.unwrap() { - transition = Some(new_state); - } - } - - assert_eq!(transition.unwrap(), expected_state); - receiver -} - -fn create_mock_openvpn_plugin_client<P: AsRef<Path>>( - openvpn_args_file_path: P, -) -> MockOpenVpnPluginRpcClient { - let address = get_plugin_arguments(openvpn_args_file_path); - - MockOpenVpnPluginRpcClient::new(address) - .expect("Failed to create mock RPC client to connect to OpenVPN plugin event listener") -} - -fn get_plugin_arguments<P: AsRef<Path>>(openvpn_args_file_path: P) -> String { - let mut arguments = search_openvpn_args(openvpn_args_file_path, OPENVPN_PLUGIN_NAME).skip(1); - - arguments - .next() - .expect("Missing OpenVPN plugin RPC listener address argument") - .expect("Failed to read from mock OpenVPN arguments file") -} diff --git a/mullvad-tests/tests/startup.rs b/mullvad-tests/tests/startup.rs deleted file mode 100644 index 812d443f66..0000000000 --- a/mullvad-tests/tests/startup.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![cfg(feature = "integration-tests")] - -use mullvad_tests::DaemonRunner; -use mullvad_types::states::TunnelState; - -#[test] -fn starts_in_disconnected_state() { - let mut daemon = DaemonRunner::spawn(); - let mut rpc_client = daemon.rpc_client().expect("Failed to create RPC client"); - - let state = rpc_client.get_state().expect("Failed to read daemon state"); - - assert_eq!(state, TunnelState::Disconnected); -} |
