Update To 11.40.268.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_action_test_util.h"
9 #include "chrome/browser/extensions/extension_service.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 "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "content/public/browser/notification_registrar.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/test/test_utils.h"
18 #include "extensions/browser/extension_system.h"
19 #include "extensions/browser/process_manager.h"
20 #include "extensions/common/extension.h"
21
22 using extensions::Extension;
23
24 namespace {
25
26 // A callback that returns true if the condition has been met and takes no
27 // arguments.
28 typedef base::Callback<bool(void)> ConditionCallback;
29
30 bool HasPageActionVisibilityReachedTarget(
31     Browser* browser, size_t target_visible_page_action_count) {
32   return extensions::extension_action_test_util::GetVisiblePageActionCount(
33       browser->tab_strip_model()->GetActiveWebContents()) ==
34       target_visible_page_action_count;
35 }
36
37 bool HaveAllExtensionRenderViewHostsFinishedLoading(
38     extensions::ProcessManager* manager) {
39   extensions::ProcessManager::ViewSet all_views = manager->GetAllViews();
40   for (extensions::ProcessManager::ViewSet::const_iterator iter =
41            all_views.begin();
42        iter != all_views.end(); ++iter) {
43     if ((*iter)->IsLoading())
44       return false;
45   }
46   return true;
47 }
48
49 }  // namespace
50
51 ////////////////////////////////////////////////////////////////////////////////
52 // ExtensionTestNotificationObserver::NotificationSet
53
54 class ExtensionTestNotificationObserver::NotificationSet
55     : public content::NotificationObserver {
56  public:
57   void Add(int type, const content::NotificationSource& source);
58   void Add(int type);
59
60   // Notified any time an Add()ed notification is received.
61   // The details of the notification are dropped.
62   base::CallbackList<void()>& callback_list() {
63     return callback_list_;
64   }
65
66  private:
67   // content::NotificationObserver:
68   void Observe(int type,
69                const content::NotificationSource& source,
70                const content::NotificationDetails& details) override;
71
72   content::NotificationRegistrar notification_registrar_;
73   base::CallbackList<void()> callback_list_;
74 };
75
76 void ExtensionTestNotificationObserver::NotificationSet::Add(
77     int type,
78     const content::NotificationSource& source) {
79   notification_registrar_.Add(this, type, source);
80 }
81
82 void ExtensionTestNotificationObserver::NotificationSet::Add(int type) {
83   Add(type, content::NotificationService::AllSources());
84 }
85
86 void ExtensionTestNotificationObserver::NotificationSet::Observe(
87     int type,
88     const content::NotificationSource& source,
89     const content::NotificationDetails& details) {
90   callback_list_.Notify();
91 }
92
93 ////////////////////////////////////////////////////////////////////////////////
94 // ExtensionTestNotificationObserver
95
96 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver(
97     Browser* browser)
98     : browser_(browser),
99       profile_(NULL),
100       extension_installs_observed_(0),
101       extension_load_errors_observed_(0),
102       crx_installers_done_observed_(0) {
103 }
104
105 ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {}
106
107 Profile* ExtensionTestNotificationObserver::GetProfile() {
108   if (!profile_) {
109     if (browser_)
110       profile_ = browser_->profile();
111     else
112       profile_ = ProfileManager::GetActiveUserProfile();
113   }
114   return profile_;
115 }
116
117 void ExtensionTestNotificationObserver::WaitForNotification(
118     int notification_type) {
119   // TODO(bauerb): Using a WindowedNotificationObserver like this can break
120   // easily, if the notification we're waiting for is sent before this method.
121   // Change it so that the WindowedNotificationObserver is constructed earlier.
122   content::NotificationRegistrar registrar;
123   registrar.Add(
124       this, notification_type, content::NotificationService::AllSources());
125   content::WindowedNotificationObserver(
126       notification_type, content::NotificationService::AllSources()).Wait();
127 }
128
129 bool ExtensionTestNotificationObserver::WaitForPageActionVisibilityChangeTo(
130     int count) {
131   extensions::ExtensionActionAPI::Get(GetProfile())->AddObserver(this);
132   WaitForCondition(
133       base::Bind(&HasPageActionVisibilityReachedTarget, browser_, count),
134       NULL);
135   extensions::ExtensionActionAPI::Get(GetProfile())->
136       RemoveObserver(this);
137   return true;
138 }
139
140 bool ExtensionTestNotificationObserver::WaitForExtensionViewsToLoad() {
141   extensions::ProcessManager* manager =
142       extensions::ProcessManager::Get(GetProfile());
143   NotificationSet notification_set;
144   notification_set.Add(content::NOTIFICATION_WEB_CONTENTS_DESTROYED);
145   notification_set.Add(content::NOTIFICATION_LOAD_STOP);
146   WaitForCondition(
147       base::Bind(&HaveAllExtensionRenderViewHostsFinishedLoading, manager),
148       &notification_set);
149   return true;
150 }
151
152 bool ExtensionTestNotificationObserver::WaitForExtensionInstall() {
153   int before = extension_installs_observed_;
154   WaitForNotification(
155       extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED);
156   return extension_installs_observed_ == (before + 1);
157 }
158
159 bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() {
160   int before = extension_installs_observed_;
161   content::WindowedNotificationObserver(
162       extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
163       content::NotificationService::AllSources()).Wait();
164   return extension_installs_observed_ == before;
165 }
166
167 void ExtensionTestNotificationObserver::WaitForExtensionLoad() {
168   WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED);
169 }
170
171 void ExtensionTestNotificationObserver::WaitForExtensionAndViewLoad() {
172   this->WaitForExtensionLoad();
173   WaitForExtensionViewsToLoad();
174 }
175
176 bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() {
177   int before = extension_load_errors_observed_;
178   WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR);
179   return extension_load_errors_observed_ != before;
180 }
181
182 bool ExtensionTestNotificationObserver::WaitForExtensionCrash(
183     const std::string& extension_id) {
184   ExtensionService* service = extensions::ExtensionSystem::Get(
185       GetProfile())->extension_service();
186
187   if (!service->GetExtensionById(extension_id, true)) {
188     // The extension is already unloaded, presumably due to a crash.
189     return true;
190   }
191   content::WindowedNotificationObserver(
192       extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
193       content::NotificationService::AllSources()).Wait();
194   return (service->GetExtensionById(extension_id, true) == NULL);
195 }
196
197 bool ExtensionTestNotificationObserver::WaitForCrxInstallerDone() {
198   int before = crx_installers_done_observed_;
199   WaitForNotification(extensions::NOTIFICATION_CRX_INSTALLER_DONE);
200   return crx_installers_done_observed_ == (before + 1);
201 }
202
203 void ExtensionTestNotificationObserver::Watch(
204     int type,
205     const content::NotificationSource& source) {
206   CHECK(!observer_);
207   observer_.reset(new content::WindowedNotificationObserver(type, source));
208   registrar_.Add(this, type, source);
209 }
210
211 void ExtensionTestNotificationObserver::Wait() {
212   observer_->Wait();
213
214   registrar_.RemoveAll();
215   observer_.reset();
216 }
217
218 void ExtensionTestNotificationObserver::Observe(
219     int type,
220     const content::NotificationSource& source,
221     const content::NotificationDetails& details) {
222   switch (type) {
223     case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED:
224       last_loaded_extension_id_ =
225         content::Details<const Extension>(details).ptr()->id();
226       VLOG(1) << "Got EXTENSION_LOADED notification.";
227       break;
228
229     case extensions::NOTIFICATION_CRX_INSTALLER_DONE:
230       VLOG(1) << "Got CRX_INSTALLER_DONE notification.";
231       {
232           const Extension* extension =
233             content::Details<const Extension>(details).ptr();
234           if (extension)
235             last_loaded_extension_id_ = extension->id();
236           else
237             last_loaded_extension_id_.clear();
238       }
239       ++crx_installers_done_observed_;
240       break;
241
242     case extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED:
243       VLOG(1) << "Got EXTENSION_INSTALLED notification.";
244       ++extension_installs_observed_;
245       break;
246
247     case extensions::NOTIFICATION_EXTENSION_LOAD_ERROR:
248       VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
249       ++extension_load_errors_observed_;
250       break;
251
252     default:
253       NOTREACHED();
254       break;
255   }
256 }
257
258 void ExtensionTestNotificationObserver::OnPageActionsUpdated(
259     content::WebContents* web_contents) {
260   MaybeQuit();
261 }
262
263 void ExtensionTestNotificationObserver::WaitForCondition(
264     const ConditionCallback& condition,
265     NotificationSet* notification_set) {
266   if (condition.Run())
267     return;
268   condition_ = condition;
269
270   scoped_refptr<content::MessageLoopRunner> runner(
271       new content::MessageLoopRunner);
272   quit_closure_ = runner->QuitClosure();
273
274   scoped_ptr<base::CallbackList<void()>::Subscription> subscription;
275   if (notification_set) {
276     subscription = notification_set->callback_list().Add(
277         base::Bind(&ExtensionTestNotificationObserver::MaybeQuit,
278                    base::Unretained(this)));
279   }
280   runner->Run();
281
282   condition_.Reset();
283   quit_closure_.Reset();
284 }
285
286 void ExtensionTestNotificationObserver::MaybeQuit() {
287   if (condition_.Run())
288     quit_closure_.Run();
289 }