1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/performance_manager/worker_watcher.h"
- #include <memory>
- #include <utility>
- #include <vector>
- #include "base/callback_helpers.h"
- #include "base/containers/contains.h"
- #include "base/guid.h"
- #include "base/observer_list.h"
- #include "base/run_loop.h"
- #include "base/strings/stringprintf.h"
- #include "base/test/bind.h"
- #include "base/test/scoped_feature_list.h"
- #include "components/performance_manager/frame_node_source.h"
- #include "components/performance_manager/graph/frame_node_impl.h"
- #include "components/performance_manager/graph/page_node_impl.h"
- #include "components/performance_manager/graph/process_node_impl.h"
- #include "components/performance_manager/graph/worker_node_impl.h"
- #include "components/performance_manager/performance_manager_impl.h"
- #include "components/performance_manager/process_node_source.h"
- #include "components/performance_manager/public/features.h"
- #include "content/public/browser/render_frame_host.h"
- #include "content/public/browser/shared_worker_service.h"
- #include "content/public/test/browser_task_environment.h"
- #include "content/public/test/fake_service_worker_context.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/blink/public/common/storage_key/storage_key.h"
- #include "url/origin.h"
- namespace performance_manager {
- namespace {
- // Generates a new sequential int ID. Used for things that need a unique ID.
- int GenerateNextId() {
- static int next_id = 0;
- return next_id++;
- }
- // Generates a unique URL for a fake worker node.
- GURL GenerateWorkerUrl() {
- return GURL(base::StringPrintf("https://www.foo.org/worker_script_%d.js",
- GenerateNextId()));
- }
- // Helper function to check that |worker_node| and |client_frame_node| are
- // correctly hooked up together.
- bool IsWorkerClient(WorkerNodeImpl* worker_node,
- FrameNodeImpl* client_frame_node) {
- return base::Contains(worker_node->client_frames(), client_frame_node) &&
- base::Contains(client_frame_node->child_worker_nodes(), worker_node);
- }
- // Helper function to check that |worker_node| and |client_worker_node| are
- // correctly hooked up together.
- bool IsWorkerClient(WorkerNodeImpl* worker_node,
- WorkerNodeImpl* client_worker_node) {
- return base::Contains(worker_node->client_workers(), client_worker_node) &&
- base::Contains(client_worker_node->child_workers(), worker_node);
- }
- // TestDedicatedWorkerService --------------------------------------------------
- // A test DedicatedWorkerService that allows to simulate creating and destroying
- // dedicated workers.
- class TestDedicatedWorkerService : public content::DedicatedWorkerService {
- public:
- TestDedicatedWorkerService();
- TestDedicatedWorkerService(const TestDedicatedWorkerService&) = delete;
- TestDedicatedWorkerService& operator=(const TestDedicatedWorkerService&) =
- delete;
- ~TestDedicatedWorkerService() override;
- // content::DedicatedWorkerService
- void AddObserver(Observer* observer) override;
- void RemoveObserver(Observer* observer) override;
- void EnumerateDedicatedWorkers(Observer* observer) override;
- // Creates a new dedicated worker and returns its ID.
- const blink::DedicatedWorkerToken& CreateDedicatedWorker(
- int worker_process_id,
- content::GlobalRenderFrameHostId client_render_frame_host_id);
- // Destroys an existing dedicated worker.
- void DestroyDedicatedWorker(const blink::DedicatedWorkerToken& token);
- private:
- base::ObserverList<Observer> observer_list_;
- // Maps each running worker to its client RenderFrameHost ID.
- base::flat_map<blink::DedicatedWorkerToken, content::GlobalRenderFrameHostId>
- dedicated_worker_client_frame_;
- };
- TestDedicatedWorkerService::TestDedicatedWorkerService() = default;
- TestDedicatedWorkerService::~TestDedicatedWorkerService() = default;
- void TestDedicatedWorkerService::AddObserver(Observer* observer) {
- observer_list_.AddObserver(observer);
- }
- void TestDedicatedWorkerService::RemoveObserver(Observer* observer) {
- observer_list_.RemoveObserver(observer);
- }
- void TestDedicatedWorkerService::EnumerateDedicatedWorkers(Observer* observer) {
- // Not implemented.
- ADD_FAILURE();
- }
- const blink::DedicatedWorkerToken&
- TestDedicatedWorkerService::CreateDedicatedWorker(
- int worker_process_id,
- content::GlobalRenderFrameHostId client_render_frame_host_id) {
- // Create a new token for the worker and add it to the map, along with its
- // client ID.
- const blink::DedicatedWorkerToken token;
- auto result = dedicated_worker_client_frame_.emplace(
- token, client_render_frame_host_id);
- DCHECK(result.second); // Check inserted.
- // Notify observers.
- for (auto& observer : observer_list_) {
- observer.OnWorkerCreated(token, worker_process_id,
- client_render_frame_host_id);
- }
- return result.first->first;
- }
- void TestDedicatedWorkerService::DestroyDedicatedWorker(
- const blink::DedicatedWorkerToken& token) {
- auto it = dedicated_worker_client_frame_.find(token);
- DCHECK(it != dedicated_worker_client_frame_.end());
- // Notify observers that the worker is being destroyed.
- for (auto& observer : observer_list_)
- observer.OnBeforeWorkerDestroyed(token, it->second);
- // Remove the worker ID from the map.
- dedicated_worker_client_frame_.erase(it);
- }
- // TestSharedWorkerService -----------------------------------------------------
- // A test SharedWorkerService that allows to simulate creating and destroying
- // shared workers and adding clients to existing workers.
- class TestSharedWorkerService : public content::SharedWorkerService {
- public:
- TestSharedWorkerService();
- TestSharedWorkerService(const TestSharedWorkerService&) = delete;
- TestSharedWorkerService& operator=(const TestSharedWorkerService&) = delete;
- ~TestSharedWorkerService() override;
- // content::SharedWorkerService
- void AddObserver(Observer* observer) override;
- void RemoveObserver(Observer* observer) override;
- void EnumerateSharedWorkers(Observer* observer) override;
- bool TerminateWorker(const GURL& url,
- const std::string& name,
- const blink::StorageKey& storage_key) override;
- void Shutdown() override;
- // Creates a new shared worker and returns its token.
- blink::SharedWorkerToken CreateSharedWorker(int worker_process_id);
- // Destroys a running shared worker.
- void DestroySharedWorker(const blink::SharedWorkerToken& shared_worker_token);
- // Adds a new frame client to an existing worker.
- void AddClient(const blink::SharedWorkerToken& shared_worker_token,
- content::GlobalRenderFrameHostId client_render_frame_host_id);
- // Removes an existing frame client from a worker.
- void RemoveClient(
- const blink::SharedWorkerToken& shared_worker_token,
- content::GlobalRenderFrameHostId client_render_frame_host_id);
- private:
- base::ObserverList<Observer> observer_list_;
- // Contains the set of clients for each running workers.
- base::flat_map<blink::SharedWorkerToken,
- base::flat_set<content::GlobalRenderFrameHostId>>
- shared_worker_client_frames_;
- };
- TestSharedWorkerService::TestSharedWorkerService() = default;
- TestSharedWorkerService::~TestSharedWorkerService() = default;
- void TestSharedWorkerService::AddObserver(Observer* observer) {
- observer_list_.AddObserver(observer);
- }
- void TestSharedWorkerService::RemoveObserver(Observer* observer) {
- observer_list_.RemoveObserver(observer);
- }
- void TestSharedWorkerService::EnumerateSharedWorkers(Observer* observer) {
- // Not implemented.
- ADD_FAILURE();
- }
- bool TestSharedWorkerService::TerminateWorker(
- const GURL& url,
- const std::string& name,
- const blink::StorageKey& storage_key) {
- // Not implemented.
- ADD_FAILURE();
- return false;
- }
- void TestSharedWorkerService::Shutdown() {
- // Not implemented.
- ADD_FAILURE();
- }
- blink::SharedWorkerToken TestSharedWorkerService::CreateSharedWorker(
- int worker_process_id) {
- // Create a new SharedWorkerToken for the worker and add it to the map.
- const blink::SharedWorkerToken shared_worker_token;
- bool inserted =
- shared_worker_client_frames_.insert({shared_worker_token, {}}).second;
- DCHECK(inserted);
- // Notify observers.
- for (auto& observer : observer_list_) {
- observer.OnWorkerCreated(shared_worker_token, worker_process_id,
- base::UnguessableToken::Create());
- }
- return shared_worker_token;
- }
- void TestSharedWorkerService::DestroySharedWorker(
- const blink::SharedWorkerToken& shared_worker_token) {
- auto it = shared_worker_client_frames_.find(shared_worker_token);
- DCHECK(it != shared_worker_client_frames_.end());
- // The worker should no longer have any clients.
- DCHECK(it->second.empty());
- // Notify observers that the worker is being destroyed.
- for (auto& observer : observer_list_)
- observer.OnBeforeWorkerDestroyed(shared_worker_token);
- // Remove the worker ID from the map.
- shared_worker_client_frames_.erase(it);
- }
- void TestSharedWorkerService::AddClient(
- const blink::SharedWorkerToken& shared_worker_token,
- content::GlobalRenderFrameHostId client_render_frame_host_id) {
- // Add the frame to the set of clients for this worker.
- auto it = shared_worker_client_frames_.find(shared_worker_token);
- DCHECK(it != shared_worker_client_frames_.end());
- base::flat_set<content::GlobalRenderFrameHostId>& client_frames = it->second;
- bool inserted = client_frames.insert(client_render_frame_host_id).second;
- DCHECK(inserted);
- // Then notify observers.
- for (auto& observer : observer_list_)
- observer.OnClientAdded(shared_worker_token, client_render_frame_host_id);
- }
- void TestSharedWorkerService::RemoveClient(
- const blink::SharedWorkerToken& shared_worker_token,
- content::GlobalRenderFrameHostId client_render_frame_host_id) {
- // Notify observers.
- for (auto& observer : observer_list_)
- observer.OnClientRemoved(shared_worker_token, client_render_frame_host_id);
- // Then remove the frame from the set of clients of this worker.
- auto it = shared_worker_client_frames_.find(shared_worker_token);
- DCHECK(it != shared_worker_client_frames_.end());
- base::flat_set<content::GlobalRenderFrameHostId>& client_frames = it->second;
- size_t removed = client_frames.erase(client_render_frame_host_id);
- DCHECK_EQ(removed, 1u);
- }
- // TestServiceWorkerContext ----------------------------------------------------
- // A test ServiceWorkerContext that allows to simulate a worker starting and
- // stopping and adding clients to running workers.
- //
- // Extends content::FakeServiceWorkerContext to avoid reimplementing all the
- // unused virtual functions.
- class TestServiceWorkerContext : public content::FakeServiceWorkerContext {
- public:
- TestServiceWorkerContext();
- ~TestServiceWorkerContext() override;
- TestServiceWorkerContext(const TestServiceWorkerContext&) = delete;
- TestServiceWorkerContext& operator=(const TestServiceWorkerContext&) = delete;
- // content::FakeServiceWorkerContext:
- void AddObserver(content::ServiceWorkerContextObserver* observer) override;
- void RemoveObserver(content::ServiceWorkerContextObserver* observer) override;
- // Creates a new service worker and returns its version ID.
- int64_t CreateServiceWorker();
- // Deletes an existing service worker.
- void DestroyServiceWorker(int64_t version_id);
- // Starts an existing service worker.
- void StartServiceWorker(int64_t version_id, int worker_process_id);
- // Stops a service shared worker.
- void StopServiceWorker(int64_t version_id);
- // Adds a new client to an existing service worker and returns its generated
- // client UUID.
- std::string AddClient(int64_t version_id,
- const content::ServiceWorkerClientInfo& client_info);
- // Adds a new client to an existing service worker with the provided
- // client UUID. Returns |client_uuid| for convenience.
- std::string AddClientWithClientID(
- int64_t version_id,
- std::string client_uuid,
- const content::ServiceWorkerClientInfo& client_info);
- // Removes an existing client from a worker.
- void RemoveClient(int64_t version_id, const std::string& client_uuid);
- // Simulates when the navigation commits, meaning that the RenderFrameHost is
- // now available for a window client. Not valid for worker clients.
- void OnControlleeNavigationCommitted(
- int64_t version_id,
- const std::string& client_uuid,
- content::GlobalRenderFrameHostId render_frame_host_id);
- private:
- base::ObserverList<content::ServiceWorkerContextObserver>::Unchecked
- observer_list_;
- // The ID that the next service worker will be assigned.
- int64_t next_service_worker_instance_id_ = 0;
- struct ServiceWorkerInfo {
- bool is_running = false;
- // Contains all the clients
- base::flat_set<std::string /*client_uuid*/> clients;
- };
- base::flat_map<int64_t /*version_id*/, ServiceWorkerInfo>
- service_worker_infos_;
- };
- TestServiceWorkerContext::TestServiceWorkerContext() = default;
- TestServiceWorkerContext::~TestServiceWorkerContext() = default;
- void TestServiceWorkerContext::AddObserver(
- content::ServiceWorkerContextObserver* observer) {
- observer_list_.AddObserver(observer);
- }
- void TestServiceWorkerContext::RemoveObserver(
- content::ServiceWorkerContextObserver* observer) {
- observer_list_.RemoveObserver(observer);
- }
- int64_t TestServiceWorkerContext::CreateServiceWorker() {
- // Create a new version ID and add it to the map.
- int64_t version_id = next_service_worker_instance_id_++;
- bool inserted = service_worker_infos_.insert({version_id, {}}).second;
- DCHECK(inserted);
- return version_id;
- }
- void TestServiceWorkerContext::DestroyServiceWorker(int64_t version_id) {
- auto it = service_worker_infos_.find(version_id);
- DCHECK(it != service_worker_infos_.end());
- const ServiceWorkerInfo& info = it->second;
- // Can only delete a service worker that isn't running and has no clients.
- DCHECK(!info.is_running);
- DCHECK(info.clients.empty());
- // Remove the worker instance from the map.
- service_worker_infos_.erase(it);
- }
- void TestServiceWorkerContext::StartServiceWorker(int64_t version_id,
- int worker_process_id) {
- auto it = service_worker_infos_.find(version_id);
- DCHECK(it != service_worker_infos_.end());
- ServiceWorkerInfo& info = it->second;
- DCHECK(!info.is_running);
- info.is_running = true;
- // Notify observers.
- GURL worker_url = GenerateWorkerUrl();
- GURL scope_url;
- for (auto& observer : observer_list_) {
- observer.OnVersionStartedRunning(
- version_id, content::ServiceWorkerRunningInfo(
- worker_url, scope_url,
- blink::StorageKey(url::Origin::Create(scope_url)),
- worker_process_id, blink::ServiceWorkerToken()));
- }
- }
- void TestServiceWorkerContext::StopServiceWorker(int64_t version_id) {
- auto it = service_worker_infos_.find(version_id);
- DCHECK(it != service_worker_infos_.end());
- ServiceWorkerInfo& info = it->second;
- DCHECK(info.is_running);
- info.is_running = false;
- // Notify observers that the worker is terminating.
- for (auto& observer : observer_list_)
- observer.OnVersionStoppedRunning(version_id);
- }
- std::string TestServiceWorkerContext::AddClient(
- int64_t version_id,
- const content::ServiceWorkerClientInfo& client_info) {
- return AddClientWithClientID(version_id, base::GenerateGUID(), client_info);
- }
- std::string TestServiceWorkerContext::AddClientWithClientID(
- int64_t version_id,
- std::string client_uuid,
- const content::ServiceWorkerClientInfo& client_info) {
- auto it = service_worker_infos_.find(version_id);
- DCHECK(it != service_worker_infos_.end());
- ServiceWorkerInfo& info = it->second;
- bool inserted = info.clients.insert(client_uuid).second;
- DCHECK(inserted);
- for (auto& observer : observer_list_)
- observer.OnControlleeAdded(version_id, client_uuid, client_info);
- return client_uuid;
- }
- void TestServiceWorkerContext::RemoveClient(int64_t version_id,
- const std::string& client_uuid) {
- auto it = service_worker_infos_.find(version_id);
- DCHECK(it != service_worker_infos_.end());
- ServiceWorkerInfo& info = it->second;
- size_t removed = info.clients.erase(client_uuid);
- DCHECK_EQ(removed, 1u);
- for (auto& observer : observer_list_)
- observer.OnControlleeRemoved(version_id, client_uuid);
- }
- void TestServiceWorkerContext::OnControlleeNavigationCommitted(
- int64_t version_id,
- const std::string& client_uuid,
- content::GlobalRenderFrameHostId render_frame_host_id) {
- auto it = service_worker_infos_.find(version_id);
- DCHECK(it != service_worker_infos_.end());
- ServiceWorkerInfo& info = it->second;
- DCHECK(base::Contains(info.clients, client_uuid));
- for (auto& observer : observer_list_) {
- observer.OnControlleeNavigationCommitted(version_id, client_uuid,
- render_frame_host_id);
- }
- }
- // TestProcessNodeSource -------------------------------------------------------
- // A test ProcessNodeSource that allows creating process nodes on demand to
- // "host" frames and workers.
- class TestProcessNodeSource : public ProcessNodeSource {
- public:
- TestProcessNodeSource();
- TestProcessNodeSource(const TestProcessNodeSource&) = delete;
- TestProcessNodeSource& operator=(const TestProcessNodeSource&) = delete;
- ~TestProcessNodeSource() override;
- // ProcessNodeSource:
- ProcessNodeImpl* GetProcessNode(int render_process_id) override;
- // Creates a process node and returns its generated render process ID.
- int CreateProcessNode();
- private:
- // Maps render process IDs with their associated process node.
- base::flat_map<int, std::unique_ptr<ProcessNodeImpl>> process_node_map_;
- };
- TestProcessNodeSource::TestProcessNodeSource() = default;
- TestProcessNodeSource::~TestProcessNodeSource() {
- std::vector<std::unique_ptr<NodeBase>> nodes;
- nodes.reserve(process_node_map_.size());
- for (auto& kv : process_node_map_) {
- std::unique_ptr<ProcessNodeImpl> process_node = std::move(kv.second);
- nodes.push_back(std::move(process_node));
- }
- PerformanceManagerImpl::BatchDeleteNodes(std::move(nodes));
- process_node_map_.clear();
- }
- ProcessNodeImpl* TestProcessNodeSource::GetProcessNode(int render_process_id) {
- auto it = process_node_map_.find(render_process_id);
- DCHECK(it != process_node_map_.end());
- return it->second.get();
- }
- int TestProcessNodeSource::CreateProcessNode() {
- // Generate a render process ID for this process node.
- int render_process_id = GenerateNextId();
- // Create the process node and insert it into the map.
- auto process_node = PerformanceManagerImpl::CreateProcessNode(
- content::PROCESS_TYPE_RENDERER, RenderProcessHostProxy());
- bool inserted =
- process_node_map_.insert({render_process_id, std::move(process_node)})
- .second;
- DCHECK(inserted);
- return render_process_id;
- }
- // TestFrameNodeSource ---------------------------------------------------------
- class TestFrameNodeSource : public FrameNodeSource {
- public:
- TestFrameNodeSource();
- TestFrameNodeSource(const TestFrameNodeSource&) = delete;
- TestFrameNodeSource& operator=(const TestFrameNodeSource&) = delete;
- ~TestFrameNodeSource() override;
- // FrameNodeSource:
- FrameNodeImpl* GetFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id) override;
- void SubscribeToFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id,
- OnbeforeFrameNodeRemovedCallback on_before_frame_node_removed_callback)
- override;
- void UnsubscribeFromFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id) override;
- // Creates a frame node and returns its generated render frame host id.
- content::GlobalRenderFrameHostId CreateFrameNode(
- int render_process_id,
- ProcessNodeImpl* process_node);
- // Deletes an existing frame node and notify subscribers.
- void DeleteFrameNode(content::GlobalRenderFrameHostId render_frame_host_id);
- private:
- // Helper function that invokes the OnBeforeFrameNodeRemovedCallback
- // associated with |frame_node| and removes it from the map.
- void InvokeAndRemoveCallback(FrameNodeImpl* frame_node);
- // The page node that hosts all frames.
- std::unique_ptr<PageNodeImpl> page_node_;
- // Maps each frame's render frame host id with their associated frame node.
- base::flat_map<content::GlobalRenderFrameHostId,
- std::unique_ptr<FrameNodeImpl>>
- frame_node_map_;
- // Maps each observed frame node to their callback.
- base::flat_map<FrameNodeImpl*, OnbeforeFrameNodeRemovedCallback>
- frame_node_callbacks_;
- };
- TestFrameNodeSource::TestFrameNodeSource()
- : page_node_(PerformanceManagerImpl::CreatePageNode(
- WebContentsProxy(),
- "page_node_context_id",
- GURL(),
- false,
- false,
- base::TimeTicks::Now(),
- PageNode::PageState::kActive)) {}
- TestFrameNodeSource::~TestFrameNodeSource() {
- std::vector<std::unique_ptr<NodeBase>> nodes;
- nodes.push_back(std::move(page_node_));
- nodes.reserve(frame_node_map_.size());
- for (auto& kv : frame_node_map_)
- nodes.push_back(std::move(kv.second));
- PerformanceManagerImpl::BatchDeleteNodes(std::move(nodes));
- frame_node_map_.clear();
- }
- FrameNodeImpl* TestFrameNodeSource::GetFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id) {
- auto it = frame_node_map_.find(render_frame_host_id);
- return it != frame_node_map_.end() ? it->second.get() : nullptr;
- }
- void TestFrameNodeSource::SubscribeToFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id,
- OnbeforeFrameNodeRemovedCallback on_before_frame_node_removed_callback) {
- FrameNodeImpl* frame_node = GetFrameNode(render_frame_host_id);
- DCHECK(frame_node);
- bool inserted =
- frame_node_callbacks_
- .emplace(frame_node, std::move(on_before_frame_node_removed_callback))
- .second;
- DCHECK(inserted);
- }
- void TestFrameNodeSource::UnsubscribeFromFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id) {
- FrameNodeImpl* frame_node = GetFrameNode(render_frame_host_id);
- DCHECK(frame_node);
- size_t removed = frame_node_callbacks_.erase(frame_node);
- DCHECK_EQ(removed, 1u);
- }
- content::GlobalRenderFrameHostId TestFrameNodeSource::CreateFrameNode(
- int render_process_id,
- ProcessNodeImpl* process_node) {
- int frame_id = GenerateNextId();
- content::GlobalRenderFrameHostId render_frame_host_id(render_process_id,
- frame_id);
- auto frame_node = PerformanceManagerImpl::CreateFrameNode(
- process_node, page_node_.get(), nullptr, frame_id,
- blink::LocalFrameToken(), content::BrowsingInstanceId(0),
- content::SiteInstanceId(0));
- bool inserted =
- frame_node_map_.insert({render_frame_host_id, std::move(frame_node)})
- .second;
- DCHECK(inserted);
- return render_frame_host_id;
- }
- void TestFrameNodeSource::DeleteFrameNode(
- content::GlobalRenderFrameHostId render_frame_host_id) {
- auto it = frame_node_map_.find(render_frame_host_id);
- DCHECK(it != frame_node_map_.end());
- FrameNodeImpl* frame_node = it->second.get();
- // Notify the subscriber then delete the node.
- InvokeAndRemoveCallback(frame_node);
- PerformanceManagerImpl::DeleteNode(std::move(it->second));
- frame_node_map_.erase(it);
- }
- void TestFrameNodeSource::InvokeAndRemoveCallback(FrameNodeImpl* frame_node) {
- auto it = frame_node_callbacks_.find(frame_node);
- DCHECK(it != frame_node_callbacks_.end());
- std::move(it->second).Run(frame_node);
- frame_node_callbacks_.erase(it);
- }
- } // namespace
- class WorkerWatcherTest : public testing::Test {
- public:
- WorkerWatcherTest();
- WorkerWatcherTest(const WorkerWatcherTest&) = delete;
- WorkerWatcherTest& operator=(const WorkerWatcherTest&) = delete;
- ~WorkerWatcherTest() override;
- // testing::Test:
- void SetUp() override;
- void TearDown() override;
- // Wraps a |graph_callback| and ensures the task completes before returning.
- void CallOnGraphAndWait(
- PerformanceManagerImpl::GraphImplCallback graph_callback);
- // Retrieves an existing worker node.
- WorkerNodeImpl* GetDedicatedWorkerNode(
- const blink::DedicatedWorkerToken& token);
- WorkerNodeImpl* GetSharedWorkerNode(
- const blink::SharedWorkerToken& shared_worker_token);
- WorkerNodeImpl* GetServiceWorkerNode(int64_t version_id);
- TestDedicatedWorkerService* dedicated_worker_service() {
- return &dedicated_worker_service_;
- }
- TestSharedWorkerService* shared_worker_service() {
- return &shared_worker_service_;
- }
- TestServiceWorkerContext* service_worker_context() {
- return &service_worker_context_;
- }
- TestProcessNodeSource* process_node_source() {
- return process_node_source_.get();
- }
- TestFrameNodeSource* frame_node_source() { return frame_node_source_.get(); }
- protected:
- // Test the frame destroyed case with or without service worker relationship
- void TestFrameDestroyed(bool enable_service_worker_relationships);
- private:
- content::BrowserTaskEnvironment task_environment_;
- TestDedicatedWorkerService dedicated_worker_service_;
- TestSharedWorkerService shared_worker_service_;
- TestServiceWorkerContext service_worker_context_;
- std::unique_ptr<PerformanceManagerImpl> performance_manager_;
- std::unique_ptr<TestProcessNodeSource> process_node_source_;
- std::unique_ptr<TestFrameNodeSource> frame_node_source_;
- // The WorkerWatcher that's being tested.
- std::unique_ptr<WorkerWatcher> worker_watcher_;
- };
- WorkerWatcherTest::WorkerWatcherTest() = default;
- WorkerWatcherTest::~WorkerWatcherTest() = default;
- void WorkerWatcherTest::SetUp() {
- performance_manager_ = PerformanceManagerImpl::Create(base::DoNothing());
- process_node_source_ = std::make_unique<TestProcessNodeSource>();
- frame_node_source_ = std::make_unique<TestFrameNodeSource>();
- worker_watcher_ = std::make_unique<WorkerWatcher>(
- "browser_context_id", &dedicated_worker_service_, &shared_worker_service_,
- &service_worker_context_, process_node_source_.get(),
- frame_node_source_.get());
- }
- void WorkerWatcherTest::TearDown() {
- // Clean up the performance manager correctly.
- worker_watcher_->TearDown();
- worker_watcher_ = nullptr;
- // Delete the TestFrameNodeSource and the TestProcessNodeSource in
- // that order since they own graph nodes.
- frame_node_source_ = nullptr;
- process_node_source_ = nullptr;
- PerformanceManagerImpl::Destroy(std::move(performance_manager_));
- }
- void WorkerWatcherTest::CallOnGraphAndWait(
- PerformanceManagerImpl::GraphImplCallback graph_callback) {
- base::RunLoop run_loop;
- PerformanceManagerImpl::CallOnGraphImpl(
- FROM_HERE,
- base::BindLambdaForTesting(
- [graph_callback = std::move(graph_callback),
- quit_closure = run_loop.QuitClosure()](GraphImpl* graph) mutable {
- std::move(graph_callback).Run(graph);
- quit_closure.Run();
- }));
- run_loop.Run();
- }
- WorkerNodeImpl* WorkerWatcherTest::GetDedicatedWorkerNode(
- const blink::DedicatedWorkerToken& token) {
- return worker_watcher_->GetDedicatedWorkerNode(token);
- }
- WorkerNodeImpl* WorkerWatcherTest::GetSharedWorkerNode(
- const blink::SharedWorkerToken& shared_worker_token) {
- return worker_watcher_->GetSharedWorkerNode(shared_worker_token);
- }
- WorkerNodeImpl* WorkerWatcherTest::GetServiceWorkerNode(int64_t version_id) {
- return worker_watcher_->GetServiceWorkerNode(version_id);
- }
- // This test creates one dedicated worker.
- TEST_F(WorkerWatcherTest, SimpleDedicatedWorker) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create the frame node.
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- // Create the worker.
- const blink::DedicatedWorkerToken token =
- dedicated_worker_service()->CreateDedicatedWorker(render_process_id,
- render_frame_host_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- worker_node = GetDedicatedWorkerNode(token),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(),
- WorkerNode::WorkerType::kDedicated);
- EXPECT_EQ(worker_node->process_node(), process_node);
- EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node));
- }));
- // Disconnect and clean up the dedicated worker.
- dedicated_worker_service()->DestroyDedicatedWorker(token);
- }
- // This test creates one shared worker with one client frame.
- TEST_F(WorkerWatcherTest, SimpleSharedWorker) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create the frame node.
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- // Create the worker.
- const blink::SharedWorkerToken shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- // Connect the frame to the worker.
- shared_worker_service()->AddClient(shared_worker_token, render_frame_host_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- worker_node = GetSharedWorkerNode(shared_worker_token),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kShared);
- EXPECT_EQ(worker_node->process_node(), process_node);
- EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node));
- }));
- // Disconnect and clean up the shared worker.
- shared_worker_service()->RemoveClient(shared_worker_token,
- render_frame_host_id);
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- }
- // This test creates one service worker with one client frame.
- TEST_F(WorkerWatcherTest, ServiceWorkerFrameClient) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create and start the service worker.
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Add a window client of the service worker.
- std::string service_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kService);
- EXPECT_EQ(worker_node->process_node(), process_node);
- // The frame can not be connected to the service worker until its
- // render frame host is available, which happens when the navigation
- // commits.
- EXPECT_TRUE(worker_node->client_frames().empty());
- }));
- // Now simulate the navigation commit.
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- service_worker_context()->OnControlleeNavigationCommitted(
- service_worker_version_id, service_worker_client_uuid,
- render_frame_host_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- worker_node = GetServiceWorkerNode(service_worker_version_id),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kService);
- EXPECT_EQ(worker_node->process_node(), process_node);
- EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node));
- }));
- // Disconnect and clean up the service worker.
- service_worker_context()->RemoveClient(service_worker_version_id,
- service_worker_client_uuid);
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- }
- // Ensures that the WorkerWatcher handles the case where a frame with a service
- // worker is (briefly?) an uncommitted client of two versions. This presumably
- // happens on version update or some such, or perhaps when a frame is a
- // bona-fide client of two service workers. Apparently this happens quite
- // rarely in the field.
- TEST_F(WorkerWatcherTest, ServiceWorkerFrameClientOfTwoWorkers) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create and start both service workers.
- int64_t first_service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(first_service_worker_version_id,
- render_process_id);
- int64_t second_service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(second_service_worker_version_id,
- render_process_id);
- // Add a window client of the service worker.
- std::string service_worker_client_uuid = service_worker_context()->AddClient(
- first_service_worker_version_id, content::ServiceWorkerClientInfo());
- service_worker_context()->AddClientWithClientID(
- second_service_worker_version_id, service_worker_client_uuid,
- content::ServiceWorkerClientInfo());
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- first_worker_node =
- GetServiceWorkerNode(first_service_worker_version_id),
- second_worker_node = GetServiceWorkerNode(
- second_service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(first_worker_node));
- EXPECT_EQ(first_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(first_worker_node->process_node(), process_node);
- // The frame was never added as a client of the service worker.
- EXPECT_TRUE(first_worker_node->client_frames().empty());
- EXPECT_TRUE(graph->NodeInGraph(second_worker_node));
- EXPECT_EQ(second_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(second_worker_node->process_node(), process_node);
- // The frame was never added as a client of the service worker.
- EXPECT_TRUE(second_worker_node->client_frames().empty());
- }));
- // Disconnect and clean up the service worker.
- service_worker_context()->RemoveClient(first_service_worker_version_id,
- service_worker_client_uuid);
- service_worker_context()->StopServiceWorker(first_service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(
- first_service_worker_version_id);
- service_worker_context()->RemoveClient(second_service_worker_version_id,
- service_worker_client_uuid);
- service_worker_context()->StopServiceWorker(second_service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(
- second_service_worker_version_id);
- }
- // Ensures that the WorkerWatcher handles the case where a frame with a service
- // worker has a double client relationship with a service worker.
- // This appears to be happening out in the real world, if quite rarely.
- // See https://crbug.com/1143281#c33.
- TEST_F(WorkerWatcherTest, ServiceWorkerTwoFrameClientRelationships) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create and start a service worker.
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Add a window client of the service worker.
- std::string first_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kService);
- // The frame was not yet added as a client.
- EXPECT_TRUE(worker_node->client_frames().empty());
- }));
- // Add a second client relationship between the same two entities.
- std::string second_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- // Now simulate the navigation commit.
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- service_worker_context()->OnControlleeNavigationCommitted(
- service_worker_version_id, first_client_uuid, render_frame_host_id);
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(1u, service_worker_node->client_frames().size());
- EXPECT_TRUE(IsWorkerClient(service_worker_node, client_frame_node));
- }));
- // Commit the second controllee navigation.
- service_worker_context()->OnControlleeNavigationCommitted(
- service_worker_version_id, second_client_uuid, render_frame_host_id);
- // Verify that the graph is still the same.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(1u, service_worker_node->client_frames().size());
- EXPECT_TRUE(IsWorkerClient(service_worker_node, client_frame_node));
- }));
- // Remove the first client relationship.
- service_worker_context()->RemoveClient(service_worker_version_id,
- first_client_uuid);
- // Verify that the graph is still the same.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(1u, service_worker_node->client_frames().size());
- EXPECT_TRUE(IsWorkerClient(service_worker_node, client_frame_node));
- }));
- // Teardown.
- service_worker_context()->RemoveClient(service_worker_version_id,
- second_client_uuid);
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- }
- // Ensures that the WorkerWatcher handles the case where a frame with a service
- // worker is created but it's navigation is never committed before the
- // FrameTreeNode is destroyed.
- TEST_F(WorkerWatcherTest, ServiceWorkerFrameClientDestroyedBeforeCommit) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create and start the service worker.
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Add a window client of the service worker.
- std::string service_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kService);
- EXPECT_EQ(worker_node->process_node(), process_node);
- // The frame was never added as a client of the service worker.
- EXPECT_TRUE(worker_node->client_frames().empty());
- }));
- // Disconnect and clean up the service worker.
- service_worker_context()->RemoveClient(service_worker_version_id,
- service_worker_client_uuid);
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- }
- TEST_F(WorkerWatcherTest, AllTypesOfServiceWorkerClients) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create and start the service worker.
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Create a client of each type and connect them to the service worker.
- // Frame client.
- std::string frame_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- service_worker_context()->OnControlleeNavigationCommitted(
- service_worker_version_id, frame_client_uuid, render_frame_host_id);
- // Dedicated worker client.
- blink::DedicatedWorkerToken dedicated_worker_token =
- dedicated_worker_service()->CreateDedicatedWorker(render_process_id,
- render_frame_host_id);
- std::string dedicated_worker_client_uuid =
- service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(dedicated_worker_token));
- // Shared worker client.
- blink::SharedWorkerToken shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- std::string shared_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(shared_worker_token));
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- client_frame_node =
- frame_node_source()->GetFrameNode(render_frame_host_id),
- dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
- shared_worker_node =
- GetSharedWorkerNode(shared_worker_token)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_TRUE(IsWorkerClient(service_worker_node, client_frame_node));
- EXPECT_TRUE(IsWorkerClient(service_worker_node, dedicated_worker_node));
- EXPECT_TRUE(IsWorkerClient(service_worker_node, shared_worker_node));
- }));
- // Disconnect and clean up the service worker and its clients.
- service_worker_context()->RemoveClient(service_worker_version_id,
- shared_worker_client_uuid);
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- service_worker_context()->RemoveClient(service_worker_version_id,
- dedicated_worker_client_uuid);
- dedicated_worker_service()->DestroyDedicatedWorker(dedicated_worker_token);
- service_worker_context()->RemoveClient(service_worker_version_id,
- frame_client_uuid);
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- }
- // Tests that the WorkerWatcher can handle the case where the service worker
- // starts after it has been assigned a client. In this case, the clients are not
- // connected to the service worker until it starts. It also tests that when the
- // service worker stops, its existing clients are also disconnected.
- TEST_F(WorkerWatcherTest, ServiceWorkerStartsAndStopsWithExistingClients) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create the worker.
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- // Create a client of each type and connect them to the service worker.
- // Frame client.
- std::string frame_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- service_worker_context()->OnControlleeNavigationCommitted(
- service_worker_version_id, frame_client_uuid, render_frame_host_id);
- // Dedicated worker client.
- blink::DedicatedWorkerToken dedicated_worker_token =
- dedicated_worker_service()->CreateDedicatedWorker(render_process_id,
- render_frame_host_id);
- std::string dedicated_worker_client_uuid =
- service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(dedicated_worker_token));
- // Shared worker client.
- blink::SharedWorkerToken shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- std::string shared_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(shared_worker_token));
- // The service worker node doesn't even exist yet.
- EXPECT_FALSE(GetServiceWorkerNode(service_worker_version_id));
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- frame_node = frame_node_source()->GetFrameNode(render_frame_host_id),
- dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
- shared_worker_node =
- GetSharedWorkerNode(shared_worker_token)](GraphImpl* graph) {
- // The clients exists in the graph but they are not connected to the
- // service worker.
- EXPECT_TRUE(graph->NodeInGraph(frame_node));
- EXPECT_TRUE(graph->NodeInGraph(dedicated_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(shared_worker_node));
- // Note: Because a dedicated worker is always connected to a frame, this
- // frame node actually has |dedicated_worker_node| as its sole client.
- ASSERT_EQ(frame_node->child_worker_nodes().size(), 1u);
- EXPECT_TRUE(base::Contains(frame_node->child_worker_nodes(),
- dedicated_worker_node));
- EXPECT_TRUE(dedicated_worker_node->child_workers().empty());
- EXPECT_TRUE(shared_worker_node->child_workers().empty());
- }));
- // Now start the service worker.
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- frame_node = frame_node_source()->GetFrameNode(render_frame_host_id),
- dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
- shared_worker_node =
- GetSharedWorkerNode(shared_worker_token)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(service_worker_node->process_node(), process_node);
- EXPECT_TRUE(graph->NodeInGraph(frame_node));
- EXPECT_TRUE(graph->NodeInGraph(dedicated_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(shared_worker_node));
- // Now is it correctly hooked up.
- EXPECT_TRUE(IsWorkerClient(service_worker_node, frame_node));
- EXPECT_TRUE(IsWorkerClient(service_worker_node, dedicated_worker_node));
- EXPECT_TRUE(IsWorkerClient(service_worker_node, shared_worker_node));
- }));
- // Stop the service worker. All the clients will be disconnected.
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- frame_node = frame_node_source()->GetFrameNode(render_frame_host_id),
- dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
- shared_worker_node =
- GetSharedWorkerNode(shared_worker_token)](GraphImpl* graph) {
- // The clients exists in the graph but they are not connected to the
- // service worker.
- EXPECT_TRUE(graph->NodeInGraph(frame_node));
- EXPECT_TRUE(graph->NodeInGraph(dedicated_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(shared_worker_node));
- // Note: Because a dedicated worker is always connected to a frame, this
- // frame node actually has |dedicated_worker_node| as its sole client.
- ASSERT_EQ(frame_node->child_worker_nodes().size(), 1u);
- EXPECT_TRUE(base::Contains(frame_node->child_worker_nodes(),
- dedicated_worker_node));
- EXPECT_TRUE(dedicated_worker_node->child_workers().empty());
- EXPECT_TRUE(shared_worker_node->child_workers().empty());
- }));
- // Disconnect and clean up the service worker and its clients
- service_worker_context()->RemoveClient(service_worker_version_id,
- shared_worker_client_uuid);
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- service_worker_context()->RemoveClient(service_worker_version_id,
- dedicated_worker_client_uuid);
- dedicated_worker_service()->DestroyDedicatedWorker(dedicated_worker_token);
- service_worker_context()->RemoveClient(service_worker_version_id,
- frame_client_uuid);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- }
- TEST_F(WorkerWatcherTest, SharedWorkerCrossProcessClient) {
- // Create the frame node.
- int frame_process_id = process_node_source()->CreateProcessNode();
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- frame_process_id,
- process_node_source()->GetProcessNode(frame_process_id));
- // Create the worker in a different process.
- int worker_process_id = process_node_source()->CreateProcessNode();
- const blink::SharedWorkerToken& shared_worker_token =
- shared_worker_service()->CreateSharedWorker(worker_process_id);
- // Connect the frame to the worker.
- shared_worker_service()->AddClient(shared_worker_token, render_frame_host_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [worker_process_node =
- process_node_source()->GetProcessNode(worker_process_id),
- worker_node = GetSharedWorkerNode(shared_worker_token),
- client_process_node =
- process_node_source()->GetProcessNode(frame_process_id),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kShared);
- EXPECT_EQ(worker_node->process_node(), worker_process_node);
- EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node));
- }));
- // Disconnect and clean up the shared worker.
- shared_worker_service()->RemoveClient(shared_worker_token,
- render_frame_host_id);
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- }
- // Tests that the WorkerWatcher can handle the case where the service worker
- // starts after it has been assigned a worker client, but the client has
- // already died by the time the service worker starts.
- TEST_F(WorkerWatcherTest, SharedWorkerStartsWithDeadWorkerClients) {
- int render_process_id = process_node_source()->CreateProcessNode();
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- // Create the worker.
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- // Create a worker client of each type and connect them to the service worker.
- // Dedicated worker client.
- blink::DedicatedWorkerToken dedicated_worker_token =
- dedicated_worker_service()->CreateDedicatedWorker(render_process_id,
- render_frame_host_id);
- std::string dedicated_worker_client_uuid =
- service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(dedicated_worker_token));
- // Shared worker client.
- blink::SharedWorkerToken shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- std::string shared_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(shared_worker_token));
- // Destroy the workers before the service worker starts.
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- dedicated_worker_service()->DestroyDedicatedWorker(dedicated_worker_token);
- // Now start the service worker.
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(service_worker_node->process_node(), process_node);
- EXPECT_TRUE(service_worker_node->child_workers().empty());
- }));
- // Disconnect the non-existent clients.
- service_worker_context()->RemoveClient(service_worker_version_id,
- shared_worker_client_uuid);
- service_worker_context()->RemoveClient(service_worker_version_id,
- dedicated_worker_client_uuid);
- // No changes in the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [process_node = process_node_source()->GetProcessNode(render_process_id),
- service_worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_EQ(service_worker_node->process_node(), process_node);
- EXPECT_TRUE(service_worker_node->child_workers().empty());
- }));
- // Stop and destroy the service worker.
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- }
- TEST_F(WorkerWatcherTest, SharedWorkerDiesAsServiceWorkerClient) {
- // Create the shared and service workers.
- int render_process_id = process_node_source()->CreateProcessNode();
- const blink::SharedWorkerToken& shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- std::string service_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id,
- content::ServiceWorkerClientInfo(shared_worker_token));
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- shared_worker_node =
- GetSharedWorkerNode(shared_worker_token)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_TRUE(graph->NodeInGraph(shared_worker_node));
- EXPECT_EQ(shared_worker_node->worker_type(),
- WorkerNode::WorkerType::kShared);
- EXPECT_TRUE(IsWorkerClient(service_worker_node, shared_worker_node));
- }));
- // Destroy the shared worker while it still has a client registration
- // against the service worker.
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- // Check expectations on the graph again.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [service_worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_EQ(service_worker_node->worker_type(),
- WorkerNode::WorkerType::kService);
- EXPECT_TRUE(service_worker_node->client_workers().empty());
- }));
- // Issue the trailing service worker client removal.
- service_worker_context()->RemoveClient(service_worker_version_id,
- service_worker_client_uuid);
- }
- TEST_F(WorkerWatcherTest, OneSharedWorkerTwoClients) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create the worker.
- const blink::SharedWorkerToken& shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- // Create 2 client frame nodes and connect them to the worker.
- content::GlobalRenderFrameHostId render_frame_host_id_1 =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- shared_worker_service()->AddClient(shared_worker_token,
- render_frame_host_id_1);
- content::GlobalRenderFrameHostId render_frame_host_id_2 =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- shared_worker_service()->AddClient(shared_worker_token,
- render_frame_host_id_2);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [worker_node = GetSharedWorkerNode(shared_worker_token),
- client_frame_node_1 =
- frame_node_source()->GetFrameNode(render_frame_host_id_1),
- client_frame_node_2 = frame_node_source()->GetFrameNode(
- render_frame_host_id_2)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(worker_node));
- EXPECT_EQ(worker_node->worker_type(), WorkerNode::WorkerType::kShared);
- // Check frame 1.
- EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node_1));
- // Check frame 2.
- EXPECT_TRUE(IsWorkerClient(worker_node, client_frame_node_2));
- }));
- // Disconnect and clean up the shared worker.
- shared_worker_service()->RemoveClient(shared_worker_token,
- render_frame_host_id_1);
- shared_worker_service()->RemoveClient(shared_worker_token,
- render_frame_host_id_2);
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- }
- TEST_F(WorkerWatcherTest, OneClientTwoSharedWorkers) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create the frame node.
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- // Create the 2 workers and connect them to the frame.
- const blink::SharedWorkerToken& shared_worker_token_1 =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- shared_worker_service()->AddClient(shared_worker_token_1,
- render_frame_host_id);
- const blink::SharedWorkerToken& shared_worker_token_2 =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- shared_worker_service()->AddClient(shared_worker_token_2,
- render_frame_host_id);
- // Check expectations on the graph.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [worker_node_1 = GetSharedWorkerNode(shared_worker_token_1),
- worker_node_2 = GetSharedWorkerNode(shared_worker_token_2),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- // Check worker 1.
- EXPECT_TRUE(graph->NodeInGraph(worker_node_1));
- EXPECT_EQ(worker_node_1->worker_type(),
- WorkerNode::WorkerType::kShared);
- EXPECT_TRUE(IsWorkerClient(worker_node_1, client_frame_node));
- // Check worker 2.
- EXPECT_TRUE(graph->NodeInGraph(worker_node_2));
- EXPECT_EQ(worker_node_2->worker_type(),
- WorkerNode::WorkerType::kShared);
- EXPECT_TRUE(IsWorkerClient(worker_node_2, client_frame_node));
- }));
- // Disconnect and clean up the shared workers.
- shared_worker_service()->RemoveClient(shared_worker_token_1,
- render_frame_host_id);
- shared_worker_service()->DestroySharedWorker(shared_worker_token_1);
- shared_worker_service()->RemoveClient(shared_worker_token_2,
- render_frame_host_id);
- shared_worker_service()->DestroySharedWorker(shared_worker_token_2);
- }
- TEST_F(WorkerWatcherTest, FrameDestroyed) {
- int render_process_id = process_node_source()->CreateProcessNode();
- // Create the frame node.
- content::GlobalRenderFrameHostId render_frame_host_id =
- frame_node_source()->CreateFrameNode(
- render_process_id,
- process_node_source()->GetProcessNode(render_process_id));
- // Create a worker of each type.
- const blink::DedicatedWorkerToken& dedicated_worker_token =
- dedicated_worker_service()->CreateDedicatedWorker(render_process_id,
- render_frame_host_id);
- const blink::SharedWorkerToken& shared_worker_token =
- shared_worker_service()->CreateSharedWorker(render_process_id);
- int64_t service_worker_version_id =
- service_worker_context()->CreateServiceWorker();
- service_worker_context()->StartServiceWorker(service_worker_version_id,
- render_process_id);
- // Connect the frame to the shared worker and the service worker. Note that it
- // is already connected to the dedicated worker.
- shared_worker_service()->AddClient(shared_worker_token, render_frame_host_id);
- std::string service_worker_client_uuid = service_worker_context()->AddClient(
- service_worker_version_id, content::ServiceWorkerClientInfo());
- service_worker_context()->OnControlleeNavigationCommitted(
- service_worker_version_id, service_worker_client_uuid,
- render_frame_host_id);
- // Check that everything is wired up correctly.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
- shared_worker_node = GetSharedWorkerNode(shared_worker_token),
- service_worker_node = GetServiceWorkerNode(service_worker_version_id),
- client_frame_node = frame_node_source()->GetFrameNode(
- render_frame_host_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(dedicated_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(shared_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_TRUE(IsWorkerClient(dedicated_worker_node, client_frame_node));
- EXPECT_TRUE(IsWorkerClient(shared_worker_node, client_frame_node));
- EXPECT_TRUE(IsWorkerClient(service_worker_node, client_frame_node));
- }));
- frame_node_source()->DeleteFrameNode(render_frame_host_id);
- // Check that the workers are no longer connected to the deleted frame.
- CallOnGraphAndWait(base::BindLambdaForTesting(
- [dedicated_worker_node = GetDedicatedWorkerNode(dedicated_worker_token),
- shared_worker_node = GetSharedWorkerNode(shared_worker_token),
- service_worker_node =
- GetServiceWorkerNode(service_worker_version_id)](GraphImpl* graph) {
- EXPECT_TRUE(graph->NodeInGraph(dedicated_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(shared_worker_node));
- EXPECT_TRUE(graph->NodeInGraph(service_worker_node));
- EXPECT_TRUE(dedicated_worker_node->client_frames().empty());
- EXPECT_TRUE(shared_worker_node->client_frames().empty());
- EXPECT_TRUE(service_worker_node->client_frames().empty());
- }));
- // Clean up. The watcher is still expecting a worker removed notification.
- service_worker_context()->RemoveClient(service_worker_version_id,
- service_worker_client_uuid);
- service_worker_context()->StopServiceWorker(service_worker_version_id);
- service_worker_context()->DestroyServiceWorker(service_worker_version_id);
- shared_worker_service()->RemoveClient(shared_worker_token,
- render_frame_host_id);
- shared_worker_service()->DestroySharedWorker(shared_worker_token);
- dedicated_worker_service()->DestroyDedicatedWorker(dedicated_worker_token);
- }
- } // namespace performance_manager
|