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
3 // found in the LICENSE file.
4
5 #include <chrome/browser/extensions/chrome_extension_test_notification_observer.h>
6 #include "base/bind.h"
7 #include "base/scoped_observer.h"
8 #include "chrome/browser/extensions/extension_action_test_util.h"
9 #include "chrome/browser/extensions/extension_util.h"
10 #include "chrome/browser/profiles/profile_manager.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/test/test_utils.h"
16 #include "extensions/browser/notification_types.h"
17 #include "extensions/browser/process_manager.h"
18 #include "extensions/common/extension.h"
19
20 namespace extensions {
21
22 namespace {
23
24 // A callback that returns true if the condition has been met and takes no
25 // arguments.
26 using ConditionCallback = base::Callback<bool(void)>;
27
HasPageActionVisibilityReachedTarget(Browser * browser,size_t target_visible_page_action_count)28 bool HasPageActionVisibilityReachedTarget(
29 Browser* browser,
30 size_t target_visible_page_action_count) {
31 return extension_action_test_util::GetVisiblePageActionCount(
32 browser->tab_strip_model()->GetActiveWebContents()) ==
33 target_visible_page_action_count;
34 }
35
HaveAllExtensionRenderFrameHostsFinishedLoading(ProcessManager * manager)36 bool HaveAllExtensionRenderFrameHostsFinishedLoading(ProcessManager* manager) {
37 ProcessManager::FrameSet all_views = manager->GetAllFrames();
38 for (content::RenderFrameHost* host : manager->GetAllFrames()) {
39 if (content::WebContents::FromRenderFrameHost(host)->IsLoading())
40 return false;
41 }
42 return true;
43 }
44
45 } // namespace
46
47 ////////////////////////////////////////////////////////////////////////////////
48 // ExtensionTestNotificationObserver
49
50 ChromeExtensionTestNotificationObserver::
ChromeExtensionTestNotificationObserver(Browser * browser)51 ChromeExtensionTestNotificationObserver(Browser* browser)
52 : ExtensionTestNotificationObserver(browser ? browser->profile() : nullptr),
53 browser_(browser) {}
54
55 ChromeExtensionTestNotificationObserver::
ChromeExtensionTestNotificationObserver(content::BrowserContext * context)56 ChromeExtensionTestNotificationObserver(content::BrowserContext* context)
57 : ExtensionTestNotificationObserver(context), browser_(nullptr) {}
58
59 ChromeExtensionTestNotificationObserver::
~ChromeExtensionTestNotificationObserver()60 ~ChromeExtensionTestNotificationObserver() {}
61
62 content::BrowserContext*
GetBrowserContext()63 ChromeExtensionTestNotificationObserver::GetBrowserContext() {
64 if (!context_) {
65 if (browser_)
66 context_ = browser_->profile();
67 else
68 context_ = ProfileManager::GetActiveUserProfile();
69 }
70 return context_;
71 }
72
73 bool ChromeExtensionTestNotificationObserver::
WaitForPageActionVisibilityChangeTo(int count)74 WaitForPageActionVisibilityChangeTo(int count) {
75 DCHECK(browser_);
76 ScopedObserver<ExtensionActionAPI, ExtensionActionAPI::Observer> observer(
77 this);
78 observer.Add(ExtensionActionAPI::Get(GetBrowserContext()));
79 WaitForCondition(
80 base::Bind(&HasPageActionVisibilityReachedTarget, browser_, count), NULL);
81 return true;
82 }
83
WaitForExtensionViewsToLoad()84 bool ChromeExtensionTestNotificationObserver::WaitForExtensionViewsToLoad() {
85 // Some views might not be created yet. This call may become insufficient if
86 // e.g. implementation of ExtensionHostQueue changes.
87 base::RunLoop().RunUntilIdle();
88
89 ProcessManager* manager = ProcessManager::Get(GetBrowserContext());
90 NotificationSet notification_set;
91 notification_set.Add(content::NOTIFICATION_WEB_CONTENTS_DESTROYED);
92 notification_set.Add(content::NOTIFICATION_LOAD_STOP);
93 notification_set.AddExtensionFrameUnregistration(manager);
94 WaitForCondition(
95 base::Bind(&HaveAllExtensionRenderFrameHostsFinishedLoading, manager),
96 ¬ification_set);
97 return true;
98 }
99
WaitForExtensionIdle(const std::string & extension_id)100 bool ChromeExtensionTestNotificationObserver::WaitForExtensionIdle(
101 const std::string& extension_id) {
102 NotificationSet notification_set;
103 notification_set.Add(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED);
104 WaitForCondition(
105 base::Bind(&util::IsExtensionIdle, extension_id, GetBrowserContext()),
106 ¬ification_set);
107 return true;
108 }
109
WaitForExtensionNotIdle(const std::string & extension_id)110 bool ChromeExtensionTestNotificationObserver::WaitForExtensionNotIdle(
111 const std::string& extension_id) {
112 NotificationSet notification_set;
113 notification_set.Add(content::NOTIFICATION_LOAD_STOP);
114 WaitForCondition(base::Bind(
115 [](const std::string& extension_id,
116 content::BrowserContext* context) -> bool {
117 return !util::IsExtensionIdle(extension_id, context);
118 },
119 extension_id, GetBrowserContext()),
120 ¬ification_set);
121 return true;
122 }
123
OnExtensionActionUpdated(ExtensionAction * extension_action,content::WebContents * web_contents,content::BrowserContext * browser_context)124 void ChromeExtensionTestNotificationObserver::OnExtensionActionUpdated(
125 ExtensionAction* extension_action,
126 content::WebContents* web_contents,
127 content::BrowserContext* browser_context) {
128 MaybeQuit();
129 }
130
131 } // namespace extensions
132