Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_test_notification_observer.cc
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.
4
5 #include "chrome/browser/extensions/extension_test_notification_observer.h"
6
7 #include "base/callback_list.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/profiles/profile_manager.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/browser_window.h"
12 #include "content/public/browser/notification_registrar.h"
13 #include "content/public/browser/notification_service.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/test/test_utils.h"
16 #include "extensions/browser/extension_system.h"
17 #include "extensions/browser/process_manager.h"
18 #include "extensions/common/extension.h"
19
20 using extensions::Extension;
21
22 namespace {
23
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;
28 }
29
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;
37 }
38
39 bool HaveAllExtensionRenderViewHostsFinishedLoading(
40     extensions::ProcessManager* manager) {
41   extensions::ProcessManager::ViewSet all_views = manager->GetAllViews();
42   for (extensions::ProcessManager::ViewSet::const_iterator iter =
43            all_views.begin();
44        iter != all_views.end(); ++iter) {
45     if ((*iter)->IsLoading())
46       return false;
47   }
48   return true;
49 }
50
51 class NotificationSet : public content::NotificationObserver {
52  public:
53   void Add(int type, const content::NotificationSource& source);
54   void Add(int type);
55
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_;
60   }
61
62  private:
63   // content::NotificationObserver:
64   virtual void Observe(int type,
65                        const content::NotificationSource& source,
66                        const content::NotificationDetails& details) OVERRIDE;
67
68   content::NotificationRegistrar notification_registrar_;
69   base::CallbackList<void()> callback_list_;
70 };
71
72 void NotificationSet::Add(
73     int type,
74     const content::NotificationSource& source) {
75   notification_registrar_.Add(this, type, source);
76 }
77
78 void NotificationSet::Add(int type) {
79   Add(type, content::NotificationService::AllSources());
80 }
81
82 void NotificationSet::Observe(
83     int type,
84     const content::NotificationSource& source,
85     const content::NotificationDetails& details) {
86   callback_list_.Notify();
87 }
88
89 void MaybeQuit(content::MessageLoopRunner* runner,
90                const base::Callback<bool(void)>& condition) {
91   if (condition.Run())
92     runner->Quit();
93 }
94
95 void WaitForCondition(
96     const base::Callback<bool(void)>& condition,
97     NotificationSet* notification_set) {
98   if (condition.Run())
99     return;
100
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));
106   runner->Run();
107 }
108
109 void WaitForCondition(
110     const base::Callback<bool(void)>& condition,
111     int type) {
112   NotificationSet notification_set;
113   notification_set.Add(type);
114   WaitForCondition(condition, &notification_set);
115 }
116
117 }  // namespace
118
119 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver(
120     Browser* browser)
121     : browser_(browser),
122       profile_(NULL),
123       extension_installs_observed_(0),
124       extension_load_errors_observed_(0),
125       crx_installers_done_observed_(0) {
126 }
127
128 ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {}
129
130 Profile* ExtensionTestNotificationObserver::GetProfile() {
131   if (!profile_) {
132     if (browser_)
133       profile_ = browser_->profile();
134     else
135       profile_ = ProfileManager::GetActiveUserProfile();
136   }
137   return profile_;
138 }
139
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;
146   registrar.Add(
147       this, notification_type, content::NotificationService::AllSources());
148   content::WindowedNotificationObserver(
149       notification_type, content::NotificationService::AllSources()).Wait();
150 }
151
152 bool ExtensionTestNotificationObserver::WaitForPageActionCountChangeTo(
153     int count) {
154   LocationBarTesting* location_bar =
155       browser_->window()->GetLocationBar()->GetLocationBarForTesting();
156   WaitForCondition(
157       base::Bind(
158           &HasExtensionPageActionCountReachedTarget, location_bar, count),
159       chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED);
160   return true;
161 }
162
163 bool ExtensionTestNotificationObserver::WaitForPageActionVisibilityChangeTo(
164     int count) {
165   LocationBarTesting* location_bar =
166       browser_->window()->GetLocationBar()->GetLocationBarForTesting();
167   WaitForCondition(
168       base::Bind(
169           &HasExtensionPageActionVisibilityReachedTarget, location_bar, count),
170       chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED);
171   return true;
172 }
173
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);
180   WaitForCondition(
181       base::Bind(&HaveAllExtensionRenderViewHostsFinishedLoading, manager),
182       &notification_set);
183   return true;
184 }
185
186 bool ExtensionTestNotificationObserver::WaitForExtensionInstall() {
187   int before = extension_installs_observed_;
188   WaitForNotification(chrome::NOTIFICATION_EXTENSION_INSTALLED);
189   return extension_installs_observed_ == (before + 1);
190 }
191
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;
198 }
199
200 void ExtensionTestNotificationObserver::WaitForExtensionLoad() {
201   WaitForNotification(chrome::NOTIFICATION_EXTENSION_LOADED);
202 }
203
204 void ExtensionTestNotificationObserver::WaitForExtensionAndViewLoad() {
205   this->WaitForExtensionLoad();
206   WaitForExtensionViewsToLoad();
207 }
208
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;
213 }
214
215 bool ExtensionTestNotificationObserver::WaitForExtensionCrash(
216     const std::string& extension_id) {
217   ExtensionService* service = extensions::ExtensionSystem::Get(
218       GetProfile())->extension_service();
219
220   if (!service->GetExtensionById(extension_id, true)) {
221     // The extension is already unloaded, presumably due to a crash.
222     return true;
223   }
224   content::WindowedNotificationObserver(
225       chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
226       content::NotificationService::AllSources()).Wait();
227   return (service->GetExtensionById(extension_id, true) == NULL);
228 }
229
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);
234 }
235
236 void ExtensionTestNotificationObserver::Watch(
237     int type,
238     const content::NotificationSource& source) {
239   CHECK(!observer_);
240   observer_.reset(new content::WindowedNotificationObserver(type, source));
241   registrar_.Add(this, type, source);
242 }
243
244 void ExtensionTestNotificationObserver::Wait() {
245   observer_->Wait();
246
247   registrar_.RemoveAll();
248   observer_.reset();
249 }
250
251 void ExtensionTestNotificationObserver::Observe(
252     int type,
253     const content::NotificationSource& source,
254     const content::NotificationDetails& details) {
255   switch (type) {
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.";
260       break;
261
262   case chrome::NOTIFICATION_CRX_INSTALLER_DONE:
263     VLOG(1) << "Got CRX_INSTALLER_DONE notification.";
264     {
265         const Extension* extension =
266           content::Details<const Extension>(details).ptr();
267         if (extension)
268           last_loaded_extension_id_ = extension->id();
269         else
270           last_loaded_extension_id_.clear();
271     }
272     ++crx_installers_done_observed_;
273     break;
274
275   case chrome::NOTIFICATION_EXTENSION_INSTALLED:
276     VLOG(1) << "Got EXTENSION_INSTALLED notification.";
277     ++extension_installs_observed_;
278     break;
279
280   case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR:
281     VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
282     ++extension_load_errors_observed_;
283     break;
284
285   default:
286     NOTREACHED();
287     break;
288   }
289 }