blob: 9e1de54fb6c5f36aff9cf148a89be3cfae452c2e [file] [log] [blame]
Devlin Cronin1fc76f32021-09-15 01:39:341// Copyright 2021 The Chromium Authors. All rights reserved.
2// 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)
21 : extension_id_(std::move(extension_id)) {
22 host_registry_observation_.Observe(
23 ExtensionHostRegistry::Get(browser_context));
24}
25
26ExtensionHostTestHelper::~ExtensionHostTestHelper() = default;
27
Devlin Cronin7cfe13b2021-09-29 16:24:3228void ExtensionHostTestHelper::RestrictToType(mojom::ViewType type) {
29 // Restricting to both a specific host and a type is either redundant (if
30 // the types match) or contradictory (if they don't). Don't allow it.
31 DCHECK(!restrict_to_host_) << "Can't restrict to both a host and view type.";
32 restrict_to_type_ = type;
33}
34
35void ExtensionHostTestHelper::RestrictToHost(const ExtensionHost* host) {
36 // Restricting to both a specific host and a type is either redundant (if
37 // the types match) or contradictory (if they don't). Don't allow it.
38 DCHECK(!restrict_to_type_) << "Can't restrict to both a host and view type.";
39 restrict_to_host_ = host;
40}
41
Devlin Cronin6ce3a19b2021-09-28 01:39:5142void ExtensionHostTestHelper::OnExtensionHostRenderProcessReady(
Devlin Cronin30eb24f2021-09-17 19:26:4343 content::BrowserContext* browser_context,
44 ExtensionHost* host) {
Devlin Cronin6ce3a19b2021-09-28 01:39:5145 EventSeen(host, HostEvent::kRenderProcessReady);
Devlin Cronin30eb24f2021-09-17 19:26:4346}
47
Devlin Cronin86f02edf2021-09-27 23:18:2748void ExtensionHostTestHelper::OnExtensionHostDocumentElementAvailable(
49 content::BrowserContext* browser_context,
50 ExtensionHost* host) {
51 EventSeen(host, HostEvent::kDocumentElementAvailable);
52}
53
Devlin Cronin58ac6f7752021-09-21 19:06:3754void ExtensionHostTestHelper::OnExtensionHostCompletedFirstLoad(
55 content::BrowserContext* browser_context,
56 ExtensionHost* host) {
57 EventSeen(host, HostEvent::kCompletedFirstLoad);
58}
59
Devlin Cronin1fc76f32021-09-15 01:39:3460void ExtensionHostTestHelper::OnExtensionHostDestroyed(
61 content::BrowserContext* browser_context,
62 ExtensionHost* host) {
63 EventSeen(host, HostEvent::kDestroyed);
64}
65
Devlin Cronin30eb24f2021-09-17 19:26:4366ExtensionHost* ExtensionHostTestHelper::WaitFor(HostEvent event) {
Devlin Cronin1fc76f32021-09-15 01:39:3467 DCHECK(!waiting_for_);
68
Devlin Cronin30eb24f2021-09-17 19:26:4369 auto iter = observed_events_.find(event);
70 if (iter != observed_events_.end()) {
71 // Note: This can be null if the host has been destroyed.
72 return iter->second;
73 }
Devlin Cronin1fc76f32021-09-15 01:39:3474
75 base::RunLoop run_loop;
76 // Note: We use QuitWhenIdle (instead of Quit) so that any other listeners of
77 // the relevant events get a chance to run first.
78 quit_loop_ = run_loop.QuitWhenIdleClosure();
79 waiting_for_ = event;
80 run_loop.Run();
Devlin Cronin30eb24f2021-09-17 19:26:4381
82 DCHECK(base::Contains(observed_events_, event));
83 // Note: This can still be null here if the corresponding ExtensionHost was
84 // destroyed. This is always true when waiting for
85 // OnExtensionHostDestroyed(), but can also happen if the ExtensionHost is
86 // destroyed while waiting for the run loop to idle.
87 return observed_events_[event];
Devlin Cronin1fc76f32021-09-15 01:39:3488}
89
90void ExtensionHostTestHelper::EventSeen(ExtensionHost* host, HostEvent event) {
91 // Check if the host matches our restrictions.
92 if (!extension_id_.empty() && host->extension_id() != extension_id_)
93 return;
Devlin Cronin86f02edf2021-09-27 23:18:2794 if (restrict_to_type_ && host->extension_host_type() != restrict_to_type_)
95 return;
Devlin Cronin7cfe13b2021-09-29 16:24:3296 if (restrict_to_host_ && host != restrict_to_host_)
97 return;
Devlin Cronin1fc76f32021-09-15 01:39:3498
Devlin Cronin30eb24f2021-09-17 19:26:4399 if (event == HostEvent::kDestroyed) {
100 // Clean up all old pointers to the ExtensionHost on its destruction.
101 for (auto& kv : observed_events_) {
102 if (kv.second == host)
103 kv.second = nullptr;
104 }
105
106 // Ensure we don't put a new pointer for the host into the map.
107 host = nullptr;
108 }
109
110 observed_events_[event] = host;
111
Devlin Cronin1fc76f32021-09-15 01:39:34112 if (waiting_for_ == event) {
113 DCHECK(quit_loop_);
114 waiting_for_.reset();
115 std::move(quit_loop_).Run();
116 }
117}
118
119} // namespace extensions