From e23e5deffad50468ca7fa86af83ba60a7706b58d Mon Sep 17 00:00:00 2001 From: ldm0 Date: Sat, 25 Jul 2026 09:07:26 +0800 Subject: [PATCH] test(lifecycle): gate post-DCL script load deterministically --- moli-core/tests/fetch_behaviors.rs | 5 ++- ..._in_order_load_after_domcontentloaded.html | 7 ++- moli-test-support/src/routes_core.rs | 43 +++++++++++++++++++ moli-test-support/src/server.rs | 6 +++ moli-test-support/src/server_routes.rs | 8 ++++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/moli-core/tests/fetch_behaviors.rs b/moli-core/tests/fetch_behaviors.rs index 7181aa9b99..2e7ee0d938 100644 --- a/moli-core/tests/fetch_behaviors.rs +++ b/moli-core/tests/fetch_behaviors.rs @@ -579,11 +579,14 @@ async fn fetch_with_domcontentloaded_stops_before_runtime_owned_script_load_even let page = browser .fetch_with_wait_until( - &server.url("/compat/runtime-owned-external-in-order-load-after-domcontentloaded"), + &server.url( + "/compat/runtime-owned-external-in-order-load-after-domcontentloaded?manual-release", + ), RenderedDomWaitUntil::DomContentLoaded, Duration::from_secs(5), ) .await?; + server.release_runtime_owned_in_order_load_after_dcl(); assert_eq!( diagnostic_global(&page, "runtimeOwnedInOrderLoadAfterDcl"), diff --git a/moli-core/tests/fixtures/runtime/runtime_owned_external_in_order_load_after_domcontentloaded.html b/moli-core/tests/fixtures/runtime/runtime_owned_external_in_order_load_after_domcontentloaded.html index a175ca46ba..3744418ae5 100644 --- a/moli-core/tests/fixtures/runtime/runtime_owned_external_in_order_load_after_domcontentloaded.html +++ b/moli-core/tests/fixtures/runtime/runtime_owned_external_in_order_load_after_domcontentloaded.html @@ -6,7 +6,7 @@ window.runtimeOwnedInOrderLoadOrder = []; const script = document.createElement("script"); script.async = false; - script.src = "/assets/runtime_owned_in_order_load_slow.js"; + script.src = "/assets/runtime_owned_in_order_load_after_dcl_gated.js"; script.onload = () => { window.runtimeOwnedInOrderLoadOrder.push("load"); queueMicrotask(() => { @@ -21,6 +21,11 @@ window.runtimeOwnedInOrderLoadOrder.push("dcl"); window.runtimeOwnedInOrderLoadAfterDcl = window.runtimeOwnedInOrderLoadOrder.join(","); + if (!location.search.includes("manual-release")) { + void fetch( + "/compat/runtime-owned-external-in-order-load-after-domcontentloaded-release", + ); + } }); window.addEventListener("load", () => { window.runtimeOwnedInOrderLoadOrder.push("window-load"); diff --git a/moli-test-support/src/routes_core.rs b/moli-test-support/src/routes_core.rs index 1bd5bbf041..a47f295fac 100644 --- a/moli-test-support/src/routes_core.rs +++ b/moli-test-support/src/routes_core.rs @@ -18,6 +18,9 @@ static RUNTIME_OWNED_ASYNC_CHUNKED_TAIL_GATES: OnceLock< static RUNTIME_OWNED_IN_ORDER_ERROR_AFTER_DCL_GATES: OnceLock< Mutex>>, > = OnceLock::new(); +static RUNTIME_OWNED_IN_ORDER_LOAD_AFTER_DCL_GATES: OnceLock< + Mutex>>, +> = OnceLock::new(); struct ConcurrentSharedStateRequestGuard; @@ -145,6 +148,27 @@ pub(crate) fn notify_runtime_owned_in_order_error_after_dcl_gate(host_key: &str) runtime_owned_in_order_error_after_dcl_gate(host_key).notify_one(); } +fn runtime_owned_in_order_load_after_dcl_gate(host_key: &str) -> Arc { + let gates = + RUNTIME_OWNED_IN_ORDER_LOAD_AFTER_DCL_GATES.get_or_init(|| Mutex::new(HashMap::new())); + let mut gates = gates.lock(); + gates + .entry(host_key.to_owned()) + .or_insert_with(|| Arc::new(tokio::sync::Notify::new())) + .clone() +} + +fn remove_runtime_owned_in_order_load_after_dcl_gate(host_key: &str) { + let Some(gates) = RUNTIME_OWNED_IN_ORDER_LOAD_AFTER_DCL_GATES.get() else { + return; + }; + gates.lock().remove(host_key); +} + +pub(crate) fn notify_runtime_owned_in_order_load_after_dcl_gate(host_key: &str) { + runtime_owned_in_order_load_after_dcl_gate(host_key).notify_one(); +} + pub(super) async fn static_page() -> Html<&'static str> { Html(STATIC_HTML) } @@ -2503,6 +2527,14 @@ pub(super) async fn runtime_owned_external_in_order_load_after_domcontentloaded_ Html(RUNTIME_OWNED_EXTERNAL_IN_ORDER_LOAD_AFTER_DOMCONTENTLOADED_HTML) } +pub(super) async fn release_runtime_owned_external_in_order_load_after_domcontentloaded( + headers: HeaderMap, +) -> StatusCode { + let host_key = request_host_key(&headers).unwrap_or_default(); + notify_runtime_owned_in_order_load_after_dcl_gate(&host_key); + StatusCode::NO_CONTENT +} + pub(super) async fn runtime_owned_external_in_order_with_defer_stays_after_domcontentloaded_page() -> Html<&'static str> { Html(RUNTIME_OWNED_EXTERNAL_IN_ORDER_WITH_DEFER_STAYS_AFTER_DOMCONTENTLOADED_HTML) @@ -4307,6 +4339,17 @@ pub(super) async fn asset_runtime_owned_in_order_load_script() -> Response { javascript_response(RUNTIME_OWNED_IN_ORDER_LOAD_JS) } +pub(super) async fn asset_runtime_owned_in_order_load_after_dcl_gated_script( + headers: HeaderMap, +) -> Response { + let host_key = request_host_key(&headers).unwrap_or_default(); + runtime_owned_in_order_load_after_dcl_gate(&host_key) + .notified() + .await; + remove_runtime_owned_in_order_load_after_dcl_gate(&host_key); + javascript_response(RUNTIME_OWNED_IN_ORDER_LOAD_JS) +} + pub(super) async fn asset_missing_runtime_owned_in_order_error_script( headers: HeaderMap, ) -> Response { diff --git a/moli-test-support/src/server.rs b/moli-test-support/src/server.rs index 9f22e7bccb..2e19fc5efb 100644 --- a/moli-test-support/src/server.rs +++ b/moli-test-support/src/server.rs @@ -45,6 +45,12 @@ impl FixtureServer { ); } + pub fn release_runtime_owned_in_order_load_after_dcl(&self) { + crate::routes_core::notify_runtime_owned_in_order_load_after_dcl_gate( + &self.addr.to_string(), + ); + } + pub async fn shutdown(mut self) { if let Some(shutdown_tx) = self.shutdown_tx.take() { let _ = shutdown_tx.send(()); diff --git a/moli-test-support/src/server_routes.rs b/moli-test-support/src/server_routes.rs index 2a0dec3827..b86d54849b 100644 --- a/moli-test-support/src/server_routes.rs +++ b/moli-test-support/src/server_routes.rs @@ -1412,6 +1412,10 @@ pub(super) fn build_router() -> Router { "/compat/runtime-owned-external-in-order-load-after-domcontentloaded", get(runtime_owned_external_in_order_load_after_domcontentloaded_page), ) + .route( + "/compat/runtime-owned-external-in-order-load-after-domcontentloaded-release", + get(release_runtime_owned_external_in_order_load_after_domcontentloaded), + ) .route( "/compat/runtime-owned-external-in-order-with-defer-stays-after-domcontentloaded", get(runtime_owned_external_in_order_with_defer_stays_after_domcontentloaded_page), @@ -2133,6 +2137,10 @@ pub(super) fn build_router() -> Router { "/assets/runtime_owned_in_order_load.js", get(asset_runtime_owned_in_order_load_script), ) + .route( + "/assets/runtime_owned_in_order_load_after_dcl_gated.js", + get(asset_runtime_owned_in_order_load_after_dcl_gated_script), + ) .route( "/assets/missing_runtime_owned_in_order_error.js", get(asset_missing_runtime_owned_in_order_error_script),