mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
fix(cli): ensure that pre- and post-test output is flushed at the appropriate times (#22611)
Some `deno_std` tests were failing to print output that was resolved after the last test finished. In addition, output printed before tests began would sometimes appear above the "running X tests ..." line, and sometimes below it depending on timing. We now guarantee that all output is flushed before and after tests run, making the output consistent. Pre-test and post-test output are captured in `------ pre-test output ------` and `------ post-test output ------` blocks to differentiate them from the regular output blocks. Here's an example of a test (that is much noisier than normal, but an example of what the output will look like): ``` Check ./load_unload.ts ------- pre-test output ------- load ----- output end ----- running 1 test from ./load_unload.ts test ... ------- output ------- test ----- output end ----- test ... ok ([WILDCARD]) ------- post-test output ------- unload ----- output end ----- ```
This commit is contained in:
parent
c9b2139b1e
commit
b6e44f91ad
14 changed files with 213 additions and 31 deletions
|
@ -397,6 +397,9 @@ impl TestRun {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
test::TestEvent::Completed => {
|
||||||
|
reporter.report_completed();
|
||||||
|
}
|
||||||
test::TestEvent::ForceEndReport => {}
|
test::TestEvent::ForceEndReport => {}
|
||||||
test::TestEvent::Sigint => {}
|
test::TestEvent::Sigint => {}
|
||||||
}
|
}
|
||||||
|
@ -742,6 +745,10 @@ impl LspTestReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_completed(&mut self) {
|
||||||
|
// there is nothing to do on report_completed
|
||||||
|
}
|
||||||
|
|
||||||
fn report_summary(
|
fn report_summary(
|
||||||
&mut self,
|
&mut self,
|
||||||
_summary: &test::TestSummary,
|
_summary: &test::TestSummary,
|
||||||
|
|
|
@ -384,6 +384,8 @@ impl TestEventSender {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::tools::test::TestResult;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use deno_core::unsync::spawn;
|
use deno_core::unsync::spawn;
|
||||||
use deno_core::unsync::spawn_blocking;
|
use deno_core::unsync::spawn_blocking;
|
||||||
|
@ -466,6 +468,75 @@ mod tests {
|
||||||
assert_eq!(messages.len(), 100000);
|
assert_eq!(messages.len(), 100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that large numbers of interleaved steps are routed properly.
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_interleave() {
|
||||||
|
test_util::timeout!(60);
|
||||||
|
const MESSAGE_COUNT: usize = 10_000;
|
||||||
|
let (mut worker, mut receiver) = create_single_test_event_channel();
|
||||||
|
let recv_handle = spawn(async move {
|
||||||
|
let mut i = 0;
|
||||||
|
while let Some((_, message)) = receiver.recv().await {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
let expected_text = format!("{:08x}", i / 2).into_bytes();
|
||||||
|
let TestEvent::Output(TestStdioStream::Stderr, text) = message else {
|
||||||
|
panic!("Incorrect message: {message:?}");
|
||||||
|
};
|
||||||
|
assert_eq!(text, expected_text);
|
||||||
|
} else {
|
||||||
|
let TestEvent::Result(index, TestResult::Ok, 0) = message else {
|
||||||
|
panic!("Incorrect message: {message:?}");
|
||||||
|
};
|
||||||
|
assert_eq!(index, i / 2);
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
eprintln!("Receiver closed");
|
||||||
|
i
|
||||||
|
});
|
||||||
|
let send_handle: deno_core::unsync::JoinHandle<()> =
|
||||||
|
spawn_blocking(move || {
|
||||||
|
for i in 0..MESSAGE_COUNT {
|
||||||
|
worker
|
||||||
|
.stderr
|
||||||
|
.write_all(format!("{i:08x}").as_str().as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
worker
|
||||||
|
.sender
|
||||||
|
.send(TestEvent::Result(i, TestResult::Ok, 0))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
eprintln!("Sent all messages");
|
||||||
|
});
|
||||||
|
send_handle.await.unwrap();
|
||||||
|
let messages = recv_handle.await.unwrap();
|
||||||
|
assert_eq!(messages, MESSAGE_COUNT * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sender_shutdown_before_receive() {
|
||||||
|
test_util::timeout!(60);
|
||||||
|
for _ in 0..10 {
|
||||||
|
let (mut worker, mut receiver) = create_single_test_event_channel();
|
||||||
|
worker.stderr.write_all(b"hello").unwrap();
|
||||||
|
worker
|
||||||
|
.sender
|
||||||
|
.send(TestEvent::Result(0, TestResult::Ok, 0))
|
||||||
|
.unwrap();
|
||||||
|
drop(worker);
|
||||||
|
let (_, message) = receiver.recv().await.unwrap();
|
||||||
|
let TestEvent::Output(TestStdioStream::Stderr, text) = message else {
|
||||||
|
panic!("Incorrect message: {message:?}");
|
||||||
|
};
|
||||||
|
assert_eq!(text.as_slice(), b"hello");
|
||||||
|
let (_, message) = receiver.recv().await.unwrap();
|
||||||
|
let TestEvent::Result(..) = message else {
|
||||||
|
panic!("Incorrect message: {message:?}");
|
||||||
|
};
|
||||||
|
assert!(receiver.recv().await.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Ensure nothing panics if we're racing the runtime shutdown.
|
/// Ensure nothing panics if we're racing the runtime shutdown.
|
||||||
#[test]
|
#[test]
|
||||||
fn test_runtime_shutdown() {
|
fn test_runtime_shutdown() {
|
||||||
|
|
|
@ -391,8 +391,14 @@ pub enum TestEvent {
|
||||||
StepRegister(TestStepDescription),
|
StepRegister(TestStepDescription),
|
||||||
StepWait(usize),
|
StepWait(usize),
|
||||||
StepResult(usize, TestStepResult, u64),
|
StepResult(usize, TestStepResult, u64),
|
||||||
ForceEndReport,
|
/// Indicates that this worker has completed.
|
||||||
|
Completed,
|
||||||
|
/// Indicates that the user has cancelled the test run with Ctrl+C and
|
||||||
|
/// the run should be aborted.
|
||||||
Sigint,
|
Sigint,
|
||||||
|
/// Used by the REPL to force a report to end without closing the worker
|
||||||
|
/// or receiver.
|
||||||
|
ForceEndReport,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestEvent {
|
impl TestEvent {
|
||||||
|
@ -401,11 +407,13 @@ impl TestEvent {
|
||||||
pub fn requires_stdio_sync(&self) -> bool {
|
pub fn requires_stdio_sync(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
TestEvent::Result(..)
|
TestEvent::Plan(..)
|
||||||
|
| TestEvent::Result(..)
|
||||||
| TestEvent::StepWait(..)
|
| TestEvent::StepWait(..)
|
||||||
| TestEvent::StepResult(..)
|
| TestEvent::StepResult(..)
|
||||||
| TestEvent::UncaughtError(..)
|
| TestEvent::UncaughtError(..)
|
||||||
| TestEvent::ForceEndReport
|
| TestEvent::ForceEndReport
|
||||||
|
| TestEvent::Completed
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,24 +649,64 @@ pub async fn run_tests_for_worker(
|
||||||
};
|
};
|
||||||
let tests: Arc<TestDescriptions> = tests.into();
|
let tests: Arc<TestDescriptions> = tests.into();
|
||||||
sender.send(TestEvent::Register(tests.clone()))?;
|
sender.send(TestEvent::Register(tests.clone()))?;
|
||||||
|
let res = run_tests_for_worker_inner(
|
||||||
|
worker,
|
||||||
|
specifier,
|
||||||
|
tests,
|
||||||
|
test_functions,
|
||||||
|
&mut sender,
|
||||||
|
options,
|
||||||
|
fail_fast_tracker,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
_ = sender.send(TestEvent::Completed);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_tests_for_worker_inner(
|
||||||
|
worker: &mut MainWorker,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
tests: Arc<TestDescriptions>,
|
||||||
|
test_functions: Vec<v8::Global<v8::Function>>,
|
||||||
|
sender: &mut TestEventSender,
|
||||||
|
options: &TestSpecifierOptions,
|
||||||
|
fail_fast_tracker: &FailFastTracker,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
let unfiltered = tests.len();
|
let unfiltered = tests.len();
|
||||||
let tests = tests
|
|
||||||
.into_iter()
|
// Build the test plan in a single pass
|
||||||
.filter(|(_, d)| options.filter.includes(&d.name))
|
let mut tests_to_run = Vec::with_capacity(tests.len());
|
||||||
.collect::<Vec<_>>();
|
let mut used_only = false;
|
||||||
let (only, no_only): (Vec<_>, Vec<_>) =
|
for ((_, d), f) in tests.tests.iter().zip(test_functions) {
|
||||||
tests.into_iter().partition(|(_, d)| d.only);
|
if !options.filter.includes(&d.name) {
|
||||||
let used_only = !only.is_empty();
|
continue;
|
||||||
let mut tests = if used_only { only } else { no_only };
|
}
|
||||||
if let Some(seed) = options.shuffle {
|
|
||||||
tests.shuffle(&mut SmallRng::seed_from_u64(seed));
|
// If we've seen an "only: true" test, the remaining tests must be "only: true" to be added
|
||||||
|
if used_only && !d.only {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the first "only: true" test we've seen, clear the other tests since they were
|
||||||
|
// only: false.
|
||||||
|
if d.only && !used_only {
|
||||||
|
used_only = true;
|
||||||
|
tests_to_run.clear();
|
||||||
|
}
|
||||||
|
tests_to_run.push((d, f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(seed) = options.shuffle {
|
||||||
|
tests_to_run.shuffle(&mut SmallRng::seed_from_u64(seed));
|
||||||
|
}
|
||||||
|
|
||||||
sender.send(TestEvent::Plan(TestPlan {
|
sender.send(TestEvent::Plan(TestPlan {
|
||||||
origin: specifier.to_string(),
|
origin: specifier.to_string(),
|
||||||
total: tests.len(),
|
total: tests_to_run.len(),
|
||||||
filtered_out: unfiltered - tests.len(),
|
filtered_out: unfiltered - tests_to_run.len(),
|
||||||
used_only,
|
used_only,
|
||||||
}))?;
|
}))?;
|
||||||
|
|
||||||
let mut had_uncaught_error = false;
|
let mut had_uncaught_error = false;
|
||||||
let stats = worker.js_runtime.runtime_activity_stats_factory();
|
let stats = worker.js_runtime.runtime_activity_stats_factory();
|
||||||
let ops = worker.js_runtime.op_names();
|
let ops = worker.js_runtime.op_names();
|
||||||
|
@ -683,7 +731,7 @@ pub async fn run_tests_for_worker(
|
||||||
filter = filter.omit_op(op_id_host_recv_ctrl as _);
|
filter = filter.omit_op(op_id_host_recv_ctrl as _);
|
||||||
filter = filter.omit_op(op_id_host_recv_message as _);
|
filter = filter.omit_op(op_id_host_recv_message as _);
|
||||||
|
|
||||||
for ((_, desc), function) in tests.into_iter().zip(test_functions) {
|
for (desc, function) in tests_to_run.into_iter() {
|
||||||
if fail_fast_tracker.should_stop() {
|
if fail_fast_tracker.should_stop() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1254,6 +1302,9 @@ pub async fn report_tests(
|
||||||
TestEvent::ForceEndReport => {
|
TestEvent::ForceEndReport => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
TestEvent::Completed => {
|
||||||
|
reporter.report_completed();
|
||||||
|
}
|
||||||
TestEvent::Sigint => {
|
TestEvent::Sigint => {
|
||||||
let elapsed = start_time
|
let elapsed = start_time
|
||||||
.map(|t| Instant::now().duration_since(t))
|
.map(|t| Instant::now().duration_since(t))
|
||||||
|
|
|
@ -101,6 +101,12 @@ impl TestReporter for CompoundTestReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_completed(&mut self) {
|
||||||
|
for reporter in &mut self.test_reporters {
|
||||||
|
reporter.report_completed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn flush_report(
|
fn flush_report(
|
||||||
&mut self,
|
&mut self,
|
||||||
elapsed: &Duration,
|
elapsed: &Duration,
|
||||||
|
|
|
@ -206,6 +206,8 @@ impl TestReporter for DotTestReporter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_completed(&mut self) {}
|
||||||
|
|
||||||
fn flush_report(
|
fn flush_report(
|
||||||
&mut self,
|
&mut self,
|
||||||
_elapsed: &Duration,
|
_elapsed: &Duration,
|
||||||
|
|
|
@ -158,6 +158,11 @@ impl TestReporter for JunitTestReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_completed(&mut self) {
|
||||||
|
// TODO(mmastrac): This reporter does not handle stdout/stderr yet, and when we do, we may need to redirect
|
||||||
|
// pre-and-post-test output somewhere.
|
||||||
|
}
|
||||||
|
|
||||||
fn flush_report(
|
fn flush_report(
|
||||||
&mut self,
|
&mut self,
|
||||||
elapsed: &Duration,
|
elapsed: &Duration,
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub trait TestReporter {
|
||||||
tests: &IndexMap<usize, TestDescription>,
|
tests: &IndexMap<usize, TestDescription>,
|
||||||
test_steps: &IndexMap<usize, TestStepDescription>,
|
test_steps: &IndexMap<usize, TestStepDescription>,
|
||||||
);
|
);
|
||||||
|
fn report_completed(&mut self);
|
||||||
fn flush_report(
|
fn flush_report(
|
||||||
&mut self,
|
&mut self,
|
||||||
elapsed: &Duration,
|
elapsed: &Duration,
|
||||||
|
|
|
@ -8,12 +8,14 @@ pub struct PrettyTestReporter {
|
||||||
parallel: bool,
|
parallel: bool,
|
||||||
echo_output: bool,
|
echo_output: bool,
|
||||||
in_new_line: bool,
|
in_new_line: bool,
|
||||||
|
phase: &'static str,
|
||||||
filter: bool,
|
filter: bool,
|
||||||
repl: bool,
|
repl: bool,
|
||||||
scope_test_id: Option<usize>,
|
scope_test_id: Option<usize>,
|
||||||
cwd: Url,
|
cwd: Url,
|
||||||
did_have_user_output: bool,
|
did_have_user_output: bool,
|
||||||
started_tests: bool,
|
started_tests: bool,
|
||||||
|
ended_tests: bool,
|
||||||
child_results_buffer:
|
child_results_buffer:
|
||||||
HashMap<usize, IndexMap<usize, (TestStepDescription, TestStepResult, u64)>>,
|
HashMap<usize, IndexMap<usize, (TestStepDescription, TestStepResult, u64)>>,
|
||||||
summary: TestSummary,
|
summary: TestSummary,
|
||||||
|
@ -31,12 +33,14 @@ impl PrettyTestReporter {
|
||||||
parallel,
|
parallel,
|
||||||
echo_output,
|
echo_output,
|
||||||
in_new_line: true,
|
in_new_line: true,
|
||||||
|
phase: "",
|
||||||
filter,
|
filter,
|
||||||
repl,
|
repl,
|
||||||
scope_test_id: None,
|
scope_test_id: None,
|
||||||
cwd: Url::from_directory_path(std::env::current_dir().unwrap()).unwrap(),
|
cwd: Url::from_directory_path(std::env::current_dir().unwrap()).unwrap(),
|
||||||
did_have_user_output: false,
|
did_have_user_output: false,
|
||||||
started_tests: false,
|
started_tests: false,
|
||||||
|
ended_tests: false,
|
||||||
child_results_buffer: Default::default(),
|
child_results_buffer: Default::default(),
|
||||||
summary: TestSummary::new(),
|
summary: TestSummary::new(),
|
||||||
writer: Box::new(std::io::stdout()),
|
writer: Box::new(std::io::stdout()),
|
||||||
|
@ -149,7 +153,7 @@ impl PrettyTestReporter {
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut self.writer,
|
&mut self.writer,
|
||||||
"{}",
|
"{}",
|
||||||
colors::gray("----- output end -----")
|
colors::gray(format!("----- {}output end -----", self.phase))
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.in_new_line = true;
|
self.in_new_line = true;
|
||||||
|
@ -161,6 +165,7 @@ impl PrettyTestReporter {
|
||||||
impl TestReporter for PrettyTestReporter {
|
impl TestReporter for PrettyTestReporter {
|
||||||
fn report_register(&mut self, _description: &TestDescription) {}
|
fn report_register(&mut self, _description: &TestDescription) {}
|
||||||
fn report_plan(&mut self, plan: &TestPlan) {
|
fn report_plan(&mut self, plan: &TestPlan) {
|
||||||
|
self.write_output_end();
|
||||||
self.summary.total += plan.total;
|
self.summary.total += plan.total;
|
||||||
self.summary.filtered_out += plan.filtered_out;
|
self.summary.filtered_out += plan.filtered_out;
|
||||||
if self.repl {
|
if self.repl {
|
||||||
|
@ -196,15 +201,22 @@ impl TestReporter for PrettyTestReporter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.did_have_user_output && self.started_tests {
|
if !self.did_have_user_output {
|
||||||
self.did_have_user_output = true;
|
self.did_have_user_output = true;
|
||||||
if !self.in_new_line {
|
if !self.in_new_line {
|
||||||
writeln!(&mut self.writer).unwrap();
|
writeln!(&mut self.writer).unwrap();
|
||||||
}
|
}
|
||||||
|
self.phase = if !self.started_tests {
|
||||||
|
"pre-test "
|
||||||
|
} else if self.ended_tests {
|
||||||
|
"post-test "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
writeln!(
|
writeln!(
|
||||||
&mut self.writer,
|
&mut self.writer,
|
||||||
"{}",
|
"{}",
|
||||||
colors::gray("------- output -------")
|
colors::gray(format!("------- {}output -------", self.phase))
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.in_new_line = true;
|
self.in_new_line = true;
|
||||||
|
@ -369,6 +381,7 @@ impl TestReporter for PrettyTestReporter {
|
||||||
_tests: &IndexMap<usize, TestDescription>,
|
_tests: &IndexMap<usize, TestDescription>,
|
||||||
_test_steps: &IndexMap<usize, TestStepDescription>,
|
_test_steps: &IndexMap<usize, TestStepDescription>,
|
||||||
) {
|
) {
|
||||||
|
self.write_output_end();
|
||||||
common::report_summary(&mut self.writer, &self.cwd, &self.summary, elapsed);
|
common::report_summary(&mut self.writer, &self.cwd, &self.summary, elapsed);
|
||||||
if !self.repl {
|
if !self.repl {
|
||||||
writeln!(&mut self.writer).unwrap();
|
writeln!(&mut self.writer).unwrap();
|
||||||
|
@ -392,6 +405,11 @@ impl TestReporter for PrettyTestReporter {
|
||||||
self.in_new_line = true;
|
self.in_new_line = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_completed(&mut self) {
|
||||||
|
self.write_output_end();
|
||||||
|
self.ended_tests = true;
|
||||||
|
}
|
||||||
|
|
||||||
fn flush_report(
|
fn flush_report(
|
||||||
&mut self,
|
&mut self,
|
||||||
_elapsed: &Duration,
|
_elapsed: &Duration,
|
||||||
|
|
|
@ -236,6 +236,8 @@ impl TestReporter for TapTestReporter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_completed(&mut self) {}
|
||||||
|
|
||||||
fn flush_report(
|
fn flush_report(
|
||||||
&mut self,
|
&mut self,
|
||||||
_elapsed: &Duration,
|
_elapsed: &Duration,
|
||||||
|
|
|
@ -4560,15 +4560,14 @@ async fn websocket_server_multi_field_connection_header() {
|
||||||
assert!(child.wait().unwrap().success());
|
assert!(child.wait().unwrap().success());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bartlomieju): this should use `deno run`, not `deno test`; but the
|
|
||||||
// test hangs then. https://github.com/denoland/deno/issues/14283
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn websocket_server_idletimeout() {
|
async fn websocket_server_idletimeout() {
|
||||||
|
test_util::timeout!(60);
|
||||||
let script =
|
let script =
|
||||||
util::testdata_path().join("run/websocket_server_idletimeout.ts");
|
util::testdata_path().join("run/websocket_server_idletimeout.ts");
|
||||||
let root_ca = util::testdata_path().join("tls/RootCA.pem");
|
let root_ca = util::testdata_path().join("tls/RootCA.pem");
|
||||||
let mut child = util::deno_cmd()
|
let mut child = util::deno_cmd()
|
||||||
.arg("test")
|
.arg("run")
|
||||||
.arg("--unstable")
|
.arg("--unstable")
|
||||||
.arg("--allow-net")
|
.arg("--allow-net")
|
||||||
.arg("--cert")
|
.arg("--cert")
|
||||||
|
@ -4579,11 +4578,13 @@ async fn websocket_server_idletimeout() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let stdout = child.stdout.as_mut().unwrap();
|
let stdout = child.stdout.as_mut().unwrap();
|
||||||
let mut buffer = [0; 5];
|
let mut buf: Vec<u8> = vec![];
|
||||||
let read = stdout.read(&mut buffer).unwrap();
|
while !String::from_utf8(buf.clone()).unwrap().contains("READY") {
|
||||||
assert_eq!(read, 5);
|
let mut buffer = [0; 64];
|
||||||
let msg = std::str::from_utf8(&buffer).unwrap();
|
let read = stdout.read(&mut buffer).unwrap();
|
||||||
assert_eq!(msg, "READY");
|
buf.extend_from_slice(&buffer[0..read]);
|
||||||
|
eprintln!("buf = {buf:?}");
|
||||||
|
}
|
||||||
|
|
||||||
let stream = tokio::net::TcpStream::connect("localhost:4509")
|
let stream = tokio::net::TcpStream::connect("localhost:4509")
|
||||||
.await
|
.await
|
||||||
|
@ -4604,8 +4605,7 @@ async fn websocket_server_idletimeout() {
|
||||||
fastwebsockets::handshake::client(&SpawnExecutor, req, stream)
|
fastwebsockets::handshake::client(&SpawnExecutor, req, stream)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
assert_eq!(child.wait().unwrap().code(), Some(123));
|
||||||
assert!(child.wait().unwrap().success());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itest!(auto_discover_lockfile {
|
itest!(auto_discover_lockfile {
|
||||||
|
|
|
@ -11,10 +11,12 @@ const { response, socket } = Deno.upgradeWebSocket(request, {
|
||||||
idleTimeout: 1,
|
idleTimeout: 1,
|
||||||
});
|
});
|
||||||
socket.onerror = (e) => {
|
socket.onerror = (e) => {
|
||||||
|
console.log(e);
|
||||||
assertEquals((e as ErrorEvent).message, "No response from ping frame.");
|
assertEquals((e as ErrorEvent).message, "No response from ping frame.");
|
||||||
errorDeferred.resolve();
|
errorDeferred.resolve();
|
||||||
};
|
};
|
||||||
socket.onclose = (e) => {
|
socket.onclose = (e) => {
|
||||||
|
console.log(e);
|
||||||
assertEquals(e.reason, "No response from ping frame.");
|
assertEquals(e.reason, "No response from ping frame.");
|
||||||
closeDeferred.resolve();
|
closeDeferred.resolve();
|
||||||
};
|
};
|
||||||
|
@ -22,4 +24,6 @@ await respondWith(response);
|
||||||
|
|
||||||
await errorDeferred.promise;
|
await errorDeferred.promise;
|
||||||
await closeDeferred.promise;
|
await closeDeferred.promise;
|
||||||
listener.close();
|
|
||||||
|
// TODO(mmastrac): this doesn't exit on its own. Why?
|
||||||
|
Deno.exit(123);
|
||||||
|
|
14
tests/testdata/test/load_unload.out
vendored
14
tests/testdata/test/load_unload.out
vendored
|
@ -1,6 +1,16 @@
|
||||||
Check [WILDCARD]/test/load_unload.ts
|
Check [WILDCARD]/load_unload.ts
|
||||||
running 1 test from ./test/load_unload.ts
|
------- pre-test output -------
|
||||||
|
load
|
||||||
|
----- pre-test output end -----
|
||||||
|
running 1 test from [WILDCARD]/load_unload.ts
|
||||||
|
test ...
|
||||||
|
------- output -------
|
||||||
|
test
|
||||||
|
----- output end -----
|
||||||
test ... ok ([WILDCARD])
|
test ... ok ([WILDCARD])
|
||||||
|
------- post-test output -------
|
||||||
|
unload
|
||||||
|
----- post-test output end -----
|
||||||
|
|
||||||
ok | 1 passed | 0 failed ([WILDCARD])
|
ok | 1 passed | 0 failed ([WILDCARD])
|
||||||
|
|
||||||
|
|
3
tests/testdata/test/load_unload.ts
vendored
3
tests/testdata/test/load_unload.ts
vendored
|
@ -4,6 +4,7 @@ addEventListener("load", () => {
|
||||||
throw new Error("Interval is already set");
|
throw new Error("Interval is already set");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("load");
|
||||||
interval = setInterval(() => {}, 0);
|
interval = setInterval(() => {}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -12,10 +13,12 @@ addEventListener("unload", () => {
|
||||||
throw new Error("Interval was not set");
|
throw new Error("Interval was not set");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("unload");
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("test", () => {
|
Deno.test("test", () => {
|
||||||
|
console.log("test");
|
||||||
if (!interval) {
|
if (!interval) {
|
||||||
throw new Error("Interval was not set");
|
throw new Error("Interval was not set");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,9 @@ macro_rules! timeout {
|
||||||
let timeout = *timeout.get(0).unwrap_or(&300);
|
let timeout = *timeout.get(0).unwrap_or(&300);
|
||||||
::std::thread::spawn(move || {
|
::std::thread::spawn(move || {
|
||||||
if rx.recv_timeout(::std::time::Duration::from_secs(timeout)) == Err(::std::sync::mpsc::RecvTimeoutError::Timeout) {
|
if rx.recv_timeout(::std::time::Duration::from_secs(timeout)) == Err(::std::sync::mpsc::RecvTimeoutError::Timeout) {
|
||||||
|
use std::io::Write;
|
||||||
eprintln!("Test {function} timed out after {timeout} seconds, aborting");
|
eprintln!("Test {function} timed out after {timeout} seconds, aborting");
|
||||||
|
_ = std::io::stderr().flush();
|
||||||
::std::process::exit(1);
|
::std::process::exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue