OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_test_notification_observer.h" | 5 #include "extensions/test/extension_test_notification_observer.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include "content/public/browser/browser_context.h" |
8 | 8 #include "content/public/browser/notification_details.h" |
9 #include "base/callback_list.h" | |
10 #include "base/scoped_observer.h" | |
11 #include "chrome/browser/extensions/extension_action_test_util.h" | |
12 #include "chrome/browser/extensions/extension_service.h" | |
13 #include "chrome/browser/extensions/extension_util.h" | |
14 #include "chrome/browser/profiles/profile_manager.h" | |
15 #include "chrome/browser/ui/browser.h" | |
16 #include "chrome/browser/ui/browser_window.h" | |
17 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
18 #include "content/public/browser/notification_registrar.h" | 9 #include "content/public/browser/notification_registrar.h" |
19 #include "content/public/browser/notification_service.h" | 10 #include "content/public/browser/notification_service.h" |
20 #include "content/public/browser/render_view_host.h" | 11 #include "content/public/browser/render_frame_host.h" |
21 #include "content/public/test/test_utils.h" | 12 #include "content/public/test/test_utils.h" |
22 #include "extensions/browser/extension_system.h" | 13 #include "extensions/browser/extension_registry.h" |
| 14 #include "extensions/browser/notification_types.h" |
23 #include "extensions/browser/process_manager.h" | 15 #include "extensions/browser/process_manager.h" |
24 #include "extensions/browser/process_manager_observer.h" | |
25 #include "extensions/common/extension.h" | 16 #include "extensions/common/extension.h" |
26 | 17 |
27 using extensions::Extension; | 18 using extensions::Extension; |
28 | 19 |
29 namespace { | 20 namespace { |
30 | 21 |
31 // A callback that returns true if the condition has been met and takes no | 22 // A callback that returns true if the condition has been met and takes no |
32 // arguments. | 23 // arguments. |
33 typedef base::Callback<bool(void)> ConditionCallback; | 24 using ConditionCallback = base::Callback<bool(void)>; |
34 | 25 |
35 bool HasPageActionVisibilityReachedTarget( | 26 const Extension* GetNonTerminatedExtensions(const std::string& id, |
36 Browser* browser, size_t target_visible_page_action_count) { | 27 content::BrowserContext* context) { |
37 return extensions::extension_action_test_util::GetVisiblePageActionCount( | 28 return extensions::ExtensionRegistry::Get(context)->GetExtensionById( |
38 browser->tab_strip_model()->GetActiveWebContents()) == | 29 id, extensions::ExtensionRegistry::EVERYTHING & |
39 target_visible_page_action_count; | 30 ~extensions::ExtensionRegistry::TERMINATED); |
40 } | |
41 | |
42 bool HaveAllExtensionRenderFrameHostsFinishedLoading( | |
43 extensions::ProcessManager* manager) { | |
44 extensions::ProcessManager::FrameSet all_views = manager->GetAllFrames(); | |
45 for (content::RenderFrameHost* host : manager->GetAllFrames()) { | |
46 if (content::WebContents::FromRenderFrameHost(host)->IsLoading()) | |
47 return false; | |
48 } | |
49 return true; | |
50 } | |
51 | |
52 bool IsExtensionNotIdle(const std::string& extension_id, | |
53 content::BrowserContext* context) { | |
54 return !extensions::util::IsExtensionIdle(extension_id, context); | |
55 } | 31 } |
56 | 32 |
57 } // namespace | 33 } // namespace |
58 | 34 |
59 //////////////////////////////////////////////////////////////////////////////// | 35 //////////////////////////////////////////////////////////////////////////////// |
60 // ExtensionTestNotificationObserver::NotificationSet | 36 // ExtensionTestNotificationObserver::NotificationSet |
61 | 37 |
62 class ExtensionTestNotificationObserver::NotificationSet | 38 ExtensionTestNotificationObserver::NotificationSet::NotificationSet() |
63 : public content::NotificationObserver, | 39 : process_manager_observer_(this) {} |
64 public extensions::ProcessManagerObserver { | 40 ExtensionTestNotificationObserver::NotificationSet::~NotificationSet() {} |
65 public: | |
66 NotificationSet() : process_manager_observer_(this) {} | |
67 ~NotificationSet() override {} | |
68 | |
69 void Add(int type, const content::NotificationSource& source); | |
70 void Add(int type); | |
71 void AddExtensionFrameUnregistration(extensions::ProcessManager* manager); | |
72 | |
73 // Notified any time an Add()ed notification is received. | |
74 // The details of the notification are dropped. | |
75 base::CallbackList<void()>& callback_list() { | |
76 return callback_list_; | |
77 } | |
78 | |
79 private: | |
80 // content::NotificationObserver: | |
81 void Observe(int type, | |
82 const content::NotificationSource& source, | |
83 const content::NotificationDetails& details) override; | |
84 | |
85 // extensions::ProcessManagerObserver: | |
86 void OnExtensionFrameUnregistered( | |
87 const std::string& extension_id, | |
88 content::RenderFrameHost* render_frame_host) override; | |
89 | |
90 content::NotificationRegistrar notification_registrar_; | |
91 base::CallbackList<void()> callback_list_; | |
92 ScopedObserver<extensions::ProcessManager, extensions::ProcessManagerObserver> | |
93 process_manager_observer_; | |
94 }; | |
95 | 41 |
96 void ExtensionTestNotificationObserver::NotificationSet::Add( | 42 void ExtensionTestNotificationObserver::NotificationSet::Add( |
97 int type, | 43 int type, |
98 const content::NotificationSource& source) { | 44 const content::NotificationSource& source) { |
99 notification_registrar_.Add(this, type, source); | 45 notification_registrar_.Add(this, type, source); |
100 } | 46 } |
101 | 47 |
102 void ExtensionTestNotificationObserver::NotificationSet::Add(int type) { | 48 void ExtensionTestNotificationObserver::NotificationSet::Add(int type) { |
103 Add(type, content::NotificationService::AllSources()); | 49 Add(type, content::NotificationService::AllSources()); |
104 } | 50 } |
(...skipping 13 matching lines...) Expand all Loading... |
118 void ExtensionTestNotificationObserver::NotificationSet:: | 64 void ExtensionTestNotificationObserver::NotificationSet:: |
119 OnExtensionFrameUnregistered(const std::string& extension_id, | 65 OnExtensionFrameUnregistered(const std::string& extension_id, |
120 content::RenderFrameHost* render_frame_host) { | 66 content::RenderFrameHost* render_frame_host) { |
121 callback_list_.Notify(); | 67 callback_list_.Notify(); |
122 } | 68 } |
123 | 69 |
124 //////////////////////////////////////////////////////////////////////////////// | 70 //////////////////////////////////////////////////////////////////////////////// |
125 // ExtensionTestNotificationObserver | 71 // ExtensionTestNotificationObserver |
126 | 72 |
127 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver( | 73 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver( |
128 Browser* browser) | 74 content::BrowserContext* context) |
129 : browser_(browser), | 75 : context_(context), |
130 profile_(NULL), | |
131 extension_installs_observed_(0), | 76 extension_installs_observed_(0), |
132 extension_load_errors_observed_(0), | 77 extension_load_errors_observed_(0), |
133 crx_installers_done_observed_(0) { | 78 crx_installers_done_observed_(0) {} |
134 } | |
135 | 79 |
136 ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {} | 80 ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {} |
137 | 81 |
138 Profile* ExtensionTestNotificationObserver::GetProfile() { | |
139 if (!profile_) { | |
140 if (browser_) | |
141 profile_ = browser_->profile(); | |
142 else | |
143 profile_ = ProfileManager::GetActiveUserProfile(); | |
144 } | |
145 return profile_; | |
146 } | |
147 | |
148 void ExtensionTestNotificationObserver::WaitForNotification( | 82 void ExtensionTestNotificationObserver::WaitForNotification( |
149 int notification_type) { | 83 int notification_type) { |
150 // TODO(bauerb): Using a WindowedNotificationObserver like this can break | 84 // TODO(bauerb): Using a WindowedNotificationObserver like this can break |
151 // easily, if the notification we're waiting for is sent before this method. | 85 // easily, if the notification we're waiting for is sent before this method. |
152 // Change it so that the WindowedNotificationObserver is constructed earlier. | 86 // Change it so that the WindowedNotificationObserver is constructed earlier. |
153 content::NotificationRegistrar registrar; | 87 content::NotificationRegistrar registrar; |
154 registrar.Add( | 88 registrar.Add(this, notification_type, |
155 this, notification_type, content::NotificationService::AllSources()); | 89 content::NotificationService::AllSources()); |
156 content::WindowedNotificationObserver( | 90 content::WindowedNotificationObserver( |
157 notification_type, content::NotificationService::AllSources()).Wait(); | 91 notification_type, content::NotificationService::AllSources()) |
158 } | 92 .Wait(); |
159 | |
160 bool ExtensionTestNotificationObserver::WaitForPageActionVisibilityChangeTo( | |
161 int count) { | |
162 extensions::ExtensionActionAPI::Get(GetProfile())->AddObserver(this); | |
163 WaitForCondition( | |
164 base::Bind(&HasPageActionVisibilityReachedTarget, browser_, count), | |
165 NULL); | |
166 extensions::ExtensionActionAPI::Get(GetProfile())-> | |
167 RemoveObserver(this); | |
168 return true; | |
169 } | |
170 | |
171 bool ExtensionTestNotificationObserver::WaitForExtensionViewsToLoad() { | |
172 extensions::ProcessManager* manager = | |
173 extensions::ProcessManager::Get(GetProfile()); | |
174 NotificationSet notification_set; | |
175 notification_set.Add(content::NOTIFICATION_WEB_CONTENTS_DESTROYED); | |
176 notification_set.Add(content::NOTIFICATION_LOAD_STOP); | |
177 notification_set.AddExtensionFrameUnregistration(manager); | |
178 WaitForCondition( | |
179 base::Bind(&HaveAllExtensionRenderFrameHostsFinishedLoading, manager), | |
180 ¬ification_set); | |
181 return true; | |
182 } | |
183 | |
184 bool ExtensionTestNotificationObserver::WaitForExtensionIdle( | |
185 const std::string& extension_id) { | |
186 NotificationSet notification_set; | |
187 notification_set.Add(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED); | |
188 WaitForCondition(base::Bind(&extensions::util::IsExtensionIdle, extension_id, | |
189 GetProfile()), | |
190 ¬ification_set); | |
191 return true; | |
192 } | |
193 | |
194 bool ExtensionTestNotificationObserver::WaitForExtensionNotIdle( | |
195 const std::string& extension_id) { | |
196 NotificationSet notification_set; | |
197 notification_set.Add(content::NOTIFICATION_LOAD_STOP); | |
198 WaitForCondition(base::Bind(&IsExtensionNotIdle, extension_id, GetProfile()), | |
199 ¬ification_set); | |
200 return true; | |
201 } | 93 } |
202 | 94 |
203 bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() { | 95 bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() { |
204 int before = extension_installs_observed_; | 96 int before = extension_installs_observed_; |
205 content::WindowedNotificationObserver( | 97 content::WindowedNotificationObserver( |
206 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR, | 98 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR, |
207 content::NotificationService::AllSources()).Wait(); | 99 content::NotificationService::AllSources()) |
| 100 .Wait(); |
208 return extension_installs_observed_ == before; | 101 return extension_installs_observed_ == before; |
209 } | 102 } |
210 | 103 |
211 void ExtensionTestNotificationObserver::WaitForExtensionLoad() { | 104 void ExtensionTestNotificationObserver::WaitForExtensionLoad() { |
212 WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED); | 105 WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED); |
213 } | 106 } |
214 | 107 |
215 void ExtensionTestNotificationObserver::WaitForExtensionAndViewLoad() { | |
216 this->WaitForExtensionLoad(); | |
217 WaitForExtensionViewsToLoad(); | |
218 } | |
219 | |
220 bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() { | 108 bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() { |
221 int before = extension_load_errors_observed_; | 109 int before = extension_load_errors_observed_; |
222 WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR); | 110 WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR); |
223 return extension_load_errors_observed_ != before; | 111 return extension_load_errors_observed_ != before; |
224 } | 112 } |
225 | 113 |
226 bool ExtensionTestNotificationObserver::WaitForExtensionCrash( | 114 bool ExtensionTestNotificationObserver::WaitForExtensionCrash( |
227 const std::string& extension_id) { | 115 const std::string& extension_id) { |
228 ExtensionService* service = extensions::ExtensionSystem::Get( | 116 if (!GetNonTerminatedExtensions(extension_id, context_)) { |
229 GetProfile())->extension_service(); | |
230 | |
231 if (!service->GetExtensionById(extension_id, true)) { | |
232 // The extension is already unloaded, presumably due to a crash. | 117 // The extension is already unloaded, presumably due to a crash. |
233 return true; | 118 return true; |
234 } | 119 } |
| 120 |
235 content::WindowedNotificationObserver( | 121 content::WindowedNotificationObserver( |
236 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, | 122 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, |
237 content::NotificationService::AllSources()).Wait(); | 123 content::NotificationService::AllSources()) |
238 return (service->GetExtensionById(extension_id, true) == NULL); | 124 .Wait(); |
| 125 return (GetNonTerminatedExtensions(extension_id, context_) == NULL); |
239 } | 126 } |
240 | 127 |
241 bool ExtensionTestNotificationObserver::WaitForCrxInstallerDone() { | 128 bool ExtensionTestNotificationObserver::WaitForCrxInstallerDone() { |
242 int before = crx_installers_done_observed_; | 129 int before = crx_installers_done_observed_; |
243 WaitForNotification(extensions::NOTIFICATION_CRX_INSTALLER_DONE); | 130 WaitForNotification(extensions::NOTIFICATION_CRX_INSTALLER_DONE); |
244 return crx_installers_done_observed_ == (before + 1); | 131 return crx_installers_done_observed_ == before + 1; |
245 } | 132 } |
246 | 133 |
247 void ExtensionTestNotificationObserver::Watch( | 134 void ExtensionTestNotificationObserver::Watch( |
248 int type, | 135 int type, |
249 const content::NotificationSource& source) { | 136 const content::NotificationSource& source) { |
250 CHECK(!observer_); | 137 CHECK(!observer_); |
251 observer_.reset(new content::WindowedNotificationObserver(type, source)); | 138 observer_.reset(new content::WindowedNotificationObserver(type, source)); |
252 registrar_.Add(this, type, source); | 139 registrar_.Add(this, type, source); |
253 } | 140 } |
254 | 141 |
255 void ExtensionTestNotificationObserver::Wait() { | 142 void ExtensionTestNotificationObserver::Wait() { |
256 observer_->Wait(); | 143 observer_->Wait(); |
257 | 144 |
258 registrar_.RemoveAll(); | 145 registrar_.RemoveAll(); |
259 observer_.reset(); | 146 observer_.reset(); |
260 } | 147 } |
261 | 148 |
262 void ExtensionTestNotificationObserver::Observe( | 149 void ExtensionTestNotificationObserver::Observe( |
263 int type, | 150 int type, |
264 const content::NotificationSource& source, | 151 const content::NotificationSource& source, |
265 const content::NotificationDetails& details) { | 152 const content::NotificationDetails& details) { |
266 switch (type) { | 153 switch (type) { |
267 case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: | 154 case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: |
268 last_loaded_extension_id_ = | 155 last_loaded_extension_id_ = |
269 content::Details<const Extension>(details).ptr()->id(); | 156 content::Details<const Extension>(details).ptr()->id(); |
270 VLOG(1) << "Got EXTENSION_LOADED notification."; | 157 VLOG(1) << "Got EXTENSION_LOADED notification."; |
271 break; | 158 break; |
272 | 159 |
273 case extensions::NOTIFICATION_CRX_INSTALLER_DONE: | 160 case extensions::NOTIFICATION_CRX_INSTALLER_DONE: |
274 VLOG(1) << "Got CRX_INSTALLER_DONE notification."; | 161 VLOG(1) << "Got CRX_INSTALLER_DONE notification."; |
275 { | 162 { |
276 const Extension* extension = | 163 const Extension* extension = |
277 content::Details<const Extension>(details).ptr(); | 164 content::Details<const Extension>(details).ptr(); |
278 if (extension) | 165 if (extension) |
279 last_loaded_extension_id_ = extension->id(); | 166 last_loaded_extension_id_ = extension->id(); |
280 else | 167 else |
281 last_loaded_extension_id_.clear(); | 168 last_loaded_extension_id_.clear(); |
282 } | 169 } |
283 ++crx_installers_done_observed_; | 170 ++crx_installers_done_observed_; |
284 break; | 171 break; |
285 | 172 |
286 case extensions::NOTIFICATION_EXTENSION_LOAD_ERROR: | 173 case extensions::NOTIFICATION_EXTENSION_LOAD_ERROR: |
287 VLOG(1) << "Got EXTENSION_LOAD_ERROR notification."; | 174 VLOG(1) << "Got EXTENSION_LOAD_ERROR notification."; |
288 ++extension_load_errors_observed_; | 175 ++extension_load_errors_observed_; |
289 break; | 176 break; |
290 | 177 |
291 default: | 178 default: |
292 NOTREACHED(); | 179 NOTREACHED(); |
293 break; | 180 break; |
294 } | 181 } |
295 } | 182 } |
296 | 183 |
297 void ExtensionTestNotificationObserver::OnPageActionsUpdated( | |
298 content::WebContents* web_contents) { | |
299 MaybeQuit(); | |
300 } | |
301 | |
302 void ExtensionTestNotificationObserver::WaitForCondition( | 184 void ExtensionTestNotificationObserver::WaitForCondition( |
303 const ConditionCallback& condition, | 185 const ConditionCallback& condition, |
304 NotificationSet* notification_set) { | 186 NotificationSet* notification_set) { |
305 if (condition.Run()) | 187 if (condition.Run()) |
306 return; | 188 return; |
307 condition_ = condition; | 189 condition_ = condition; |
308 | 190 |
309 scoped_refptr<content::MessageLoopRunner> runner( | 191 scoped_refptr<content::MessageLoopRunner> runner( |
310 new content::MessageLoopRunner); | 192 new content::MessageLoopRunner); |
311 quit_closure_ = runner->QuitClosure(); | 193 quit_closure_ = runner->QuitClosure(); |
312 | 194 |
313 std::unique_ptr<base::CallbackList<void()>::Subscription> subscription; | 195 std::unique_ptr<base::CallbackList<void()>::Subscription> subscription; |
314 if (notification_set) { | 196 if (notification_set) { |
315 subscription = notification_set->callback_list().Add( | 197 subscription = notification_set->callback_list().Add(base::Bind( |
316 base::Bind(&ExtensionTestNotificationObserver::MaybeQuit, | 198 &ExtensionTestNotificationObserver::MaybeQuit, base::Unretained(this))); |
317 base::Unretained(this))); | |
318 } | 199 } |
319 runner->Run(); | 200 runner->Run(); |
320 | 201 |
321 condition_.Reset(); | 202 condition_.Reset(); |
322 quit_closure_.Reset(); | 203 quit_closure_.Reset(); |
323 } | 204 } |
324 | 205 |
325 void ExtensionTestNotificationObserver::MaybeQuit() { | 206 void ExtensionTestNotificationObserver::MaybeQuit() { |
326 if (condition_.Run()) | 207 if (condition_.Run()) |
327 quit_closure_.Run(); | 208 quit_closure_.Run(); |
328 } | 209 } |
OLD | NEW |