1 // Copyright (c) 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 <map>
6 #include <string>
7
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/notifications/message_center_notification_manager.h"
16 #include "chrome/browser/notifications/notification.h"
17 #include "chrome/browser/notifications/notification_ui_manager.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/test_switches.h"
22 #include "content/public/browser/notification_details.h"
23 #include "content/public/browser/notification_observer.h"
24 #include "content/public/browser/notification_source.h"
25 #include "ui/message_center/message_center.h"
26 #include "ui/message_center/message_center_types.h"
27
28 class TestAddObserver : public message_center::MessageCenterObserver {
29 public:
TestAddObserver(message_center::MessageCenter * message_center)30 explicit TestAddObserver(message_center::MessageCenter* message_center)
31 : message_center_(message_center) {
32 message_center_->AddObserver(this);
33 }
34
~TestAddObserver()35 virtual ~TestAddObserver() { message_center_->RemoveObserver(this); }
36
OnNotificationAdded(const std::string & id)37 virtual void OnNotificationAdded(const std::string& id) OVERRIDE {
38 std::string log = logs_[id];
39 if (log != "")
40 log += "_";
41 logs_[id] = log + "add-" + id;
42 }
43
OnNotificationUpdated(const std::string & id)44 virtual void OnNotificationUpdated(const std::string& id) OVERRIDE {
45 std::string log = logs_[id];
46 if (log != "")
47 log += "_";
48 logs_[id] = log + "update-" + id;
49 }
50
log(const std::string & id)51 const std::string log(const std::string& id) { return logs_[id]; }
reset_logs()52 void reset_logs() { logs_.clear(); }
53
54 private:
55 std::map<std::string, std::string> logs_;
56 message_center::MessageCenter* message_center_;
57 };
58
59 class MessageCenterNotificationsTest : public InProcessBrowserTest {
60 public:
MessageCenterNotificationsTest()61 MessageCenterNotificationsTest() {}
62
manager()63 MessageCenterNotificationManager* manager() {
64 return static_cast<MessageCenterNotificationManager*>(
65 g_browser_process->notification_ui_manager());
66 }
67
message_center()68 message_center::MessageCenter* message_center() {
69 return g_browser_process->message_center();
70 }
71
profile()72 Profile* profile() { return browser()->profile(); }
73
74 class TestDelegate : public NotificationDelegate {
75 public:
TestDelegate(const std::string & id)76 explicit TestDelegate(const std::string& id) : id_(id) {}
77
Display()78 virtual void Display() OVERRIDE { log_ += "Display_"; }
Error()79 virtual void Error() OVERRIDE { log_ += "Error_"; }
Close(bool by_user)80 virtual void Close(bool by_user) OVERRIDE {
81 log_ += "Close_";
82 log_ += ( by_user ? "by_user_" : "programmatically_");
83 }
Click()84 virtual void Click() OVERRIDE { log_ += "Click_"; }
ButtonClick(int button_index)85 virtual void ButtonClick(int button_index) OVERRIDE {
86 log_ += "ButtonClick_";
87 log_ += base::IntToString(button_index) + "_";
88 }
id() const89 virtual std::string id() const OVERRIDE { return id_; }
GetWebContents() const90 virtual content::WebContents* GetWebContents() const OVERRIDE {
91 return NULL;
92 }
93
log()94 const std::string& log() { return log_; }
95
96 private:
~TestDelegate()97 virtual ~TestDelegate() {}
98 std::string id_;
99 std::string log_;
100
101 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
102 };
103
CreateTestNotification(const std::string & id,TestDelegate ** delegate=NULL)104 Notification CreateTestNotification(const std::string& id,
105 TestDelegate** delegate = NULL) {
106 TestDelegate* new_delegate = new TestDelegate(id);
107 if (delegate) {
108 *delegate = new_delegate;
109 new_delegate->AddRef();
110 }
111
112 return Notification(GURL("chrome-test://testing/"),
113 GURL(),
114 base::ASCIIToUTF16("title"),
115 base::ASCIIToUTF16("message"),
116 blink::WebTextDirectionDefault,
117 base::UTF8ToUTF16("chrome-test://testing/"),
118 base::UTF8ToUTF16("REPLACE-ME"),
119 new_delegate);
120 }
121
CreateRichTestNotification(const std::string & id,TestDelegate ** delegate=NULL)122 Notification CreateRichTestNotification(const std::string& id,
123 TestDelegate** delegate = NULL) {
124 TestDelegate* new_delegate = new TestDelegate(id);
125 if (delegate) {
126 *delegate = new_delegate;
127 new_delegate->AddRef();
128 }
129
130 message_center::RichNotificationData data;
131
132 return Notification(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
133 GURL("chrome-test://testing/"),
134 base::ASCIIToUTF16("title"),
135 base::ASCIIToUTF16("message"),
136 gfx::Image(),
137 blink::WebTextDirectionDefault,
138 message_center::NotifierId(
139 message_center::NotifierId::APPLICATION,
140 "extension_id"),
141 base::UTF8ToUTF16("chrome-test://testing/"),
142 base::UTF8ToUTF16("REPLACE-ME"),
143 data,
144 new_delegate);
145 }
146 };
147
148 // TODO(rsesek): Implement Message Center on Mac and get these tests passing
149 // for real. http://crbug.com/179904
150 #if !defined(OS_MACOSX)
151
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,RetrieveBaseParts)152 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, RetrieveBaseParts) {
153 EXPECT_TRUE(manager());
154 EXPECT_TRUE(message_center());
155 }
156
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,BasicAddCancel)157 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, BasicAddCancel) {
158 #if defined(OS_WIN) && defined(USE_ASH)
159 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
160 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
161 return;
162 #endif
163
164 // Someone may create system notifications like "you're in multi-profile
165 // mode..." or something which may change the expectation.
166 // TODO(mukai): move this to SetUpOnMainThread() after fixing the side-effect
167 // of canceling animation which prevents some Displayed() event.
168 manager()->CancelAll();
169 manager()->Add(CreateTestNotification("hey"), profile());
170 EXPECT_EQ(1u, message_center()->NotificationCount());
171 manager()->CancelById("hey");
172 EXPECT_EQ(0u, message_center()->NotificationCount());
173 }
174
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,BasicDelegate)175 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, BasicDelegate) {
176 #if defined(OS_WIN) && defined(USE_ASH)
177 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
178 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
179 return;
180 #endif
181
182 TestDelegate* delegate;
183 manager()->Add(CreateTestNotification("hey", &delegate), profile());
184 // Verify that delegate accumulated correct log of events.
185 EXPECT_EQ("Display_", delegate->log());
186 manager()->CancelById("hey");
187 // Verify that delegate accumulated correct log of events.
188 EXPECT_EQ("Display_Close_programmatically_", delegate->log());
189 delegate->Release();
190 }
191
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,ButtonClickedDelegate)192 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, ButtonClickedDelegate) {
193 #if defined(OS_WIN) && defined(USE_ASH)
194 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
195 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
196 return;
197 #endif
198
199 TestDelegate* delegate;
200 manager()->Add(CreateTestNotification("n", &delegate), profile());
201 message_center()->ClickOnNotificationButton("n", 1);
202 // Verify that delegate accumulated correct log of events.
203 EXPECT_EQ("Display_ButtonClick_1_", delegate->log());
204 delegate->Release();
205 }
206
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,UpdateExistingNotification)207 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
208 UpdateExistingNotification) {
209 #if defined(OS_WIN) && defined(USE_ASH)
210 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
211 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
212 return;
213 #endif
214
215 TestDelegate* delegate;
216 manager()->Add(CreateTestNotification("n", &delegate), profile());
217 TestDelegate* delegate2;
218 manager()->Add(CreateRichTestNotification("n", &delegate2), profile());
219
220 manager()->CancelById("n");
221 EXPECT_EQ("Display_", delegate->log());
222 EXPECT_EQ("Close_programmatically_", delegate2->log());
223
224 delegate->Release();
225 delegate2->Release();
226 }
227
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,QueueWhenCenterVisible)228 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, QueueWhenCenterVisible) {
229 #if defined(OS_WIN) && defined(USE_ASH)
230 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
231 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
232 return;
233 #endif
234
235 TestAddObserver observer(message_center());
236
237 TestDelegate* delegate;
238 TestDelegate* delegate2;
239
240 manager()->Add(CreateTestNotification("n", &delegate), profile());
241 message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
242 manager()->Add(CreateTestNotification("n2", &delegate2), profile());
243
244 // 'update-n' should happen since SetVisibility updates is_read status of n.
245 // TODO(mukai): fix event handling to happen update-n just once.
246 EXPECT_EQ("add-n_update-n_update-n", observer.log("n"));
247
248 message_center()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
249
250 EXPECT_EQ("add-n2", observer.log("n2"));
251
252 delegate->Release();
253 delegate2->Release();
254 }
255
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,UpdateNonProgressNotificationWhenCenterVisible)256 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
257 UpdateNonProgressNotificationWhenCenterVisible) {
258 #if defined(OS_WIN) && defined(USE_ASH)
259 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
260 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
261 return;
262 #endif
263
264 TestAddObserver observer(message_center());
265
266 TestDelegate* delegate;
267
268 // Add a non-progress notification and update it while the message center
269 // is visible.
270 Notification notification = CreateTestNotification("n", &delegate);
271 manager()->Add(notification, profile());
272 message_center()->ClickOnNotification("n");
273 message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
274 observer.reset_logs();
275 notification.set_title(base::ASCIIToUTF16("title2"));
276 manager()->Update(notification, profile());
277
278 // Expect that the notification update is not done.
279 EXPECT_EQ("", observer.log("n"));
280
281 message_center()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
282 EXPECT_EQ("update-n", observer.log("n"));
283
284 delegate->Release();
285 }
286
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,UpdateNonProgressToProgressNotificationWhenCenterVisible)287 IN_PROC_BROWSER_TEST_F(
288 MessageCenterNotificationsTest,
289 UpdateNonProgressToProgressNotificationWhenCenterVisible) {
290 #if defined(OS_WIN) && defined(USE_ASH)
291 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
292 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
293 return;
294 #endif
295
296 TestAddObserver observer(message_center());
297
298 TestDelegate* delegate;
299
300 // Add a non-progress notification and change the type to progress while the
301 // message center is visible.
302 Notification notification = CreateTestNotification("n", &delegate);
303 manager()->Add(notification, profile());
304 message_center()->ClickOnNotification("n");
305 message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
306 observer.reset_logs();
307 notification.set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
308 manager()->Update(notification, profile());
309
310 // Expect that the notification update is not done.
311 EXPECT_EQ("", observer.log("n"));
312
313 message_center()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
314 EXPECT_EQ("update-n", observer.log("n"));
315
316 delegate->Release();
317 }
318
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,UpdateProgressNotificationWhenCenterVisible)319 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
320 UpdateProgressNotificationWhenCenterVisible) {
321 #if defined(OS_WIN) && defined(USE_ASH)
322 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
323 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
324 return;
325 #endif
326
327 TestAddObserver observer(message_center());
328
329 TestDelegate* delegate;
330
331 // Add a progress notification and update it while the message center
332 // is visible.
333 Notification notification = CreateTestNotification("n", &delegate);
334 notification.set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
335 manager()->Add(notification, profile());
336 message_center()->ClickOnNotification("n");
337 message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
338 observer.reset_logs();
339 notification.set_progress(50);
340 manager()->Update(notification, profile());
341
342 // Expect that the progress notification update is performed.
343 EXPECT_EQ("update-n", observer.log("n"));
344
345 delegate->Release();
346 }
347
348 #if !defined(OS_CHROMEOS)
349 #define MAYBE_HideWhenFullscreenEnabled HideWhenFullscreenEnabled
350 #else
351 #define MAYBE_HideWhenFullscreenEnabled DISABLED_HideWhenFullscreenEnabled
352 #endif
353
IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,MAYBE_HideWhenFullscreenEnabled)354 IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
355 MAYBE_HideWhenFullscreenEnabled) {
356 TestDelegate* delegate;
357 manager()->Add(CreateTestNotification("n", &delegate), profile());
358
359 EXPECT_EQ("Display_", delegate->log());
360 EXPECT_TRUE(message_center()->HasPopupNotifications());
361 bool is_fullscreen = true;
362 // Cast so that Observe() is public.
363 content::NotificationObserver* observer =
364 static_cast<content::NotificationObserver*>(manager());
365 observer->Observe(chrome::NOTIFICATION_FULLSCREEN_CHANGED,
366 content::Source<Profile>(profile()),
367 content::Details<bool>(&is_fullscreen));
368 EXPECT_FALSE(message_center()->HasPopupNotifications());
369 }
370
371 #endif // !defined(OS_MACOSX)
372