// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <tuple> #include <utility> #include <vector> #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/test/bind.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/service_worker_context.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/service_worker_test_helpers.h" #include "extensions/browser/process_manager.h" #include "extensions/browser/service_worker/service_worker_host.h" #include "extensions/browser/service_worker/service_worker_task_queue.h" #include "extensions/browser/service_worker/service_worker_test_utils.h" #include "extensions/browser/service_worker/worker_id_set.h" #include "extensions/common/extension_id.h" #include "extensions/common/mojom/service_worker_host.mojom-test-utils.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/test_extension_dir.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" #include "url/gurl.h" // Tests for validating the logic for keeping track of extension service // workers. This is intentionally broad to include things like: // * Starting and stopping state of the service worker // * Keeping track of information for the running worker instance namespace extensions { namespace { TestServiceWorkerTaskQueueObserver; // A helper class that intercepts the // `ServiceWorkerHost::DidStopServiceWorkerContext()` mojom receiver method and // does *not* forward the call onto the real `ServiceWorkerHost` implementation. class ServiceWorkerHostInterceptorForWorkerStop : public mojom::ServiceWorkerHostInterceptorForTesting { … }; class ServiceWorkerTrackingBrowserTest : public ExtensionBrowserTest { … }; // Test class to help verify the tracking of `WorkerId`s in // `ServiceWorkerTaskQueue` and `WorkerIdSet`. class ServiceWorkerIdTrackingBrowserTest : public ServiceWorkerTrackingBrowserTest { … }; // TODO(crbug.com/40936639): improve the stall test by using similar logic to // ServiceWorkerVersionTest.StallInStopping_DetachThenStart to more closely // simulate a worker thread delayed in stopping. This will also allow testing // when the delay causes ProcessManager::RenderProcessExited() to be called // before ServiceWorkerTaskQueue::OnStopped(). // Tests that when: // 1) something, other than a worker, keeps the extension renderer process // alive (e.g. a tab is open to a page hosted inside the extension) and // 2) simultaneously the worker is stopped but is stalled/blocked in // terminating (preventing notification to //extensions that it has stopped) // and // 3) sometime later a new worker instance is started (e.g. by a new extension // event that is sent) // // (a.k.a a "delayed worker stop") the //extensions browser layer should only // track (`WorkerIdSet`) one worker instance (`WorkerId`) (the new worker // instance). This avoids tracking one or more instances of stopped workers. // Regression test for crbug.com/40936639. IN_PROC_BROWSER_TEST_F( ServiceWorkerIdTrackingBrowserTest, WorkerStalledInStopping_RemovedByBrowserStopNotification) { … } // Test that when a worker is stopped and then restarted we only track one // instance of `WorkerId` in `WorkerIdSet`. This specific test removes it via // the renderer stop notification first (but it could also happen in other ways) // and then ensures the browser stop notification doesn't try to doubly remove // the `WorkerId`. IN_PROC_BROWSER_TEST_F( ServiceWorkerIdTrackingBrowserTest, WorkerNotStalledInStopping_RemovedByRenderStopNotificationFirst) { … } // Test that when a worker is stopped and then restarted we only track one // instance of `WorkerId` in `WorkerIdSet`. This specific test removes it via // the browser stop notification first and then ensures the renderer stop // notification doesn't try to doubly remove the `WorkerId`. IN_PROC_BROWSER_TEST_F( ServiceWorkerIdTrackingBrowserTest, WorkerNotStalledInStopping_RemovedByBrowserStopNotificationFirst) { … } ServiceWorkerStopTrackingBrowserTest; // Test that if a browser stop notification is received before the render stop // notification (since these things can be triggered independently) the worker's // browser readiness remains not ready. IN_PROC_BROWSER_TEST_F( ServiceWorkerStopTrackingBrowserTest, OnStoppedUpdatesBrowserState_BeforeRenderStopNotification) { … } // Test that if a browser stop notification is received after the render stop // notification (since these things can be triggered independently) // it updates the worker's browser readiness information to not ready. IN_PROC_BROWSER_TEST_F( ServiceWorkerStopTrackingBrowserTest, OnStoppedUpdatesBrowserState_AfterRenderStopNotification) { … } // Test that if a browser stop notification is received after a worker is // deactivated (since they can be triggered independently) we don't update the // worker's browser readiness information. IN_PROC_BROWSER_TEST_F(ServiceWorkerStopTrackingBrowserTest, OnStoppedRunsAfterDeactivatingWorker) { … } } // namespace } // namespace extensions