blob: fc9cca8f107236b3bb3d974f334b230a0154665c [file] [log] [blame]
Avi Drissman60039d42022-09-13 21:49:051// Copyright 2021 The Chromium Authors
Devlin Cronin1fc76f32021-09-15 01:39:342// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "extensions/browser/extension_host_test_helper.h"
6
Devlin Cronin7cfe13b2021-09-29 16:24:327#include "base/check.h"
Devlin Cronin1fc76f32021-09-15 01:39:348#include "base/containers/contains.h"
9#include "base/run_loop.h"
10#include "extensions/browser/extension_host.h"
11
12namespace extensions {
13
14ExtensionHostTestHelper::ExtensionHostTestHelper(
15 content::BrowserContext* browser_context)
16 : ExtensionHostTestHelper(browser_context, ExtensionId()) {}
17
18ExtensionHostTestHelper::ExtensionHostTestHelper(
19 content::BrowserContext* browser_context,
20 ExtensionId extension_id)
Devlin Croninc2fafd32021-09-29 17:20:3221 : browser_context_(browser_context),
22 extension_id_(std::move(extension_id)) {
Devlin Cronin1fc76f32021-09-15 01:39:3423 host_registry_observation_.Observe(
24 ExtensionHostRegistry::Get(browser_context));
25}
26
27ExtensionHostTestHelper::~ExtensionHostTestHelper() = default;
28
Devlin Cronin7cfe13b2021-09-29 16:24:3229void ExtensionHostTestHelper::RestrictToType(mojom::ViewType type) {
30 // Restricting to both a specific host and a type is either redundant (if
31 // the types match) or contradictory (if they don't). Don't allow it.
32 DCHECK(!restrict_to_host_) << "Can't restrict to both a host and view type.";
33 restrict_to_type_ = type;
34}
35
36void ExtensionHostTestHelper::RestrictToHost(const ExtensionHost* host) {
37 // Restricting to both a specific host and a type is either redundant (if
38 // the types match) or contradictory (if they don't). Don't allow it.
39 DCHECK(!restrict_to_type_) << "Can't restrict to both a host and view type.";
40 restrict_to_host_ = host;
41}
42
Devlin Cronin6ce3a19b2021-09-28 01:39:5143void ExtensionHostTestHelper::OnExtensionHostRenderProcessReady(
Devlin Cronin30eb24f2021-09-17 19:26:4344 content::BrowserContext* browser_context,
45 ExtensionHost* host) {
Devlin Cronin6ce3a19b2021-09-28 01:39:5146 EventSeen(host, HostEvent::kRenderProcessReady);
Devlin Cronin30eb24f2021-09-17 19:26:4347}
48
Devlin Cronin86f02edf2021-09-27 23:18:2749void ExtensionHostTestHelper::OnExtensionHostDocumentElementAvailable(
50 content::BrowserContext* browser_context,
51 ExtensionHost* host) {
52 EventSeen(host, HostEvent::kDocumentElementAvailable);
53}
54
Devlin Cronin58ac6f7752021-09-21 19:06:3755void ExtensionHostTestHelper::OnExtensionHostCompletedFirstLoad(
56 content::BrowserContext* browser_context,
57 ExtensionHost* host) {
58 EventSeen(host, HostEvent::kCompletedFirstLoad);
59}
60
Devlin Cronin1fc76f32021-09-15 01:39:3461void ExtensionHostTestHelper::OnExtensionHostDestroyed(
62 content::BrowserContext* browser_context,
63 ExtensionHost* host) {
64 EventSeen(host, HostEvent::kDestroyed);
65}
66
Devlin Croninb1433812021-10-14 18:26:1067void ExtensionHostTestHelper::OnExtensionHostRenderProcessGone(
68 content::BrowserContext* browser_context,
69 ExtensionHost* host) {
70 EventSeen(host, HostEvent::kRenderProcessGone);
71}
72
Devlin Cronin30eb24f2021-09-17 19:26:4373ExtensionHost* ExtensionHostTestHelper::WaitFor(HostEvent event) {
Devlin Cronin1fc76f32021-09-15 01:39:3474 DCHECK(!waiting_for_);
75
Devlin Cronin30eb24f2021-09-17 19:26:4376 auto iter = observed_events_.find(event);
77 if (iter != observed_events_.end()) {
78 // Note: This can be null if the host has been destroyed.
79 return iter->second;
80 }
Devlin Cronin1fc76f32021-09-15 01:39:3481
82 base::RunLoop run_loop;
83 // Note: We use QuitWhenIdle (instead of Quit) so that any other listeners of
84 // the relevant events get a chance to run first.
85 quit_loop_ = run_loop.QuitWhenIdleClosure();
86 waiting_for_ = event;
87 run_loop.Run();
Devlin Cronin30eb24f2021-09-17 19:26:4388
89 DCHECK(base::Contains(observed_events_, event));
90 // Note: This can still be null here if the corresponding ExtensionHost was
91 // destroyed. This is always true when waiting for
92 // OnExtensionHostDestroyed(), but can also happen if the ExtensionHost is
93 // destroyed while waiting for the run loop to idle.
94 return observed_events_[event];
Devlin Cronin1fc76f32021-09-15 01:39:3495}
96
97void ExtensionHostTestHelper::EventSeen(ExtensionHost* host, HostEvent event) {
98 // Check if the host matches our restrictions.
Devlin Croninc2fafd32021-09-29 17:20:3299 // Note: We have to check the browser context explicitly because the
100 // ExtensionHostRegistry is shared between on- and off-the-record profiles,
101 // so the `host`'s browser context may not be the same as the one associated
102 // with this object in the case of split mode extensions.
103 if (host->browser_context() != browser_context_)
104 return;
Devlin Cronin1fc76f32021-09-15 01:39:34105 if (!extension_id_.empty() && host->extension_id() != extension_id_)
106 return;
Devlin Cronin86f02edf2021-09-27 23:18:27107 if (restrict_to_type_ && host->extension_host_type() != restrict_to_type_)
108 return;
Devlin Cronin7cfe13b2021-09-29 16:24:32109 if (restrict_to_host_ && host != restrict_to_host_)
110 return;
Devlin Cronin1fc76f32021-09-15 01:39:34111
Devlin Cronin30eb24f2021-09-17 19:26:43112 if (event == HostEvent::kDestroyed) {
113 // Clean up all old pointers to the ExtensionHost on its destruction.
114 for (auto& kv : observed_events_) {
115 if (kv.second == host)
116 kv.second = nullptr;
117 }
118
119 // Ensure we don't put a new pointer for the host into the map.
120 host = nullptr;
121 }
122
123 observed_events_[event] = host;
124
Devlin Cronin1fc76f32021-09-15 01:39:34125 if (waiting_for_ == event) {
126 DCHECK(quit_loop_);
127 waiting_for_.reset();
128 std::move(quit_loop_).Run();
129 }
130}
131
132} // namespace extensions