Skip to content

Commit 94c4755

Browse files
committed
test: add waitUntil non-blocking response test
Verify that HTTP response arrives immediately even when waitUntil schedules a 200ms timer. Also fix unused variable warning in limiter test.
1 parent c56155e commit 94c4755

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

src/ops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ mod tests {
743743
#[test]
744744
fn test_update_request_creates_fresh_limiters() {
745745
let ops = RunnerOperations::new();
746-
let (tx_a, _rx_a) = std::sync::mpsc::channel::<LogEvent>();
746+
let (_tx_a, _rx_a) = std::sync::mpsc::channel::<LogEvent>();
747747
let (tx_b, _rx_b) = std::sync::mpsc::channel::<LogEvent>();
748748

749749
// Request A grabs its limiters and simulates some usage

tests/worker_handlers_test.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
use openworkers_core::{Event, HttpMethod, HttpRequest, RequestBody, Script};
2222
use openworkers_runtime_v8::Worker;
2323
use std::collections::HashMap;
24-
use std::time::Duration;
24+
use std::time::{Duration, Instant};
2525

2626
/// Helper to run async tests in a LocalSet (required for tokio spawn_local)
2727
async fn run_local<F, Fut, T>(f: F) -> T
@@ -580,3 +580,76 @@ async fn test_export_as_default_bundler_pattern_transformed() {
580580
})
581581
.await;
582582
}
583+
584+
// =============================================================================
585+
// waitUntil tests
586+
// =============================================================================
587+
588+
/// waitUntil should NOT block the response or exec() completion.
589+
///
590+
/// The handler sends a response immediately, then calls waitUntil with a 200ms
591+
/// delayed promise. exec() should return as soon as the response is ready,
592+
/// NOT after the waitUntil promise resolves.
593+
///
594+
/// Verify that the HTTP response is sent to the client immediately,
595+
/// WITHOUT waiting for waitUntil promises to resolve.
596+
///
597+
/// The worker's waitUntil schedules a 200ms timer. The response should
598+
/// arrive well before that. exec() itself will block (Worker pumps V8
599+
/// microtasks via FullyComplete), but from the HTTP client's perspective,
600+
/// the response is not delayed by waitUntil — that's the important invariant.
601+
#[tokio::test]
602+
async fn test_wait_until_does_not_block_response() {
603+
run_local(|| async {
604+
let script = Script::new(
605+
r#"
606+
addEventListener('fetch', (event) => {
607+
event.respondWith(new Response('ok'));
608+
event.waitUntil(new Promise(resolve => setTimeout(resolve, 200)));
609+
});
610+
"#,
611+
);
612+
613+
let mut worker = Worker::new(script, None)
614+
.await
615+
.expect("Worker should initialize");
616+
617+
let (task, rx) = Event::fetch(make_request());
618+
619+
let start = Instant::now();
620+
621+
// Run exec in background — it will block for ~200ms (Worker uses FullyComplete
622+
// to pump V8 microtasks), but the response is sent before that.
623+
let exec_handle = tokio::task::spawn_local(async move { worker.exec(task).await });
624+
625+
// Response should arrive quickly (before waitUntil's 200ms timer)
626+
let response = tokio::time::timeout(Duration::from_millis(100), rx)
627+
.await
628+
.expect("Response should arrive before waitUntil completes")
629+
.expect("Should get response");
630+
631+
let response_time = start.elapsed();
632+
assert_eq!(response.status, 200);
633+
634+
// The response must arrive well before the 200ms waitUntil timer
635+
assert!(
636+
response_time < Duration::from_millis(100),
637+
"Response should arrive before waitUntil (200ms), took {:?}",
638+
response_time
639+
);
640+
641+
// exec() will block until waitUntil completes (Worker uses FullyComplete)
642+
// This is expected — Worker is oneshot, so pumping V8 is fine.
643+
// For warm reuse (ExecutionContext), StreamsComplete returns earlier.
644+
let exec_result = exec_handle.await.unwrap();
645+
exec_result.expect("exec should succeed");
646+
647+
let exec_time = start.elapsed();
648+
649+
eprintln!(
650+
"Response arrived in {:?}, exec completed in {:?}",
651+
response_time, exec_time
652+
);
653+
})
654+
.await;
655+
}

0 commit comments

Comments
 (0)