1 // Copyright (c) 2012 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 "base/strings/string_number_conversions.h"
6 #include "base/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
11 #include "chrome/browser/extensions/extension_apitest.h"
12 #include "chrome/browser/extensions/extension_function_test_utils.h"
13 #include "chrome/browser/notifications/notification.h"
14 #include "chrome/browser/notifications/notification_ui_manager.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/test/test_utils.h"
17 #include "extensions/browser/api/test/test_api.h"
18 #include "extensions/common/features/feature.h"
19 #include "ui/message_center/message_center.h"
20 #include "ui/message_center/notification_list.h"
21 #include "ui/message_center/notifier_settings.h"
22
23 using extensions::Extension;
24
25 namespace utils = extension_function_test_utils;
26
27 namespace {
28
29 // A class that waits for a |chrome.test.sendMessage| call, ignores the message,
30 // and writes down the user gesture status of the message.
31 class UserGestureCatcher : public content::NotificationObserver {
32 public:
UserGestureCatcher()33 UserGestureCatcher() : waiting_(false) {
34 registrar_.Add(this,
35 chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE,
36 content::NotificationService::AllSources());
37 }
38
~UserGestureCatcher()39 virtual ~UserGestureCatcher() {}
40
GetNextResult()41 bool GetNextResult() {
42 if (results_.empty()) {
43 waiting_ = true;
44 content::RunMessageLoop();
45 waiting_ = false;
46 }
47
48 if (!results_.empty()) {
49 bool ret = results_.front();
50 results_.pop_front();
51 return ret;
52 }
53 NOTREACHED();
54 return false;
55 }
56
57 private:
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)58 virtual void Observe(int type,
59 const content::NotificationSource& source,
60 const content::NotificationDetails& details) OVERRIDE {
61 results_.push_back(
62 static_cast<content::Source<extensions::TestSendMessageFunction> >(
63 source)
64 .ptr()
65 ->user_gesture());
66 if (waiting_)
67 base::MessageLoopForUI::current()->Quit();
68 }
69
70 content::NotificationRegistrar registrar_;
71
72 // A sequential list of user gesture notifications from the test extension(s).
73 std::deque<bool> results_;
74
75 // True if we're in a nested message loop waiting for results from
76 // the extension.
77 bool waiting_;
78 };
79
80 class NotificationsApiTest : public ExtensionApiTest {
81 public:
LoadExtensionAndWait(const std::string & test_name)82 const extensions::Extension* LoadExtensionAndWait(
83 const std::string& test_name) {
84 base::FilePath extdir = test_data_dir_.AppendASCII(test_name);
85 content::WindowedNotificationObserver page_created(
86 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
87 content::NotificationService::AllSources());
88 const extensions::Extension* extension = LoadExtension(extdir);
89 if (extension) {
90 page_created.Wait();
91 }
92 return extension;
93 }
94 };
95
96 } // namespace
97
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestBasicUsage)98 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestBasicUsage) {
99 ASSERT_TRUE(RunExtensionTest("notifications/api/basic_usage")) << message_;
100 }
101
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestEvents)102 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestEvents) {
103 ASSERT_TRUE(RunExtensionTest("notifications/api/events")) << message_;
104 }
105
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestCSP)106 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestCSP) {
107 ASSERT_TRUE(RunExtensionTest("notifications/api/csp")) << message_;
108 }
109
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestByUser)110 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestByUser) {
111 const extensions::Extension* extension =
112 LoadExtensionAndWait("notifications/api/by_user");
113 ASSERT_TRUE(extension) << message_;
114
115 {
116 ResultCatcher catcher;
117 g_browser_process->message_center()->RemoveNotification(
118 extension->id() + "-FOO",
119 false);
120 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
121 }
122
123 {
124 ResultCatcher catcher;
125 g_browser_process->message_center()->RemoveNotification(
126 extension->id() + "-BAR",
127 true);
128 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
129 }
130
131 {
132 ResultCatcher catcher;
133 g_browser_process->message_center()->RemoveAllNotifications(false);
134 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
135 }
136 {
137 ResultCatcher catcher;
138 g_browser_process->message_center()->RemoveAllNotifications(true);
139 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
140 }
141 }
142
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestPartialUpdate)143 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestPartialUpdate) {
144 ASSERT_TRUE(RunExtensionTest("notifications/api/partial_update")) << message_;
145 const extensions::Extension* extension = GetSingleLoadedExtension();
146 ASSERT_TRUE(extension) << message_;
147
148 const char kNewTitle[] = "Changed!";
149 const char kNewMessage[] = "Too late! The show ended yesterday";
150 int kNewPriority = 2;
151
152 const message_center::NotificationList::Notifications& notifications =
153 g_browser_process->message_center()->GetVisibleNotifications();
154 ASSERT_EQ(1u, notifications.size());
155 message_center::Notification* notification = *(notifications.begin());
156 LOG(INFO) << "Notification ID: " << notification->id();
157
158 EXPECT_EQ(base::ASCIIToUTF16(kNewTitle), notification->title());
159 EXPECT_EQ(base::ASCIIToUTF16(kNewMessage), notification->message());
160 EXPECT_EQ(kNewPriority, notification->priority());
161 EXPECT_EQ(0u, notification->buttons().size());
162 }
163
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestGetPermissionLevel)164 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestGetPermissionLevel) {
165 scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
166
167 // Get permission level for the extension whose notifications are enabled.
168 {
169 scoped_refptr<extensions::NotificationsGetPermissionLevelFunction>
170 notification_function(
171 new extensions::NotificationsGetPermissionLevelFunction());
172
173 notification_function->set_extension(empty_extension.get());
174 notification_function->set_has_callback(true);
175
176 scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
177 notification_function.get(),
178 "[]",
179 browser(),
180 utils::NONE));
181
182 EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
183 std::string permission_level;
184 EXPECT_TRUE(result->GetAsString(&permission_level));
185 EXPECT_EQ("granted", permission_level);
186 }
187
188 // Get permission level for the extension whose notifications are disabled.
189 {
190 scoped_refptr<extensions::NotificationsGetPermissionLevelFunction>
191 notification_function(
192 new extensions::NotificationsGetPermissionLevelFunction());
193
194 notification_function->set_extension(empty_extension.get());
195 notification_function->set_has_callback(true);
196
197 message_center::NotifierId notifier_id(
198 message_center::NotifierId::APPLICATION,
199 empty_extension->id());
200 message_center::Notifier notifier(notifier_id, base::string16(), true);
201 g_browser_process->message_center()->GetNotifierSettingsProvider()->
202 SetNotifierEnabled(notifier, false);
203
204 scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
205 notification_function.get(),
206 "[]",
207 browser(),
208 utils::NONE));
209
210 EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
211 std::string permission_level;
212 EXPECT_TRUE(result->GetAsString(&permission_level));
213 EXPECT_EQ("denied", permission_level);
214 }
215 }
216
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestOnPermissionLevelChanged)217 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestOnPermissionLevelChanged) {
218 const extensions::Extension* extension =
219 LoadExtensionAndWait("notifications/api/permission");
220 ASSERT_TRUE(extension) << message_;
221
222 // Test permission level changing from granted to denied.
223 {
224 ResultCatcher catcher;
225
226 message_center::NotifierId notifier_id(
227 message_center::NotifierId::APPLICATION,
228 extension->id());
229 message_center::Notifier notifier(notifier_id, base::string16(), true);
230 g_browser_process->message_center()->GetNotifierSettingsProvider()->
231 SetNotifierEnabled(notifier, false);
232
233 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
234 }
235
236 // Test permission level changing from denied to granted.
237 {
238 ResultCatcher catcher;
239
240 message_center::NotifierId notifier_id(
241 message_center::NotifierId::APPLICATION,
242 extension->id());
243 message_center::Notifier notifier(notifier_id, base::string16(), false);
244 g_browser_process->message_center()->GetNotifierSettingsProvider()->
245 SetNotifierEnabled(notifier, true);
246
247 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
248 }
249 }
250
IN_PROC_BROWSER_TEST_F(NotificationsApiTest,TestUserGesture)251 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestUserGesture) {
252 const extensions::Extension* extension =
253 LoadExtensionAndWait("notifications/api/user_gesture");
254 ASSERT_TRUE(extension) << message_;
255
256 const message_center::NotificationList::Notifications& notifications =
257 g_browser_process->message_center()->GetVisibleNotifications();
258 ASSERT_EQ(1u, notifications.size());
259 message_center::Notification* notification = *(notifications.begin());
260
261 {
262 UserGestureCatcher catcher;
263 notification->ButtonClick(0);
264 EXPECT_TRUE(catcher.GetNextResult());
265 notification->Click();
266 EXPECT_TRUE(catcher.GetNextResult());
267 notification->Close(true);
268 EXPECT_TRUE(catcher.GetNextResult());
269 notification->Close(false);
270 EXPECT_FALSE(catcher.GetNextResult());
271 }
272 }
273