summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2023-04-12 23:51:04 +0100
committerGitHub <noreply@github.com>2023-04-13 00:51:04 +0200
commitd97f9d22b3873b89019a0fea67b83ed7cac8bd69 (patch)
tree4133837dd7dcb509e4a08158bf36ea5b38a93a5a
parent17e4782140a602043c4f92e643c1908c521ae017 (diff)
fix(test): add process sigint handler for --watch (#18678)
Fixes #18676.
-rw-r--r--cli/tests/integration/watcher_tests.rs29
-rw-r--r--cli/tools/test.rs19
2 files changed, 48 insertions, 0 deletions
diff --git a/cli/tests/integration/watcher_tests.rs b/cli/tests/integration/watcher_tests.rs
index 58b703701..407a63f6c 100644
--- a/cli/tests/integration/watcher_tests.rs
+++ b/cli/tests/integration/watcher_tests.rs
@@ -1122,6 +1122,35 @@ fn test_watch_unload_handler_error_on_drop() {
check_alive_then_kill(child);
}
+#[cfg(unix)]
+#[test]
+fn test_watch_sigint() {
+ use nix::sys::signal;
+ use nix::sys::signal::Signal;
+ use nix::unistd::Pid;
+
+ let t = TempDir::new();
+ let file_to_watch = t.path().join("file_to_watch.js");
+ write(&file_to_watch, r#"Deno.test("foo", () => {});"#).unwrap();
+ let mut child = util::deno_cmd()
+ .current_dir(util::testdata_path())
+ .arg("test")
+ .arg("--watch")
+ .arg(&file_to_watch)
+ .env("NO_COLOR", "1")
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped())
+ .spawn()
+ .unwrap();
+ let (mut stdout_lines, mut stderr_lines) = child_lines(&mut child);
+ wait_contains("Test started", &mut stderr_lines);
+ wait_contains("ok | 1 passed | 0 failed", &mut stdout_lines);
+ wait_contains("Test finished", &mut stderr_lines);
+ signal::kill(Pid::from_raw(child.id() as i32), Signal::SIGINT).unwrap();
+ let exit_status = child.wait().unwrap();
+ assert_eq!(exit_status.code(), Some(130));
+}
+
// Regression test for https://github.com/denoland/deno/issues/15465.
#[test]
fn run_watch_reload_once() {
diff --git a/cli/tools/test.rs b/cli/tools/test.rs
index 87cb3c5e3..ce99a6edc 100644
--- a/cli/tools/test.rs
+++ b/cli/tools/test.rs
@@ -57,7 +57,9 @@ use std::io::Write;
use std::num::NonZeroUsize;
use std::path::Path;
use std::path::PathBuf;
+use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
@@ -1174,6 +1176,8 @@ pub async fn check_specifiers(
Ok(())
}
+static HAS_TEST_RUN_SIGINT_HANDLER: AtomicBool = AtomicBool::new(false);
+
/// Test a collection of specifiers with test modes concurrently.
async fn test_specifiers(
ps: &ProcState,
@@ -1201,6 +1205,7 @@ async fn test_specifiers(
signal::ctrl_c().await.unwrap();
sender_.upgrade().map(|s| s.send(TestEvent::Sigint).ok());
});
+ HAS_TEST_RUN_SIGINT_HANDLER.store(true, Ordering::Relaxed);
let join_handles =
specifiers_with_mode
@@ -1388,6 +1393,7 @@ async fn test_specifiers(
}
sigint_handler_handle.abort();
+ HAS_TEST_RUN_SIGINT_HANDLER.store(false, Ordering::Relaxed);
let elapsed = Instant::now().duration_since(earlier);
reporter.report_summary(&summary, &elapsed);
@@ -1736,6 +1742,19 @@ pub async fn run_tests_with_watch(
}
};
+ // On top of the sigint handlers which are added and unbound for each test
+ // run, a process-scoped basic exit handler is required due to a tokio
+ // limitation where it doesn't unbind its own handler for the entire process
+ // once a user adds one.
+ tokio::task::spawn(async move {
+ loop {
+ signal::ctrl_c().await.unwrap();
+ if !HAS_TEST_RUN_SIGINT_HANDLER.load(Ordering::Relaxed) {
+ std::process::exit(130);
+ }
+ }
+ });
+
let clear_screen = !ps.borrow().options.no_clear_screen();
file_watcher::watch_func(
resolver,