Skip to content

Commit

Permalink
WIP Implement more tests for FDA check
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusPettersson98 committed Dec 13, 2024
1 parent df24377 commit d9f663e
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 5 deletions.
4 changes: 4 additions & 0 deletions talpid-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ] }
84 changes: 79 additions & 5 deletions talpid-core/src/split_tunnel/macos/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ async fn parse_logger_status(
// Received output, but not an err
NeedFda::No
}
// Timed out while checking for full-disk access
// FIXME: I have to add this for the next select to work ..?
_ = tokio::time::sleep(EARLY_FAIL_TIMEOUT) => NeedFda::No,
}
});

Expand Down Expand Up @@ -564,12 +567,62 @@ 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, EARLY_FAIL_TIMEOUT,
MIN_OS_VERSION,
};
use std::{process::ExitStatus, time::Duration};
use super::*;

use std::{pin::Pin, process::ExitStatus, time::Duration};

use talpid_platform_metadata::MacosVersion;
use tokio::io::{simplex, AsyncWriteExt, ReadHalf, SimplexStream};

/// A mock-version of stdout. [SimplexStream] implements [AsyncRead], so it can be used to test
/// [parse_logger_status].
struct MockStdout {
stdout: Pin<Box<ReadHalf<SimplexStream>>>,
lag: Pin<Box<tokio::time::Sleep>>,
}

impl MockStdout {
async fn new(msg: &str) -> Self {
// 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 = {
let (read_half, mut write_half) = simplex(msg.as_bytes().len());
write_half.write_all(msg.as_bytes()).await.unwrap();
Box::pin(read_half)
};

let lag = Box::pin(tokio::time::sleep(Duration::ZERO));

Self { stdout, lag }
}

/// "print" to "stdout" after `duration`.
fn delay(self, until: Duration) -> Self {
drop(self.lag);
let lag = Box::pin(tokio::time::sleep(until));
Self { lag, ..self }
}
}

impl AsyncRead for MockStdout {
fn poll_read(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> std::task::Poll<io::Result<()>> {
use std::task::Poll;
// Wait for the deadline to be exceeded
match self.lag.as_mut().poll(cx) {
Poll::Pending => Poll::Pending,
// When the deadline has passed, we can start "reading" from "stdout"
Poll::Ready(_) => self.stdout.as_mut().poll_read(cx, buf),
}
}
}

#[test]
fn test_min_os_version() {
Expand Down Expand Up @@ -643,4 +696,25 @@ mod test {
"expected 'NeedFda::No' on immediate exit",
);
}

/// Check that [parse_logger_status] doesn't get stuck because nothing is ever output
/// to stdout.
#[tokio::test]
async fn test_parse_logger_status_hogged() {
let stdout = MockStdout::new("This will never be printed\n")
.await
.delay(Duration::MAX);
let stderr = MockStdout::new("This will never be printed\n")
.await
.delay(Duration::MAX);

let need_fda =
parse_logger_status(async { Ok(ExitStatus::default()) }, stdout, stderr).await;

assert_eq!(
need_fda,
NeedFda::No,
"expected 'NeedFda::No' when nothing was ever printed to stdout or stderr"
);
}
}

0 comments on commit d9f663e

Please sign in to comment.