LibWeb: Add an Internals hook to interrupt a navigation with a traversal
clobberNextNavigationWithATraversal() arms a one-shot that, on the next call to Navigable::begin_navigation, re-stamps the navigable’s ongoing navigation with a synthetic session-history traversal during the unload check, then clears it on a later turn — draining deferred navigations. This lets a single-process test deterministically reproduce a race between a cross-document navigation and a concurrent traversal, which otherwise only surfaces under scheduling jitter in a multi-process run.
This commit is contained in:
parent
4ecfd0903f
commit
85a4f2633c
5 changed files with 34 additions and 0 deletions
|
|
@ -1990,6 +1990,15 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
|
|||
// and an optional boolean initialInsertion (default false):
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
|
||||
|
||||
// Test-only: armed via Internals.clobberNextNavigationWithATraversal(). Consumed by the next call to begin_navigation,
|
||||
// which simulates a concurrent session-history traversal interrupting the unload check.
|
||||
static bool s_clobber_next_navigation_with_a_traversal = false;
|
||||
void Navigable::clobber_next_navigation_with_a_traversal_for_testing()
|
||||
{
|
||||
s_clobber_next_navigation_with_a_traversal = true;
|
||||
}
|
||||
|
||||
void Navigable::begin_navigation(NavigateParams params)
|
||||
{
|
||||
// AD-HOC: Not in the spec but we should not navigate a navigable that has been destroyed.
|
||||
|
|
@ -2213,6 +2222,17 @@ void Navigable::begin_navigation(NavigateParams params)
|
|||
return;
|
||||
}
|
||||
|
||||
// Test-only (Internals.clobberNextNavigationWithATraversal): re-stamp our ongoing navigation with a
|
||||
// synthetic traversal now, and clear it on a later turn (which drains deferred navigations). This
|
||||
// deterministically reproduces the race the guard below must survive.
|
||||
if (s_clobber_next_navigation_with_a_traversal) {
|
||||
s_clobber_next_navigation_with_a_traversal = false;
|
||||
set_ongoing_navigation(Traversal::Tag, NavigationAPIAbortBehavior::Preserve);
|
||||
Platform::EventLoopPlugin::the().deferred_invoke(GC::create_function(heap(), [this] {
|
||||
set_ongoing_navigation(Empty {}, NavigationAPIAbortBehavior::Preserve);
|
||||
}));
|
||||
}
|
||||
|
||||
if (ongoing_navigation() != navigation_id) {
|
||||
set_delaying_load_events(false);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ public:
|
|||
Variant<Empty, Traversal, String> ongoing_navigation() const { return m_ongoing_navigation; }
|
||||
void set_ongoing_navigation(Variant<Empty, Traversal, String> ongoing_navigation, NavigationAPIAbortBehavior = NavigationAPIAbortBehavior::Abort);
|
||||
|
||||
// Test-only (Internals.clobberNextNavigationWithATraversal): make the next navigation's unload check be interrupted
|
||||
// by a synthetic session-history traversal that re-stamps the ongoing navigation.
|
||||
static void clobber_next_navigation_with_a_traversal_for_testing();
|
||||
|
||||
void populate_session_history_entry_document(
|
||||
URL::URL url,
|
||||
Variant<Empty, String, POSTResource> document_resource,
|
||||
|
|
|
|||
|
|
@ -299,6 +299,11 @@ void Internals::commit_text()
|
|||
page().handle_keydown(UIEvents::Key_Return, 0, 0x0d, false, true);
|
||||
}
|
||||
|
||||
void Internals::clobber_next_navigation_with_a_traversal()
|
||||
{
|
||||
HTML::Navigable::clobber_next_navigation_with_a_traversal_for_testing();
|
||||
}
|
||||
|
||||
UIEvents::MouseButton Internals::button_from_unsigned_short(WebIDL::UnsignedShort button)
|
||||
{
|
||||
switch (button) {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ public:
|
|||
String dump_session_history();
|
||||
String dump_ui_process_session_history();
|
||||
GC::Ref<WebIDL::Promise> flush_session_history_traversal_queue();
|
||||
void clobber_next_navigation_with_a_traversal();
|
||||
|
||||
GC::Ptr<DOM::ShadowRoot> get_shadow_root(GC::Ref<DOM::Element>);
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,10 @@ interface Internals {
|
|||
DOMString dumpUIProcessSessionHistory();
|
||||
Promise<undefined> flushSessionHistoryTraversalQueue();
|
||||
|
||||
// Test-only: deterministically reproduce the navigation-vs-traversal race in Navigable::begin_navigation by
|
||||
// re-stamping the next navigation's ongoing navigation with a traversal during its unload check.
|
||||
undefined clobberNextNavigationWithATraversal();
|
||||
|
||||
// Returns the shadow root of the element, if it has one, even if it's not normally accessible to JS.
|
||||
ShadowRoot? getShadowRoot(Element element);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue