Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_test_notification_observer.cc
blobda99e29621ff6559228c51505da9f1d0388092ec
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_action_test_util.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_util.h"
11 #include "chrome/browser/profiles/profile_manager.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_window.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "content/public/browser/notification_registrar.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/process_manager.h"
21 #include "extensions/common/extension.h"
23 using extensions::Extension;
25 namespace {
27 // A callback that returns true if the condition has been met and takes no
28 // arguments.
29 typedef base::Callback<bool(void)> ConditionCallback;
31 bool HasPageActionVisibilityReachedTarget(
32 Browser* browser, size_t target_visible_page_action_count) {
33 return extensions::extension_action_test_util::GetVisiblePageActionCount(
34 browser->tab_strip_model()->GetActiveWebContents()) ==
35 target_visible_page_action_count;
38 bool HaveAllExtensionRenderFrameHostsFinishedLoading(
39 extensions::ProcessManager* manager) {
40 extensions::ProcessManager::FrameSet all_views = manager->GetAllFrames();
41 for (content::RenderFrameHost* host : manager->GetAllFrames()) {
42 if (content::WebContents::FromRenderFrameHost(host)->IsLoading())
43 return false;
45 return true;
48 bool IsExtensionNotIdle(const std::string& extension_id,
49 content::BrowserContext* context) {
50 return !extensions::util::IsExtensionIdle(extension_id, context);
53 } // namespace
55 ////////////////////////////////////////////////////////////////////////////////
56 // ExtensionTestNotificationObserver::NotificationSet
58 class ExtensionTestNotificationObserver::NotificationSet
59 : public content::NotificationObserver {
60 public:
61 void Add(int type, const content::NotificationSource& source);
62 void Add(int type);
64 // Notified any time an Add()ed notification is received.
65 // The details of the notification are dropped.
66 base::CallbackList<void()>& callback_list() {
67 return callback_list_;
70 private:
71 // content::NotificationObserver:
72 void Observe(int type,
73 const content::NotificationSource& source,
74 const content::NotificationDetails& details) override;
76 content::NotificationRegistrar notification_registrar_;
77 base::CallbackList<void()> callback_list_;
80 void ExtensionTestNotificationObserver::NotificationSet::Add(
81 int type,
82 const content::NotificationSource& source) {
83 notification_registrar_.Add(this, type, source);
86 void ExtensionTestNotificationObserver::NotificationSet::Add(int type) {
87 Add(type, content::NotificationService::AllSources());
90 void ExtensionTestNotificationObserver::NotificationSet::Observe(
91 int type,
92 const content::NotificationSource& source,
93 const content::NotificationDetails& details) {
94 callback_list_.Notify();
97 ////////////////////////////////////////////////////////////////////////////////
98 // ExtensionTestNotificationObserver
100 ExtensionTestNotificationObserver::ExtensionTestNotificationObserver(
101 Browser* browser)
102 : browser_(browser),
103 profile_(NULL),
104 extension_installs_observed_(0),
105 extension_load_errors_observed_(0),
106 crx_installers_done_observed_(0) {
109 ExtensionTestNotificationObserver::~ExtensionTestNotificationObserver() {}
111 Profile* ExtensionTestNotificationObserver::GetProfile() {
112 if (!profile_) {
113 if (browser_)
114 profile_ = browser_->profile();
115 else
116 profile_ = ProfileManager::GetActiveUserProfile();
118 return profile_;
121 void ExtensionTestNotificationObserver::WaitForNotification(
122 int notification_type) {
123 // TODO(bauerb): Using a WindowedNotificationObserver like this can break
124 // easily, if the notification we're waiting for is sent before this method.
125 // Change it so that the WindowedNotificationObserver is constructed earlier.
126 content::NotificationRegistrar registrar;
127 registrar.Add(
128 this, notification_type, content::NotificationService::AllSources());
129 content::WindowedNotificationObserver(
130 notification_type, content::NotificationService::AllSources()).Wait();
133 bool ExtensionTestNotificationObserver::WaitForPageActionVisibilityChangeTo(
134 int count) {
135 extensions::ExtensionActionAPI::Get(GetProfile())->AddObserver(this);
136 WaitForCondition(
137 base::Bind(&HasPageActionVisibilityReachedTarget, browser_, count),
138 NULL);
139 extensions::ExtensionActionAPI::Get(GetProfile())->
140 RemoveObserver(this);
141 return true;
144 bool ExtensionTestNotificationObserver::WaitForExtensionViewsToLoad() {
145 extensions::ProcessManager* manager =
146 extensions::ProcessManager::Get(GetProfile());
147 NotificationSet notification_set;
148 notification_set.Add(content::NOTIFICATION_WEB_CONTENTS_DESTROYED);
149 notification_set.Add(content::NOTIFICATION_LOAD_STOP);
150 WaitForCondition(
151 base::Bind(&HaveAllExtensionRenderFrameHostsFinishedLoading, manager),
152 &notification_set);
153 return true;
156 bool ExtensionTestNotificationObserver::WaitForExtensionIdle(
157 const std::string& extension_id) {
158 NotificationSet notification_set;
159 notification_set.Add(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED);
160 WaitForCondition(base::Bind(&extensions::util::IsExtensionIdle, extension_id,
161 GetProfile()),
162 &notification_set);
163 return true;
166 bool ExtensionTestNotificationObserver::WaitForExtensionNotIdle(
167 const std::string& extension_id) {
168 NotificationSet notification_set;
169 notification_set.Add(content::NOTIFICATION_LOAD_STOP);
170 WaitForCondition(base::Bind(&IsExtensionNotIdle, extension_id, GetProfile()),
171 &notification_set);
172 return true;
175 bool ExtensionTestNotificationObserver::WaitForExtensionInstall() {
176 int before = extension_installs_observed_;
177 WaitForNotification(
178 extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED);
179 return extension_installs_observed_ == (before + 1);
182 bool ExtensionTestNotificationObserver::WaitForExtensionInstallError() {
183 int before = extension_installs_observed_;
184 content::WindowedNotificationObserver(
185 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
186 content::NotificationService::AllSources()).Wait();
187 return extension_installs_observed_ == before;
190 void ExtensionTestNotificationObserver::WaitForExtensionLoad() {
191 WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED);
194 void ExtensionTestNotificationObserver::WaitForExtensionAndViewLoad() {
195 this->WaitForExtensionLoad();
196 WaitForExtensionViewsToLoad();
199 bool ExtensionTestNotificationObserver::WaitForExtensionLoadError() {
200 int before = extension_load_errors_observed_;
201 WaitForNotification(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR);
202 return extension_load_errors_observed_ != before;
205 bool ExtensionTestNotificationObserver::WaitForExtensionCrash(
206 const std::string& extension_id) {
207 ExtensionService* service = extensions::ExtensionSystem::Get(
208 GetProfile())->extension_service();
210 if (!service->GetExtensionById(extension_id, true)) {
211 // The extension is already unloaded, presumably due to a crash.
212 return true;
214 content::WindowedNotificationObserver(
215 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
216 content::NotificationService::AllSources()).Wait();
217 return (service->GetExtensionById(extension_id, true) == NULL);
220 bool ExtensionTestNotificationObserver::WaitForCrxInstallerDone() {
221 int before = crx_installers_done_observed_;
222 WaitForNotification(extensions::NOTIFICATION_CRX_INSTALLER_DONE);
223 return crx_installers_done_observed_ == (before + 1);
226 void ExtensionTestNotificationObserver::Watch(
227 int type,
228 const content::NotificationSource& source) {
229 CHECK(!observer_);
230 observer_.reset(new content::WindowedNotificationObserver(type, source));
231 registrar_.Add(this, type, source);
234 void ExtensionTestNotificationObserver::Wait() {
235 observer_->Wait();
237 registrar_.RemoveAll();
238 observer_.reset();
241 void ExtensionTestNotificationObserver::Observe(
242 int type,
243 const content::NotificationSource& source,
244 const content::NotificationDetails& details) {
245 switch (type) {
246 case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED:
247 last_loaded_extension_id_ =
248 content::Details<const Extension>(details).ptr()->id();
249 VLOG(1) << "Got EXTENSION_LOADED notification.";
250 break;
252 case extensions::NOTIFICATION_CRX_INSTALLER_DONE:
253 VLOG(1) << "Got CRX_INSTALLER_DONE notification.";
255 const Extension* extension =
256 content::Details<const Extension>(details).ptr();
257 if (extension)
258 last_loaded_extension_id_ = extension->id();
259 else
260 last_loaded_extension_id_.clear();
262 ++crx_installers_done_observed_;
263 break;
265 case extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED:
266 VLOG(1) << "Got EXTENSION_INSTALLED notification.";
267 ++extension_installs_observed_;
268 break;
270 case extensions::NOTIFICATION_EXTENSION_LOAD_ERROR:
271 VLOG(1) << "Got EXTENSION_LOAD_ERROR notification.";
272 ++extension_load_errors_observed_;
273 break;
275 default:
276 NOTREACHED();
277 break;
281 void ExtensionTestNotificationObserver::OnPageActionsUpdated(
282 content::WebContents* web_contents) {
283 MaybeQuit();
286 void ExtensionTestNotificationObserver::WaitForCondition(
287 const ConditionCallback& condition,
288 NotificationSet* notification_set) {
289 if (condition.Run())
290 return;
291 condition_ = condition;
293 scoped_refptr<content::MessageLoopRunner> runner(
294 new content::MessageLoopRunner);
295 quit_closure_ = runner->QuitClosure();
297 scoped_ptr<base::CallbackList<void()>::Subscription> subscription;
298 if (notification_set) {
299 subscription = notification_set->callback_list().Add(
300 base::Bind(&ExtensionTestNotificationObserver::MaybeQuit,
301 base::Unretained(this)));
303 runner->Run();
305 condition_.Reset();
306 quit_closure_.Reset();
309 void ExtensionTestNotificationObserver::MaybeQuit() {
310 if (condition_.Run())
311 quit_closure_.Run();