1 // Copyright 2013 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.
5 #include "chrome/browser/extensions/extension_test_notification_observer.h"
7 #include "base/callback_list.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_system.h"
10 #include "chrome/browser/profiles/profile_manager.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "content/public/browser/notification_registrar.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/test/test_utils.h"
17 #include "extensions/browser/process_manager.h"
18 #include "extensions/common/extension.h"
20 using extensions::Extension
;
24 bool HasExtensionPageActionCountReachedTarget(LocationBarTesting
* location_bar
,
25 int target_page_action_count
) {
26 VLOG(1) << "Number of page actions: " << location_bar
->PageActionCount();
27 return location_bar
->PageActionCount() == target_page_action_count
;
30 bool HasExtensionPageActionVisibilityReachedTarget(
31 LocationBarTesting
* location_bar
,
32 int target_visible_page_action_count
) {
33 VLOG(1) << "Number of visible page actions: "
34 << location_bar
->PageActionVisibleCount();
35 return location_bar
->PageActionVisibleCount() ==
36 target_visible_page_action_count
;
39 bool HaveAllExtensionRenderViewHostsFinishedLoading(
40 extensions::ProcessManager
* manager
) {
41 extensions::ProcessManager::ViewSet all_views
= manager
->GetAllViews();
42 for (extensions::ProcessManager::ViewSet::const_iterator iter
=
44 iter
!= all_views
.end(); ++iter
) {
45 if ((*iter
)->IsLoading())
51 class NotificationSet
: public content::NotificationObserver
{
53 void Add(int type
, const content::NotificationSource
& source
);
56 // Notified any time an Add()ed notification is received.
57 // The details of the notification are dropped.
58 base::CallbackList
<void()>& callback_list() {
59 return callback_list_
;
63 // content::NotificationObserver:
64 virtual void Observe(int type
,
65 const content::NotificationSource
& source
,
66 const content::NotificationDetails
& details
) OVERRIDE
;
68 content::NotificationRegistrar notification_registrar_
;
69 base::CallbackList
<void()> callback_list_
;
72 void NotificationSet::Add(
74 const content::NotificationSource
& source
) {
75 notification_registrar_
.Add(this, type
, source
);
78 void NotificationSet::Add(int type
) {
79 Add(type
, content::NotificationService::AllSources());
82 void NotificationSet::Observe(
84 const content::NotificationSource
& source
,
85 const content::NotificationDetails
& details
) {
86 callback_list_
.Notify();
89 void MaybeQuit(content::MessageLoopRunner
* runner
,
90 const base::Callback
<bool(void)>& condition
) {
95 void WaitForCondition(
96 const base::Callback
<bool(void)>& condition
,
97 NotificationSet
* notification_set
) {
101 scoped_refptr
<content::MessageLoopRunner
> runner(
102 new content::MessageLoopRunner
);
103 scoped_ptr
<base::CallbackList
<void()>::Subscription
> subscription
=
104 notification_set
->callback_list().Add(
105 base::Bind(&MaybeQuit
, base::Unretained(runner
.get()), condition
));
109 void WaitForCondition(
110 const base::Callback
<bool(void)>& condition
,
112 NotificationSet notification_set
;
113 notification_set
.Add(type
);
114 WaitForCondition(condition
, ¬ification_set
);
119 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver(
123 extension_installs_observed_(0),
124 extension_load_errors_observed_(0),
125 crx_installers_done_observed_(0) {
128 ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {}
130 Profile
* ExtensionTestNotificationObserver::GetProfile() {
133 profile_
= browser_
->profile();
135 profile_
= ProfileManager::GetActiveUserProfile();
140 void ExtensionTestNotificationObserver::WaitForNotification(
141 int notification_type
) {
142 // TODO(bauerb): Using a WindowedNotificationObserver like this can break
143 // easily, if the notification we're waiting for is sent before this method.
144 // Change it so that the WindowedNotificationObserver is constructed earlier.
145 content::NotificationRegistrar registrar
;
147 this, notification_type
, content::NotificationService::AllSources());
148 content::WindowedNotificationObserver(
149 notification_type
, content::NotificationService::AllSources()).Wait();
152 bool ExtensionTestNotificationObserver::WaitForPageActionCountChangeTo(
154 LocationBarTesting
* location_bar
=
155 browser_
->window()->GetLocationBar()->GetLocationBarForTesting();
158 &HasExtensionPageActionCountReachedTarget
, location_bar
, count
),
159 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED
);
163 bool ExtensionTestNotificationObserver::WaitForPageActionVisibilityChangeTo(
165 LocationBarTesting
* location_bar
=
166 browser_
->window()->GetLocationBar()->GetLocationBarForTesting();
169 &HasExtensionPageActionVisibilityReachedTarget
, location_bar
, count
),
170 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED
);
174 bool ExtensionTestNotificationObserver::WaitForExtensionViewsToLoad() {
175 extensions::ProcessManager
* manager
=
176 extensions::ExtensionSystem::Get(GetProfile())->process_manager();
177 NotificationSet notification_set
;
178 notification_set
.Add(content::NOTIFICATION_WEB_CONTENTS_DESTROYED
);
179 notification_set
.Add(content::NOTIFICATION_LOAD_STOP
);
181 base::Bind(&HaveAllExtensionRenderViewHostsFinishedLoading
, manager
),
186 bool ExtensionTestNotificationObserver::WaitForExtensionInstall() {
187 int before
= extension_installs_observed_
;
188 WaitForNotification(chrome::NOTIFICATION_EXTENSION_INSTALLED
);
189 return extension_installs_observed_
== (before
+ 1);
192 bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() {
193 int before
= extension_installs_observed_
;
194 content::WindowedNotificationObserver(
195 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR
,
196 content::NotificationService::AllSources()).Wait();
197 return extension_installs_observed_
== before
;
200 void ExtensionTestNotificationObserver::WaitForExtensionLoad() {
201 WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOADED
);
204 void ExtensionTestNotificationObserver::WaitForExtensionAndViewLoad() {
205 this->WaitForExtensionLoad();
206 WaitForExtensionViewsToLoad();
209 bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() {
210 int before
= extension_load_errors_observed_
;
211 WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR
);
212 return extension_load_errors_observed_
!= before
;
215 bool ExtensionTestNotificationObserver::WaitForExtensionCrash(
216 const std::string
& extension_id
) {
217 ExtensionService
* service
= extensions::ExtensionSystem::Get(
218 GetProfile())->extension_service();
220 if (!service
->GetExtensionById(extension_id
, true)) {
221 // The extension is already unloaded, presumably due to a crash.
224 content::WindowedNotificationObserver(
225 chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED
,
226 content::NotificationService::AllSources()).Wait();
227 return (service
->GetExtensionById(extension_id
, true) == NULL
);
230 bool ExtensionTestNotificationObserver::WaitForCrxInstallerDone() {
231 int before
= crx_installers_done_observed_
;
232 WaitForNotification(chrome::NOTIFICATION_CRX_INSTALLER_DONE
);
233 return crx_installers_done_observed_
== (before
+ 1);
236 void ExtensionTestNotificationObserver::Watch(
238 const content::NotificationSource
& source
) {
240 observer_
.reset(new content::WindowedNotificationObserver(type
, source
));
241 registrar_
.Add(this, type
, source
);
244 void ExtensionTestNotificationObserver::Wait() {
247 registrar_
.RemoveAll();
251 void ExtensionTestNotificationObserver::Observe(
253 const content::NotificationSource
& source
,
254 const content::NotificationDetails
& details
) {
256 case chrome::NOTIFICATION_EXTENSION_LOADED
:
257 last_loaded_extension_id_
=
258 content::Details
<const Extension
>(details
).ptr()->id();
259 VLOG(1) << "Got EXTENSION_LOADED notification.";
262 case chrome::NOTIFICATION_CRX_INSTALLER_DONE
:
263 VLOG(1) << "Got CRX_INSTALLER_DONE notification.";
265 const Extension
* extension
=
266 content::Details
<const Extension
>(details
).ptr();
268 last_loaded_extension_id_
= extension
->id();
270 last_loaded_extension_id_
.clear();
272 ++crx_installers_done_observed_
;
275 case chrome::NOTIFICATION_EXTENSION_INSTALLED
:
276 VLOG(1) << "Got EXTENSION_INSTALLED notification.";
277 ++extension_installs_observed_
;
280 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR
:
281 VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
282 ++extension_load_errors_observed_
;