summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2018-08-27 14:48:07 +0100
committerEmīls Piņķis <emils@mullvad.net>2018-08-29 16:28:17 +0100
commit7e329e2019ce87d32b8e4324400e6f3915739837 (patch)
tree536481c0c5d1f682dce9fb1e975836c0e4d0a156
parentcff2be6a76823fa250df6b3a69a796093634dbc6 (diff)
downloadmullvadvpn-7e329e2019ce87d32b8e4324400e6f3915739837.tar.xz
mullvadvpn-7e329e2019ce87d32b8e4324400e6f3915739837.zip
Fix mullvad-tests
-rw-r--r--mullvad-tests/Cargo.toml4
-rw-r--r--mullvad-tests/src/lib.rs90
-rw-r--r--mullvad-tests/tests/connection.rs112
-rw-r--r--mullvad-tests/tests/startup.rs55
4 files changed, 58 insertions, 203 deletions
diff --git a/mullvad-tests/Cargo.toml b/mullvad-tests/Cargo.toml
index 7e7169c3f4..18f8b959d8 100644
--- a/mullvad-tests/Cargo.toml
+++ b/mullvad-tests/Cargo.toml
@@ -17,6 +17,10 @@ notify = "4.0"
openvpn-plugin = { version = "0.3", features = ["serde"] }
talpid-ipc = { path = "../talpid-ipc" }
tempfile = "3.0"
+jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs", branch = "master" }
+jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs", branch = "master" }
+tokio-core = "0.1"
+futures = "0.1.23"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
diff --git a/mullvad-tests/src/lib.rs b/mullvad-tests/src/lib.rs
index 0e2f404258..b90aaa3157 100644
--- a/mullvad-tests/src/lib.rs
+++ b/mullvad-tests/src/lib.rs
@@ -1,5 +1,7 @@
#[macro_use]
extern crate duct;
+extern crate jsonrpc_client_core;
+extern crate jsonrpc_client_ipc;
#[cfg(unix)]
extern crate libc;
extern crate mullvad_ipc_client;
@@ -9,6 +11,9 @@ extern crate openvpn_plugin;
extern crate talpid_ipc;
extern crate tempfile;
+extern crate futures;
+extern crate tokio_core;
+
pub mod mock_openvpn;
use std::collections::HashMap;
@@ -18,12 +23,15 @@ use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use std::{cmp, thread};
-use mullvad_ipc_client::DaemonRpcClient;
+use futures::sync::oneshot;
+use jsonrpc_client_core::{Future, Transport};
+use jsonrpc_client_ipc::IpcTransport;
+use mullvad_ipc_client::{DaemonRpcClient, ResultExt};
use mullvad_paths::resources::API_CA_FILENAME;
use notify::{RawEvent, RecommendedWatcher, RecursiveMode, Watcher};
use openvpn_plugin::types::OpenVpnPluginEvent;
-use talpid_ipc::WsIpcClient;
use tempfile::TempDir;
+use tokio_core::reactor::Core;
use self::mock_openvpn::MOCK_OPENVPN_ARGS_FILE;
use self::platform_specific::*;
@@ -261,50 +269,42 @@ fn prepare_relay_list<T: AsRef<Path>>(path: T) {
pub struct DaemonRunner {
process: Option<duct::Handle>,
mock_openvpn_args_file: PathBuf,
- rpc_address_file: PathBuf,
+ rpc_socket_path: PathBuf,
_temp_dir: TempDir,
}
impl DaemonRunner {
pub fn spawn_with_real_rpc_address_file() -> Self {
- Self::spawn_internal(false)
+ Self::spawn_internal()
}
pub fn spawn() -> Self {
- Self::spawn_internal(true)
+ Self::spawn_internal()
}
- fn spawn_internal(mock_rpc_address_file: bool) -> Self {
+ 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_address_file = if mock_rpc_address_file {
- temp_dir.path().join(".mullvad_rpc_address")
- } else {
- mullvad_paths::get_rpc_address_path().expect("Failed to build RPC connection file path")
- };
- let mut expression = cmd!(DAEMON_EXECUTABLE_PATH, "-v", "--disable-log-to-file")
+ let rpc_socket_path = temp_dir.path().join("rpc_socket");
+
+ let expression = 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();
- if mock_rpc_address_file {
- expression = expression.env(
- "MULLVAD_RPC_ADDRESS_PATH",
- rpc_address_file.display().to_string(),
- );
- }
let process = expression.start().expect("Failed to start daemon");
DaemonRunner {
process: Some(process),
mock_openvpn_args_file,
- rpc_address_file,
+ rpc_socket_path,
_temp_dir: temp_dir,
}
}
@@ -314,10 +314,12 @@ impl DaemonRunner {
}
pub fn rpc_client(&mut self) -> Result<DaemonRpcClient> {
- 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))
+ 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, handle| {
+ IpcTransport::new(&path, &handle)
+ .chain_err(|| mullvad_ipc_client::ErrorKind::TransportError)
+ }).map_err(|e| format!("Failed to construct an RPC client - {}", e))
}
#[cfg(unix)]
@@ -360,35 +362,38 @@ impl Drop for DaemonRunner {
process.kill().unwrap();
}
}
-
- let _ = fs::remove_file(&self.rpc_address_file);
}
}
pub struct MockOpenVpnPluginRpcClient {
- credentials: String,
- rpc: WsIpcClient,
+ rpc: jsonrpc_client_core::ClientHandle,
}
impl MockOpenVpnPluginRpcClient {
- pub fn new(address: String, credentials: String) -> Result<Self> {
- let rpc = WsIpcClient::connect(&address).map_err(|error| {
- format!("Failed to create Mock OpenVPN plugin RPC client: {}", error)
- })?;
+ fn spawn_event_loop(address: String) -> Result<jsonrpc_client_core::ClientHandle> {
+ let (tx, rx) = oneshot::channel();
+ thread::spawn(move || {
+ let mut core = Core::new().expect("failed to spawn an event loop");
- Ok(MockOpenVpnPluginRpcClient { rpc, credentials })
- }
+ let result = IpcTransport::new(&address, &core.handle())
+ .map_err(|error| {
+ format!("Failed to create Mock OpenVPN plugin RPC client: {}", error)
+ }).map(Transport::into_client);
+ match result {
+ Ok((client, client_handle)) => {
+ tx.send(Ok(client_handle)).unwrap();
+ core.run(client).expect("client failed");
+ }
+ Err(e) => tx.send(Err(e)).unwrap(),
+ }
+ });
- pub fn authenticate(&mut self) -> Result<bool> {
- self.rpc
- .call("authenticate", &[&self.credentials])
- .map_err(|error| format!("Failed to authenticate mock OpenVPN IPC client: {}", error))
+ rx.wait().unwrap()
}
- pub fn authenticate_with(&mut self, credentials: &str) -> Result<bool> {
- self.rpc
- .call("authenticate", &[credentials])
- .map_err(|error| format!("Failed to authenticate mock OpenVPN IPC client: {}", error))
+ pub fn new(address: String) -> Result<Self> {
+ let rpc = Self::spawn_event_loop(address)?;
+ Ok(MockOpenVpnPluginRpcClient { rpc })
}
pub fn up(&mut self) -> Result<()> {
@@ -417,7 +422,8 @@ impl MockOpenVpnPluginRpcClient {
env: HashMap<String, String>,
) -> Result<()> {
self.rpc
- .call("openvpn_event", &(event, env))
+ .call_method("openvpn_event", &(event, env))
+ .wait()
.map_err(|error| format!("Failed to send mock OpenVPN event {:?}: {}", event, error))
}
}
diff --git a/mullvad-tests/tests/connection.rs b/mullvad-tests/tests/connection.rs
index 88e8a88c74..75ee04d788 100644
--- a/mullvad-tests/tests/connection.rs
+++ b/mullvad-tests/tests/connection.rs
@@ -34,11 +34,6 @@ const CONNECTED_STATE: DaemonState = DaemonState {
target_state: TargetState::Secured,
};
-const DISCONNECTING_STATE: DaemonState = DaemonState {
- state: SecurityState::Secured,
- target_state: TargetState::Unsecured,
-};
-
#[test]
fn spawns_openvpn() {
let mut daemon = DaemonRunner::spawn();
@@ -91,86 +86,6 @@ fn changes_to_connecting_state() {
}
#[test]
-fn ignores_event_from_unauthorized_connection_from_openvpn_plugin() {
- 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.new_state_subscribe().unwrap();
-
- rpc_client.set_account(Some("123456".to_owned())).unwrap();
- rpc_client.connect().unwrap();
-
- assert_state_event(&state_events, CONNECTING_STATE);
- openvpn_args_file_events.assert_create_write_close_sequence();
-
- let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- let call_result = mock_plugin_client.up();
-
- assert!(call_result.is_err());
- assert_no_state_event(&state_events);
- assert_eq!(rpc_client.get_state().unwrap(), CONNECTING_STATE);
-}
-
-#[test]
-fn authentication_credentials() {
- 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.new_state_subscribe().unwrap();
-
- rpc_client.set_account(Some("123456".to_owned())).unwrap();
- rpc_client.connect().unwrap();
-
- assert_state_event(&state_events, CONNECTING_STATE);
- openvpn_args_file_events.assert_create_write_close_sequence();
-
- let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
-
- assert_eq!(
- mock_plugin_client.authenticate_with(&String::new()),
- Ok(false)
- );
- assert_eq!(
- mock_plugin_client.authenticate_with(&"fake-secret".to_owned()),
- Ok(false)
- );
- assert_eq!(mock_plugin_client.authenticate(), Ok(true));
- // Ensure it doesn't accept additional incorrect credentials
- assert_eq!(
- mock_plugin_client.authenticate_with(&"different-secret".to_owned()),
- Ok(false)
- );
-}
-
-#[test]
-fn separate_connections_have_independent_authentication() {
- 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.new_state_subscribe().unwrap();
-
- rpc_client.set_account(Some("123456".to_owned())).unwrap();
- rpc_client.connect().unwrap();
-
- assert_state_event(&state_events, CONNECTING_STATE);
- openvpn_args_file_events.assert_create_write_close_sequence();
-
- let mut first_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- let mut second_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
-
- let auth_result = first_plugin_client.authenticate();
- let call_result = second_plugin_client.up();
-
- assert_eq!(auth_result, Ok(true));
- assert!(call_result.is_err());
- assert_no_state_event(&state_events);
- assert_eq!(rpc_client.get_state().unwrap(), CONNECTING_STATE);
-}
-
-#[test]
fn changes_to_connected_state() {
let mut daemon = DaemonRunner::spawn();
let mut rpc_client = daemon.rpc_client().unwrap();
@@ -186,7 +101,6 @@ fn changes_to_connected_state() {
let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- mock_plugin_client.authenticate().unwrap();
mock_plugin_client.up().unwrap();
assert_state_event(&state_events, CONNECTED_STATE);
@@ -209,7 +123,6 @@ fn returns_to_connecting_state() {
let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- mock_plugin_client.authenticate().unwrap();
mock_plugin_client.up().unwrap();
assert_state_event(&state_events, CONNECTED_STATE);
@@ -240,14 +153,12 @@ fn disconnects() {
let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- mock_plugin_client.authenticate().unwrap();
mock_plugin_client.up().unwrap();
assert_state_event(&state_events, CONNECTED_STATE);
rpc_client.disconnect().unwrap();
- assert_state_event(&state_events, DISCONNECTING_STATE);
assert_state_event(&state_events, DISCONNECTED_STATE);
assert_eq!(rpc_client.get_state().unwrap(), DISCONNECTED_STATE);
}
@@ -260,33 +171,20 @@ fn assert_state_event(receiver: &mpsc::Receiver<DaemonState>, expected_state: Da
assert_eq!(received_state, expected_state);
}
-fn assert_no_state_event(receiver: &mpsc::Receiver<DaemonState>) {
- assert_eq!(
- receiver.recv_timeout(Duration::from_secs(1)),
- Err(mpsc::RecvTimeoutError::Timeout),
- );
-}
-
fn create_mock_openvpn_plugin_client<P: AsRef<Path>>(
openvpn_args_file_path: P,
) -> MockOpenVpnPluginRpcClient {
- let (address, credentials) = get_plugin_arguments(openvpn_args_file_path);
+ let address = get_plugin_arguments(openvpn_args_file_path);
- MockOpenVpnPluginRpcClient::new(address, credentials)
+ 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, String) {
+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);
- let address = arguments
+ arguments
.next()
.expect("Missing OpenVPN plugin RPC listener address argument")
- .expect("Failed to read from mock OpenVPN arguments file");
- let credentials = arguments
- .next()
- .expect("Missing OpenVPN plugin RPC listener credentials argument")
- .expect("Failed to read from mock OpenVPN arguments file");
-
- (address, credentials)
+ .expect("Failed to read from mock OpenVPN arguments file")
}
diff --git a/mullvad-tests/tests/startup.rs b/mullvad-tests/tests/startup.rs
index 3bf47430cc..0424023515 100644
--- a/mullvad-tests/tests/startup.rs
+++ b/mullvad-tests/tests/startup.rs
@@ -4,39 +4,9 @@ extern crate mullvad_paths;
extern crate mullvad_tests;
extern crate mullvad_types;
-use std::fs::{self, Metadata};
-use std::io;
-use std::time::Duration;
-
-use mullvad_tests::{DaemonRunner, PathWatcher};
+use mullvad_tests::DaemonRunner;
use mullvad_types::states::{DaemonState, SecurityState, TargetState};
-use platform_specific::*;
-
-#[test]
-fn rpc_info_file_permissions() {
- let rpc_file = mullvad_paths::get_rpc_address_path().unwrap();
-
- 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 rpc_file_watcher = PathWatcher::watch(&rpc_file).unwrap();
- let _daemon = DaemonRunner::spawn_with_real_rpc_address_file();
-
- rpc_file_watcher.wait_for_burst_of_events(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"),
- );
-}
-
#[test]
fn starts_in_not_connected_state() {
let mut daemon = DaemonRunner::spawn();
@@ -50,26 +20,3 @@ fn starts_in_not_connected_state() {
assert_eq!(state, not_connected_state);
}
-
-#[cfg(unix)]
-mod platform_specific {
- extern crate libc;
-
- 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
- }
-}