summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--talpid-core/Cargo.toml4
-rw-r--r--talpid-core/src/split_tunnel/macos/process.rs73
2 files changed, 63 insertions, 14 deletions
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml
index 7ec3fd20f2..0cc71a4399 100644
--- a/talpid-core/Cargo.toml
+++ b/talpid-core/Cargo.toml
@@ -103,3 +103,7 @@ features = [
[build-dependencies]
tonic-build = { workspace = true, default-features = false, features = ["transport", "prost"] }
+
+
+[dev-dependencies]
+tokio = { workspace = true, features = [ "io-util", "test-util", "time" ] }
diff --git a/talpid-core/src/split_tunnel/macos/process.rs b/talpid-core/src/split_tunnel/macos/process.rs
index 49ae0fd740..05f83b2497 100644
--- a/talpid-core/src/split_tunnel/macos/process.rs
+++ b/talpid-core/src/split_tunnel/macos/process.rs
@@ -553,8 +553,28 @@ fn check_os_version_support_inner(version: MacosVersion) -> Result<(), Error> {
#[cfg(test)]
mod test {
- use super::{check_os_version_support_inner, parse_logger_status, NeedFda, MIN_OS_VERSION};
+ use super::*;
+
+ use std::time::Duration;
use talpid_platform_metadata::MacosVersion;
+ use tokio::io::{simplex, AsyncWriteExt};
+
+ /// A mock-version of std{out,err}. [tokio::io::SimplexStream] implements [AsyncRead], so it can be used to test
+ /// [parse_logger_status].
+ fn output(msg: &'static str, lag: Duration) -> impl AsyncRead + Unpin + Send + 'static {
+ // Ensure that 'msg' contains a newline to prevent user errors
+ assert!(
+ msg.contains('\n'),
+ "Message does not contain a newline!! Make sure to add a newline to '{msg}'"
+ );
+ let (stdout_read, mut stdout_write) = simplex(msg.as_bytes().len());
+ // "print" to "stdout" after `duration`.
+ tokio::spawn(async move {
+ tokio::time::sleep(lag).await;
+ stdout_write.write_all(msg.as_bytes()).await.unwrap();
+ });
+ stdout_read
+ }
#[test]
fn test_min_os_version() {
@@ -589,10 +609,10 @@ mod test {
);
}
- /// If the check times out and 'ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED' is not in stderr, assume
- /// full-disk access is available.
+ /// If process exits without 'ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED', assume full-disk access
+ /// is available.
#[tokio::test]
- async fn test_parse_logger_status_timeout() {
+ async fn test_parse_logger_status_immediate_exit() {
let need_fda = parse_logger_status(
b"nothing to see here\n".as_slice(),
b"nothing to see here\n".as_slice(),
@@ -602,24 +622,49 @@ mod test {
assert_eq!(
need_fda,
NeedFda::No,
- "expected 'NeedFda::No' when ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED wasn't present"
+ "expected 'NeedFda::No' on immediate exit",
);
}
- /// If process exits without 'ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED', assume full-disk access
- /// is available.
+ /// Check that [parse_logger_status] returns within a reasonable timeframe.
+ /// "Reasonable" being within [EARLY_FAIL_TIMEOUT].
+ #[tokio::test(start_paused = true)]
+ async fn test_parse_logger_status_responsive() {
+ let start = tokio::time::Instant::now();
+ let stdout = output("This will never be printed\n", Duration::MAX);
+ let stderr = output(
+ "ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED\n",
+ EARLY_FAIL_TIMEOUT / 2,
+ );
+ tokio::time::resume();
+
+ let need_fda = parse_logger_status(stdout, stderr).await;
+
+ tokio::time::pause();
+
+ assert_eq!(
+ need_fda,
+ NeedFda::Yes,
+ "expected 'NeedFda::Yes' when ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED was eventually printed to stderr"
+ );
+
+ // Assert that we did not spend more time waiting than we should
+ assert!(start.elapsed() < EARLY_FAIL_TIMEOUT);
+ }
+
+ /// Check that [parse_logger_status] doesn't get stuck because nothing is ever output
+ /// to std{out,err}. It should time out with the assumption that full-disk access is available.
#[tokio::test]
- async fn test_parse_logger_status_immediate_exit() {
- let need_fda = parse_logger_status(
- b"nothing to see here\n".as_slice(),
- b"nothing to see here\n".as_slice(),
- )
- .await;
+ async fn test_parse_logger_status_timeout() {
+ let stdout = output("This will never be printed\n", Duration::MAX);
+ let stderr = output("This will never be printed\n", Duration::MAX);
+
+ let need_fda = parse_logger_status(stdout, stderr).await;
assert_eq!(
need_fda,
NeedFda::No,
- "expected 'NeedFda::No' on immediate exit",
+ "expected 'NeedFda::No' when nothing was ever printed to stdout or stderr"
);
}
}