summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--src/lib.rs3
-rw-r--r--src/process.rs50
-rw-r--r--tests/process.rs36
-rw-r--r--tests/util.rs16
5 files changed, 108 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml
index 50a05a487f..5b9368c0b1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,9 @@ rust:
os:
- linux
- osx
+env:
+ global:
+ - RUST_TEST_THREADS=1
before_script:
- (cargo install rustfmt || true)
diff --git a/src/lib.rs b/src/lib.rs
index 949a029d45..fec2e1da5e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,9 @@
//! The core components of the talpidaemon VPN client.
+/// Working with processes.
+pub mod process;
+
#[cfg(test)]
mod tests {
#[test]
diff --git a/src/process.rs b/src/process.rs
new file mode 100644
index 0000000000..7143b85eb3
--- /dev/null
+++ b/src/process.rs
@@ -0,0 +1,50 @@
+use std::ffi::{OsString, OsStr};
+use std::io;
+use std::path::{Path, PathBuf};
+use std::process::{Command, Child, Stdio};
+
+/// An OpenVPN process builder, providing control over the different arguments that the OpenVPN
+/// binary accepts.
+pub struct OpenVpnBuilder {
+ openvpn_bin: OsString,
+ config: Option<PathBuf>,
+}
+
+impl OpenVpnBuilder {
+ /// Constructs a new `OpenVpnBuilder` for launching OpenVPN processes from the binary at
+ /// `openvpn_bin`.
+ pub fn new<P: AsRef<OsStr>>(openvpn_bin: P) -> Self {
+ OpenVpnBuilder {
+ openvpn_bin: OsString::from(openvpn_bin.as_ref()),
+ config: None,
+ }
+ }
+
+ /// Sets what configuration file will be given to OpenVPN
+ pub fn config<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+ self.config = Some(path.as_ref().to_path_buf());
+ self
+ }
+
+ /// Executes the OpenVPN process as a child process, returning a handle to it.
+ pub fn spawn(&mut self) -> io::Result<Child> {
+ let mut command = self.create_command();
+ self.apply_settings(&mut command);
+ command.spawn()
+ }
+
+ fn create_command(&mut self) -> Command {
+ let mut command = Command::new(&self.openvpn_bin);
+ command.env_clear()
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null());
+ command
+ }
+
+ fn apply_settings(&self, command: &mut Command) {
+ if let Some(ref config) = self.config {
+ command.arg("--config").arg(config);
+ }
+ }
+}
diff --git a/tests/process.rs b/tests/process.rs
new file mode 100644
index 0000000000..2281a9d990
--- /dev/null
+++ b/tests/process.rs
@@ -0,0 +1,36 @@
+extern crate talpid_core;
+
+mod util;
+
+use talpid_core::process::OpenVpnBuilder;
+
+#[cfg(target_os = "linux")]
+#[test]
+fn check_test_environment() {
+ use std::env;
+ let test_threads = env::var("RUST_TEST_THREADS");
+ if !test_threads.is_ok() || test_threads.unwrap() != "1" {
+ panic!("Tests must be run with environment variable RUST_TEST_THREADS=1");
+ }
+}
+
+#[cfg(target_os = "linux")]
+#[test]
+fn openvpn_builder_starts_correct_process() {
+ let mut child = OpenVpnBuilder::new("echo").spawn().unwrap();
+ let args = util::read_args_for_proc(child.id());
+
+ assert_eq!(vec!["echo"], args);
+ child.kill().unwrap();
+}
+
+#[cfg(target_os = "linux")]
+#[test]
+fn openvpn_builder_passes_config() {
+ let config_path = "/path/to/config".to_owned();
+ let mut child = OpenVpnBuilder::new("echo").config(&config_path).spawn().unwrap();
+ let args = util::read_args_for_proc(child.id());
+
+ assert!(args.contains(&config_path));
+ child.kill().unwrap();
+}
diff --git a/tests/util.rs b/tests/util.rs
new file mode 100644
index 0000000000..8fe87e5783
--- /dev/null
+++ b/tests/util.rs
@@ -0,0 +1,16 @@
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
+
+pub fn read_file<P: AsRef<Path>>(path: P) -> String {
+ let mut string = String::new();
+ let mut f = File::open(path).unwrap();
+ f.read_to_string(&mut string).unwrap();
+ string
+}
+
+#[cfg(target_os = "linux")]
+pub fn read_args_for_proc(pid: u32) -> Vec<String> {
+ let cmdline = read_file(format!("/proc/{}/cmdline", pid));
+ cmdline.split_terminator('\0').map(String::from).collect()
+}