blob: d0440e177af4bb4a7e12d8c7e114acc029dfee5c [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/service_worker_test_helpers.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/service_worker/service_worker_task_queue.h"
#include "extensions/browser/service_worker/service_worker_test_utils.h"
#include "extensions/common/extension_features.h"
#include "extensions/test/extension_test_message_listener.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/service_worker/embedded_worker_status.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom-forward.h"
namespace extensions {
namespace {
constexpr char kTestExtensionId[] = "iegclhlplifhodhkoafiokenjoapiobj";
using DispatchWebNavigationEventCallback = base::OnceCallback<void()>;
// Observes service worker start requests via
// ServiceWorkerTaskQueue::DidStartWorkerForScope.
class ServiceWorkerStartCountObserver
: public ServiceWorkerTaskQueue::TestObserver {
public:
explicit ServiceWorkerStartCountObserver(const ExtensionId& extension_id)
: extension_id_(extension_id) {
ServiceWorkerTaskQueue::SetObserverForTest(this);
}
~ServiceWorkerStartCountObserver() override {
ServiceWorkerTaskQueue::SetObserverForTest(nullptr);
}
ServiceWorkerStartCountObserver(const ServiceWorkerStartCountObserver&) =
delete;
ServiceWorkerStartCountObserver& operator=(
const ServiceWorkerStartCountObserver&) = delete;
int GetStartWorkerRequestCount() { return extension_worker_start_count_; }
// ServiceWorkerTaskQueue::TestObserver:
void RequestedWorkerStart(const ExtensionId& extension_id) override {
if (extension_id == extension_id_) {
extension_worker_start_count_++;
}
}
private:
int extension_worker_start_count_ = 0;
ExtensionId extension_id_;
};
// TODO(crbug.com/1467015): Combine with service_worker_apitest.cc
// TestWorkerObserver.
// Test class that monitors a newly started worker and obtains the worker's
// version ID when it starts and allows the caller to wait for the worker to
// stop (after requesting the worker to stop).
class TestServiceWorkerContextObserver
: public content::ServiceWorkerContextObserver {
public:
TestServiceWorkerContextObserver(content::BrowserContext* browser_context,
const ExtensionId& extension_id)
: extension_url_(Extension::GetBaseURLFromExtensionId(extension_id)),
sw_context_(service_worker_test_utils::GetServiceWorkerContext(
browser_context)) {
scoped_observation_.Observe(sw_context_);
}
TestServiceWorkerContextObserver(const TestServiceWorkerContextObserver&) =
delete;
TestServiceWorkerContextObserver& operator=(
const TestServiceWorkerContextObserver&) = delete;
void WaitForWorkerStopped() { start_stopped_worker_run_loop_.Run(); }
void WaitForWorkerStarted() { start_stopped_worker_run_loop_.Run(); }
int64_t test_worker_version_id = blink::mojom::kInvalidServiceWorkerVersionId;
// ServiceWorkerContextObserver:
// Called when a worker has entered the
// `blink::EmbeddedWorkerStatus::kRunning` status. Used to obtain the new
// worker's version ID for later use/comparison.
void OnVersionStartedRunning(
int64_t version_id,
const content::ServiceWorkerRunningInfo& running_info) override {
if (running_info.scope != extension_url_) {
return;
}
test_worker_version_id = version_id;
start_stopped_worker_run_loop_.Quit();
}
// Called when a worker has entered the
// `blink::EmbeddedWorkerStatus::kStopped` status. Used to indicate when our
// test extension has stopped.
void OnVersionStoppedRunning(int64_t version_id) override {
// `test_worker_version_id` is the previously running version's id.
if (test_worker_version_id != version_id) {
return;
}
start_stopped_worker_run_loop_.Quit();
}
base::RunLoop start_stopped_worker_run_loop_;
const GURL extension_url_;
const raw_ptr<content::ServiceWorkerContext> sw_context_;
base::ScopedObservation<content::ServiceWorkerContext,
content::ServiceWorkerContextObserver>
scoped_observation_{this};
};
// Monitors the worker's running status and allows a callback to be run when the
// running status matches a specific `blink::EmbeddedWorkerStatus` running
// status.
class TestExtensionServiceWorkerRunningStatusObserver
: public content::ServiceWorkerTestHelper {
public:
explicit TestExtensionServiceWorkerRunningStatusObserver(
content::ServiceWorkerContext* sw_context,
int64_t worker_version_id = blink::mojom::kInvalidServiceWorkerVersionId)
: ServiceWorkerTestHelper(sw_context, worker_version_id),
test_worker_version_id_(worker_version_id) {}
TestExtensionServiceWorkerRunningStatusObserver(
const TestExtensionServiceWorkerRunningStatusObserver&) = delete;
TestExtensionServiceWorkerRunningStatusObserver& operator=(
const TestExtensionServiceWorkerRunningStatusObserver&) = delete;
// Set the worker status to watch for before running
// `test_event_dispatch_callback_`.
void SetDispatchCallbackOnStatus(
blink::EmbeddedWorkerStatus dispatch_status) {
dispatch_callback_on_status_ = dispatch_status;
}
// Set the callback to run when `dispatch_callback_on_status_` matches
// worker's current running status.
void SetDispatchTestEventCallback(base::OnceCallback<void()> callback) {
test_event_dispatch_callback_ = std::move(callback);
}
protected:
void OnDidRunningStatusChange(blink::EmbeddedWorkerStatus running_status,
int64_t version_id) override {
worker_running_status_ = running_status;
// We assume the next worker that arrives here is the one we're testing.
// This would be an incorrect assumption if we ever allowed multiple workers
// for an extension.
test_worker_version_id_ = version_id;
CheckWorkerStatusAndMaybeDispatchTestEvent(version_id);
}
// If running status matches desired running status then run the test event
// callback.
void CheckWorkerStatusAndMaybeDispatchTestEvent(
int64_t target_worker_version_id) {
if (!test_event_dispatch_callback_.is_null() &&
worker_running_status_ == dispatch_callback_on_status_) {
std::move(test_event_dispatch_callback_).Run();
}
}
private:
int64_t test_worker_version_id_ =
blink::mojom::kInvalidServiceWorkerVersionId;
blink::EmbeddedWorkerStatus worker_running_status_;
blink::EmbeddedWorkerStatus dispatch_callback_on_status_;
base::OnceCallback<void()> test_event_dispatch_callback_;
};
class ServiceWorkerEventDispatchingBrowserTest
: public ExtensionBrowserTest,
public testing::WithParamInterface<bool> {
public:
ServiceWorkerEventDispatchingBrowserTest() {
scoped_feature_list_.InitWithFeatureState(
extensions_features::kExtensionsServiceWorkerOptimizedEventDispatch,
GetParam());
}
ServiceWorkerEventDispatchingBrowserTest(
const ServiceWorkerEventDispatchingBrowserTest&) = delete;
ServiceWorkerEventDispatchingBrowserTest& operator=(
const ServiceWorkerEventDispatchingBrowserTest&) = delete;
void SetUpOnMainThread() override {
ExtensionBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
sw_context_ = GetServiceWorkerContext();
}
void TearDownOnMainThread() override {
ExtensionBrowserTest::TearDownOnMainThread();
sw_context_ = nullptr;
}
content::WebContents* web_contents() const {
return browser()->tab_strip_model()->GetActiveWebContents();
}
DispatchWebNavigationEventCallback CreateDispatchWebNavEventCallback(
int num_events_to_dispatch = 1) {
return base::BindOnce(
&ServiceWorkerEventDispatchingBrowserTest::DispatchWebNavigationEvent,
base::Unretained(this), num_events_to_dispatch);
}
// Broadcasts a webNavigation.onBeforeNavigate events.
void DispatchWebNavigationEvent(int num_events_to_dispatch = 1) {
EventRouter* router = EventRouter::EventRouter::Get(profile());
testing::NiceMock<content::MockNavigationHandle> handle(web_contents());
for (int i = 0; i < num_events_to_dispatch; i++) {
auto event =
web_navigation_api_helpers::CreateOnBeforeNavigateEvent(&handle);
router->BroadcastEvent(std::move(event));
}
}
protected:
raw_ptr<content::ServiceWorkerContext> sw_context_ = nullptr;
base::test::ScopedFeatureList scoped_feature_list_;
};
// Tests that dispatching an event to a worker with status
// `blink::EmbeddedWorkerStatus::kRunning` succeeds.
IN_PROC_BROWSER_TEST_P(ServiceWorkerEventDispatchingBrowserTest,
DispatchToRunningWorker) {
TestServiceWorkerContextObserver sw_started_observer(profile(),
kTestExtensionId);
ExtensionTestMessageListener extension_oninstall_listener_fired(
"installed listener fired");
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("events/reliability/service_worker"),
{.wait_for_registration_stored = true});
ASSERT_TRUE(extension);
ASSERT_EQ(kTestExtensionId, extension->id());
// This ensures that we wait until the the browser receives the ack from the
// renderer. This prevents unexpected histogram emits later.
ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied());
ASSERT_TRUE(content::CheckServiceWorkerIsRunning(
sw_context_, sw_started_observer.test_worker_version_id));
// Stop the worker, and wait for it to stop. We must stop it first before we
// can observe the kRunning status.
browsertest_util::StopServiceWorkerForExtensionGlobalScope(
browser()->profile(), extension->id());
sw_started_observer.WaitForWorkerStopped();
ASSERT_TRUE(content::CheckServiceWorkerIsStopped(
sw_context_, sw_started_observer.test_worker_version_id));
// Add observer that will watch for changes to the running status of the
// worker.
TestExtensionServiceWorkerRunningStatusObserver test_event_observer(
GetServiceWorkerContext());
// Setup to run the test event when kRunning status is encountered.
test_event_observer.SetDispatchTestEventCallback(
CreateDispatchWebNavEventCallback());
test_event_observer.SetDispatchCallbackOnStatus(
blink::EmbeddedWorkerStatus::kRunning);
// Setup listeners for confirming the event ran successfully.
base::HistogramTester histogram_tester;
ExtensionTestMessageListener extension_event_listener_fired("listener fired");
// Start the worker.
sw_context_->StartWorkerForScope(/*scope=*/extension->url(),
/*key=*/
blink::StorageKey::CreateFirstParty(
url::Origin::Create(extension->url())),
/*info_callback=*/base::DoNothing(),
/*failure_callback=*/base::DoNothing());
// During the above start request we catch the kRunning status with
// TestExtensionServiceWorkerRunningStatusObserver::OnDidRunningStatusChange()
// then synchronously dispatch the test event there.
// The histogram expect checks that we get an ack from the renderer to the
// browser for the event. The wait confirms that the extension worker listener
// finished. The wait is first (despite temporally possibly being after the
// ack) because it is currently the most convenient to wait on.
EXPECT_TRUE(extension_event_listener_fired.WaitUntilSatisfied());
// Call to webNavigation.onBeforeNavigate expected.
histogram_tester.ExpectTotalCount(
"Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2",
/*expected_count=*/1);
}
// Tests that dispatching an event to a worker with status
// `blink::EmbeddedWorkerStatus::kStopped` succeeds. This logic is laid out
// differently than in the other test cases because we can't currently detect
// precisely when a worker enters the stopped status.
IN_PROC_BROWSER_TEST_P(ServiceWorkerEventDispatchingBrowserTest,
DispatchToStoppedWorker) {
TestServiceWorkerContextObserver sw_started_stopped_observer(
profile(), kTestExtensionId);
ExtensionTestMessageListener extension_oninstall_listener_fired(
"installed listener fired");
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("events/reliability/service_worker"),
{.wait_for_registration_stored = true});
ASSERT_TRUE(extension);
ASSERT_EQ(kTestExtensionId, extension->id());
// This ensures that we wait until the the browser receives the ack from the
// renderer. This prevents unexpected histogram emits later.
ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied());
ASSERT_TRUE(content::CheckServiceWorkerIsRunning(
sw_context_, sw_started_stopped_observer.test_worker_version_id));
// ServiceWorkerVersion is destroyed async when we stop the worker so we can't
// precisely check when the worker stopped. So instead, wait for when we
// notice a stopping worker, confirm the worker didn't restart, and check the
// worker's status to confirm kStopped occurred to be as certain that we can
// that the worker is stopped when we dispatch the event.
TestExtensionServiceWorkerRunningStatusObserver worker_restarted_observer(
GetServiceWorkerContext());
// Stop the worker, and wait for it to stop.
browsertest_util::StopServiceWorkerForExtensionGlobalScope(
browser()->profile(), extension->id());
sw_started_stopped_observer.WaitForWorkerStopped();
// TODO(crbug.com/1467015): Add a more guaranteed check that the worker was
// stopped when we dispatch the event. This check confirms the worker is
// currently stopped, but doesn't guarantee that when we dispatch the event
// below that it is still stopped.
ASSERT_TRUE(content::CheckServiceWorkerIsStopped(
sw_context_,
// Service workers keep the same version id across restarts.
sw_started_stopped_observer.test_worker_version_id));
// Setup listeners for confirming the event ran successfully.
base::HistogramTester histogram_tester;
ExtensionTestMessageListener extension_event_listener_fired("listener fired");
DispatchWebNavigationEvent();
// The histogram expect checks that we get an ack from the renderer to the
// browser for the event. The wait confirms that the extension worker
// listener finished. The wait is first (despite temporally possibly being
// after the ack) because it is currently the most convenient to wait on.
EXPECT_TRUE(extension_event_listener_fired.WaitUntilSatisfied());
// Call to webNavigation.onBeforeNavigate expected.
histogram_tester.ExpectTotalCount(
"Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2",
/*expected_count=*/1);
}
// Tests that dispatching an event to a worker with status
// `blink::EmbeddedWorkerStatus::kStarting` succeeds. This test first
// installs the extension and waits for the worker to fully start. Then stops it
// and starts it again to catch the kStarting status. This is to avoid event
// acknowledgments on install we aren't trying to test for.
// TODO(jlulejian): If we suspect or see worker bugs that occur on extension
// install then create test cases where we dispatch events immediately on
// extension install.
IN_PROC_BROWSER_TEST_P(ServiceWorkerEventDispatchingBrowserTest,
DispatchToStartingWorker) {
TestServiceWorkerContextObserver sw_started_stopped_observer(
profile(), kTestExtensionId);
ExtensionTestMessageListener extension_oninstall_listener_fired(
"installed listener fired");
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("events/reliability/service_worker"),
{.wait_for_registration_stored = true});
ASSERT_TRUE(extension);
ASSERT_EQ(kTestExtensionId, extension->id());
// This ensures that we wait until the the browser receives the ack from the
// renderer. This prevents unexpected histogram emits later.
ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied());
ASSERT_TRUE(content::CheckServiceWorkerIsRunning(
sw_context_, sw_started_stopped_observer.test_worker_version_id));
// Stop the worker, and wait for it to stop. We must stop it first before we
// can start and observe the kStarting status.
browsertest_util::StopServiceWorkerForExtensionGlobalScope(
browser()->profile(), extension->id());
sw_started_stopped_observer.WaitForWorkerStopped();
// Add observer that will watch for changes to the running status of the
// worker.
TestExtensionServiceWorkerRunningStatusObserver test_event_observer(
GetServiceWorkerContext());
// Setup to run the test event when kStarting status is encountered.
test_event_observer.SetDispatchTestEventCallback(
CreateDispatchWebNavEventCallback());
test_event_observer.SetDispatchCallbackOnStatus(
blink::EmbeddedWorkerStatus::kStarting);
// Setup listeners for confirming the event ran successfully.
base::HistogramTester histogram_tester;
ExtensionTestMessageListener extension_event_listener_fired("listener fired");
// Start the worker and wait until the worker is kStarting.
sw_context_->StartWorkerForScope(/*scope=*/extension->url(),
/*key=*/
blink::StorageKey::CreateFirstParty(
url::Origin::Create(extension->url())),
/*info_callback=*/base::DoNothing(),
/*failure_callback=*/base::DoNothing());
// During the above start request we catch the transient kStarting status with
// TestExtensionServiceWorkerRunningStatusObserver::OnDidRunningStatusChange()
// then synchronously dispatch the test event there.
// The histogram expect checks that we get an ack from the renderer to the
// browser for the event. The wait confirms that the extension worker listener
// finished. The wait is first (despite temporally possibly being after the
// ack) because it is currently the most convenient to wait on.
EXPECT_TRUE(extension_event_listener_fired.WaitUntilSatisfied());
// Call to webNavigation.onBeforeNavigate expected.
histogram_tester.ExpectTotalCount(
"Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2",
/*expected_count=*/1);
}
// Tests that dispatching an event to a
// worker with status `blink::EmbeddedWorkerStatus::kStopping` succeeds.
IN_PROC_BROWSER_TEST_P(ServiceWorkerEventDispatchingBrowserTest,
DispatchToStoppingWorker) {
TestServiceWorkerContextObserver sw_started_observer(profile(),
kTestExtensionId);
ExtensionTestMessageListener extension_oninstall_listener_fired(
"installed listener fired");
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("events/reliability/service_worker"),
{.wait_for_registration_stored = true});
ASSERT_TRUE(extension);
ASSERT_EQ(kTestExtensionId, extension->id());
// This ensures that we wait until the the browser receives the ack from the
// renderer. This prevents unexpected histogram emits later.
ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied());
ASSERT_TRUE(content::CheckServiceWorkerIsRunning(
sw_context_, sw_started_observer.test_worker_version_id));
// Add observer that will watch for changes to the running status of the
// worker.
TestExtensionServiceWorkerRunningStatusObserver test_event_observer(
GetServiceWorkerContext(), sw_started_observer.test_worker_version_id);
// Setup to run the test event when kStopping status is encountered.
test_event_observer.SetDispatchTestEventCallback(
CreateDispatchWebNavEventCallback());
test_event_observer.SetDispatchCallbackOnStatus(
blink::EmbeddedWorkerStatus::kStopping);
// Setup listeners for confirming the event ran successfully.
base::HistogramTester histogram_tester;
ExtensionTestMessageListener extension_event_listener_fired("listener fired");
// Stop the worker, but don't wait for it to stop. We want to catch the state
// change to kStopping status when we dispatch the event.
content::StopServiceWorkerForScope(sw_context_, extension->url(),
base::DoNothing());
// During the above stop request we catch the kStopped status with
// TestExtensionServiceWorkerRunningStatusObserver::OnDidRunningStatusChange()
// then synchronously dispatch the test event there.
// The histogram expect checks that we get an ack from the renderer to the
// browser for the event. The wait confirms that the extension worker listener
// finished. The wait is first (despite temporally possibly being after the
// ack) because it is currently the most convenient to wait on.
EXPECT_TRUE(extension_event_listener_fired.WaitUntilSatisfied());
// Call to webNavigation.onBeforeNavigate expected.
histogram_tester.ExpectTotalCount(
"Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2",
/*expected_count=*/1);
}
// Tests that we will not attempt to redundantly start a worker if it is
// in the kStarting status (meaning: there are pending events/tasks to
// process).
IN_PROC_BROWSER_TEST_P(ServiceWorkerEventDispatchingBrowserTest,
StartingWorkerIsNotStartRequested) {
TestServiceWorkerContextObserver sw_started_stopped_observer(
profile(), kTestExtensionId);
ExtensionTestMessageListener extension_oninstall_listener_fired(
"installed listener fired");
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII(
"events/reliability/service_worker_redundant_start"),
{.wait_for_registration_stored = true});
ASSERT_TRUE(extension);
ASSERT_EQ(kTestExtensionId, extension->id());
// This ensures that we wait until the the browser receives the ack from the
// renderer. This prevents unexpected histogram emits later.
ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied());
ASSERT_TRUE(content::CheckServiceWorkerIsRunning(
sw_context_, sw_started_stopped_observer.test_worker_version_id));
// Stop the worker, and wait for it to stop. We must stop it first before we
// can start and observe the kStarting status.
browsertest_util::StopServiceWorkerForExtensionGlobalScope(
browser()->profile(), extension->id());
sw_started_stopped_observer.WaitForWorkerStopped();
// Add observer that will watch for changes to the running status of the
// worker.
TestExtensionServiceWorkerRunningStatusObserver test_event_observer(
GetServiceWorkerContext());
// Setup to send test events when kStarting status is encountered.
// Sending multiple events is what could elicit a redundant start if the
// logic isn't working as expected.
test_event_observer.SetDispatchTestEventCallback(
CreateDispatchWebNavEventCallback(/*num_events_to_dispatch=*/2));
test_event_observer.SetDispatchCallbackOnStatus(
blink::EmbeddedWorkerStatus::kStarting);
// Setup listeners for confirming the event ran successfully.
base::HistogramTester histogram_tester;
ExtensionTestMessageListener extension_event_listener_fired_three_times(
"listener fired three times");
ServiceWorkerStartCountObserver start_count_observer(extension->id());
// This dispatch will start the worker with the existing event routing and
// task queueing logic.
DispatchWebNavigationEvent();
// During the above start that occurs as part of dispatching the event we
// catch the transient kStarting status with
// TestExtensionServiceWorkerRunningStatusObserver::OnDidRunningStatusChange()
// then synchronously dispatch two more test events there.
EXPECT_TRUE(extension_event_listener_fired_three_times.WaitUntilSatisfied());
// Three calls to webNavigation.onBeforeNavigate listener expected.
histogram_tester.ExpectTotalCount(
"Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2",
/*expected_count=*/3);
// Confirm the expected number of start requests that are sent to the
// extension during the multi event dispatch. Should only need one start to
// process the multiple events.
EXPECT_EQ(1, start_count_observer.GetStartWorkerRequestCount());
}
// Tests the behavior of service worker start requests when a worker is already
// running. extensions_features::kExtensionsServiceWorkerOptimizedEventDispatch
// feature disabled means we will redundantly try to start a worker when it is
// already started. The feature enabled means that we will not redundantly
// attempt to start a started worker for every event dispatch.
IN_PROC_BROWSER_TEST_P(ServiceWorkerEventDispatchingBrowserTest,
StartedWorkerRedundantStarts) {
TestServiceWorkerContextObserver sw_started_stopped_observer(
profile(), kTestExtensionId);
ExtensionTestMessageListener extension_oninstall_listener_fired(
"installed listener fired");
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("events/reliability/service_worker"),
{.wait_for_registration_stored = true});
ASSERT_TRUE(extension);
ASSERT_EQ(kTestExtensionId, extension->id());
// This ensures that we wait until the the browser receives the ack from the
// renderer. This prevents unexpected histogram emits later.
ASSERT_TRUE(extension_oninstall_listener_fired.WaitUntilSatisfied());
sw_started_stopped_observer.WaitForWorkerStarted();
ASSERT_TRUE(content::CheckServiceWorkerIsRunning(
sw_context_, sw_started_stopped_observer.test_worker_version_id));
// Setup listeners for confirming the event ran successfully.
ExtensionTestMessageListener extension_event_listener_fired("listener fired");
ServiceWorkerStartCountObserver start_count_observer(extension->id());
DispatchWebNavigationEvent();
EXPECT_TRUE(extension_event_listener_fired.WaitUntilSatisfied());
// Confirm the expected number of start requests that are sent to the
// extension worker during event dispatch.
if (GetParam()) {
// extensions_features::kExtensionsServiceWorkerOptimizedEventDispatch true
// No start is requested when dispatching to the worker since the worker is
// running ready to receive tasks.
EXPECT_EQ(0, start_count_observer.GetStartWorkerRequestCount());
} else {
// extensions_features::kExtensionsServiceWorkerOptimizedEventDispatch false
// Since the feature is disabled, we will attempt to start a worker on every
// event dispatch even though it is already started/running and can run the
// event.
EXPECT_EQ(1, start_count_observer.GetStartWorkerRequestCount());
}
}
INSTANTIATE_TEST_SUITE_P(
All,
ServiceWorkerEventDispatchingBrowserTest,
/* extensions_features::kExtensionsServiceWorkerOptimizedEventDispatch
enabled status */
testing::Bool());
// TODO(crbug.com/1467015): Create test for event dispatching that uses the
// `EventRouter::DispatchEventToSender()` event flow.
// TODO(crbug.com/40072982): Test that kBadRequestId no longer kills the service
// worker renderer with a test that mimics receiving a stale ack to the browser.
} // namespace
} // namespace extensions