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 "ui/message_center/message_center_impl.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/message_center/message_center.h"
13 #include "ui/message_center/message_center_types.h"
14 #include "ui/message_center/notification_blocker.h"
15 #include "ui/message_center/notification_types.h"
17 namespace message_center
{
20 class MessageCenterImplTest
: public testing::Test
,
21 public MessageCenterObserver
{
23 MessageCenterImplTest() {}
25 virtual void SetUp() OVERRIDE
{
26 MessageCenter::Initialize();
27 message_center_
= MessageCenter::Get();
28 loop_
.reset(new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT
));
29 run_loop_
.reset(new base::RunLoop());
30 closure_
= run_loop_
->QuitClosure();
33 virtual void TearDown() OVERRIDE
{
36 message_center_
= NULL
;
37 MessageCenter::Shutdown();
40 MessageCenter
* message_center() const { return message_center_
; }
41 base::RunLoop
* run_loop() const { return run_loop_
.get(); }
42 base::Closure
closure() const { return closure_
; }
45 Notification
* CreateSimpleNotification(const std::string
& id
) {
46 return CreateNotification(id
, NOTIFICATION_TYPE_SIMPLE
);
49 Notification
* CreateNotification(const std::string
& id
,
50 message_center::NotificationType type
) {
51 return new Notification(type
,
55 gfx::Image() /* icon */,
56 base::string16() /* display_source */,
57 NotifierId(NotifierId::APPLICATION
, "app1"),
58 RichNotificationData(),
63 MessageCenter
* message_center_
;
64 scoped_ptr
<base::MessageLoop
> loop_
;
65 scoped_ptr
<base::RunLoop
> run_loop_
;
66 base::Closure closure_
;
68 DISALLOW_COPY_AND_ASSIGN(MessageCenterImplTest
);
71 class ToggledNotificationBlocker
: public NotificationBlocker
{
73 explicit ToggledNotificationBlocker(MessageCenter
* message_center
)
74 : NotificationBlocker(message_center
),
75 notifications_enabled_(true) {}
76 virtual ~ToggledNotificationBlocker() {}
78 void SetNotificationsEnabled(bool enabled
) {
79 if (notifications_enabled_
!= enabled
) {
80 notifications_enabled_
= enabled
;
82 NotificationBlocker::Observer
, observers(), OnBlockingStateChanged());
86 // NotificationBlocker overrides:
87 virtual bool ShouldShowNotificationAsPopup(
88 const message_center::NotifierId
& notifier_id
) const OVERRIDE
{
89 return notifications_enabled_
;
93 bool notifications_enabled_
;
95 DISALLOW_COPY_AND_ASSIGN(ToggledNotificationBlocker
);
98 class PopupNotificationBlocker
: public ToggledNotificationBlocker
{
100 PopupNotificationBlocker(MessageCenter
* message_center
,
101 const NotifierId
& allowed_notifier
)
102 : ToggledNotificationBlocker(message_center
),
103 allowed_notifier_(allowed_notifier
) {}
104 virtual ~PopupNotificationBlocker() {}
106 // NotificationBlocker overrides:
107 virtual bool ShouldShowNotificationAsPopup(
108 const NotifierId
& notifier_id
) const OVERRIDE
{
109 return (notifier_id
== allowed_notifier_
) ||
110 ToggledNotificationBlocker::ShouldShowNotificationAsPopup(notifier_id
);
114 NotifierId allowed_notifier_
;
116 DISALLOW_COPY_AND_ASSIGN(PopupNotificationBlocker
);
119 bool PopupNotificationsContain(
120 const NotificationList::PopupNotifications
& popups
,
121 const std::string
& id
) {
122 for (NotificationList::PopupNotifications::const_iterator iter
=
123 popups
.begin(); iter
!= popups
.end(); ++iter
) {
124 if ((*iter
)->id() == id
)
134 class MockPopupTimersController
: public PopupTimersController
{
136 MockPopupTimersController(MessageCenter
* message_center
,
137 base::Closure quit_closure
)
138 : PopupTimersController(message_center
),
139 timer_finished_(false),
140 quit_closure_(quit_closure
) {}
141 virtual ~MockPopupTimersController() {}
143 virtual void TimerFinished(const std::string
& id
) OVERRIDE
{
144 base::MessageLoop::current()->PostTask(FROM_HERE
, quit_closure_
);
145 timer_finished_
= true;
149 bool timer_finished() const { return timer_finished_
; }
150 const std::string
& last_id() const { return last_id_
; }
153 bool timer_finished_
;
154 std::string last_id_
;
155 base::Closure quit_closure_
;
158 TEST_F(MessageCenterImplTest
, PopupTimersEmptyController
) {
159 scoped_ptr
<PopupTimersController
> popup_timers_controller
=
160 make_scoped_ptr(new PopupTimersController(message_center()));
162 // Test that all functions succed without any timers created.
163 popup_timers_controller
->PauseAll();
164 popup_timers_controller
->StartAll();
165 popup_timers_controller
->CancelAll();
166 popup_timers_controller
->TimerFinished("unknown");
167 popup_timers_controller
->PauseTimer("unknown");
168 popup_timers_controller
->CancelTimer("unknown");
171 TEST_F(MessageCenterImplTest
, PopupTimersControllerStartTimer
) {
172 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
174 new MockPopupTimersController(message_center(), closure()));
175 popup_timers_controller
->StartTimer("test",
176 base::TimeDelta::FromMilliseconds(1));
178 EXPECT_TRUE(popup_timers_controller
->timer_finished());
181 TEST_F(MessageCenterImplTest
, PopupTimersControllerPauseTimer
) {
182 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
184 new MockPopupTimersController(message_center(), closure()));
185 popup_timers_controller
->StartTimer("test",
186 base::TimeDelta::FromMilliseconds(1));
187 popup_timers_controller
->PauseTimer("test");
188 run_loop()->RunUntilIdle();
190 EXPECT_FALSE(popup_timers_controller
->timer_finished());
193 TEST_F(MessageCenterImplTest
, PopupTimersControllerCancelTimer
) {
194 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
196 new MockPopupTimersController(message_center(), closure()));
197 popup_timers_controller
->StartTimer("test",
198 base::TimeDelta::FromMilliseconds(1));
199 popup_timers_controller
->CancelTimer("test");
200 run_loop()->RunUntilIdle();
202 EXPECT_FALSE(popup_timers_controller
->timer_finished());
205 TEST_F(MessageCenterImplTest
, PopupTimersControllerPauseAllTimers
) {
206 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
208 new MockPopupTimersController(message_center(), closure()));
209 popup_timers_controller
->StartTimer("test",
210 base::TimeDelta::FromMilliseconds(1));
211 popup_timers_controller
->PauseAll();
212 run_loop()->RunUntilIdle();
214 EXPECT_FALSE(popup_timers_controller
->timer_finished());
217 TEST_F(MessageCenterImplTest
, PopupTimersControllerStartAllTimers
) {
218 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
220 new MockPopupTimersController(message_center(), closure()));
221 popup_timers_controller
->StartTimer("test",
222 base::TimeDelta::FromMilliseconds(1));
223 popup_timers_controller
->PauseAll();
224 popup_timers_controller
->StartAll();
227 EXPECT_TRUE(popup_timers_controller
->timer_finished());
230 TEST_F(MessageCenterImplTest
, PopupTimersControllerStartMultipleTimers
) {
231 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
233 new MockPopupTimersController(message_center(), closure()));
234 popup_timers_controller
->StartTimer("test",
235 base::TimeDelta::FromMilliseconds(5));
236 popup_timers_controller
->StartTimer("test2",
237 base::TimeDelta::FromMilliseconds(1));
238 popup_timers_controller
->StartTimer("test3",
239 base::TimeDelta::FromMilliseconds(3));
240 popup_timers_controller
->PauseAll();
241 popup_timers_controller
->StartAll();
244 EXPECT_EQ(popup_timers_controller
->last_id(), "test2");
245 EXPECT_TRUE(popup_timers_controller
->timer_finished());
248 TEST_F(MessageCenterImplTest
, PopupTimersControllerStartMultipleTimersPause
) {
249 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
251 new MockPopupTimersController(message_center(), closure()));
252 popup_timers_controller
->StartTimer("test",
253 base::TimeDelta::FromMilliseconds(5));
254 popup_timers_controller
->StartTimer("test2",
255 base::TimeDelta::FromMilliseconds(1));
256 popup_timers_controller
->StartTimer("test3",
257 base::TimeDelta::FromMilliseconds(3));
258 popup_timers_controller
->PauseTimer("test2");
262 EXPECT_EQ(popup_timers_controller
->last_id(), "test3");
263 EXPECT_TRUE(popup_timers_controller
->timer_finished());
266 TEST_F(MessageCenterImplTest
, PopupTimersControllerResetTimer
) {
267 scoped_ptr
<MockPopupTimersController
> popup_timers_controller
=
269 new MockPopupTimersController(message_center(), closure()));
270 popup_timers_controller
->StartTimer("test",
271 base::TimeDelta::FromMilliseconds(5));
272 popup_timers_controller
->StartTimer("test2",
273 base::TimeDelta::FromMilliseconds(1));
274 popup_timers_controller
->StartTimer("test3",
275 base::TimeDelta::FromMilliseconds(3));
276 popup_timers_controller
->PauseTimer("test2");
277 popup_timers_controller
->ResetTimer("test",
278 base::TimeDelta::FromMilliseconds(2));
282 EXPECT_EQ(popup_timers_controller
->last_id(), "test");
283 EXPECT_TRUE(popup_timers_controller
->timer_finished());
286 TEST_F(MessageCenterImplTest
, NotificationBlocker
) {
287 NotifierId
notifier_id(NotifierId::APPLICATION
, "app1");
288 // Multiple blockers to verify the case that one blocker blocks but another
290 ToggledNotificationBlocker
blocker1(message_center());
291 ToggledNotificationBlocker
blocker2(message_center());
293 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
294 NOTIFICATION_TYPE_SIMPLE
,
296 UTF8ToUTF16("title"),
297 UTF8ToUTF16("message"),
298 gfx::Image() /* icon */,
299 base::string16() /* display_source */,
301 RichNotificationData(),
303 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
304 NOTIFICATION_TYPE_SIMPLE
,
306 UTF8ToUTF16("title"),
307 UTF8ToUTF16("message"),
308 gfx::Image() /* icon */,
309 base::string16() /* display_source */,
311 RichNotificationData(),
313 EXPECT_EQ(2u, message_center()->GetPopupNotifications().size());
314 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
316 // Block all notifications. All popups are gone and message center should be
318 blocker1
.SetNotificationsEnabled(false);
319 EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
320 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
322 // Updates |blocker2| state, which doesn't affect the global state.
323 blocker2
.SetNotificationsEnabled(false);
324 EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
325 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
327 blocker2
.SetNotificationsEnabled(true);
328 EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
329 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
331 // If |blocker2| blocks, then unblocking blocker1 doesn't change the global
333 blocker2
.SetNotificationsEnabled(false);
334 blocker1
.SetNotificationsEnabled(true);
335 EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
336 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
338 // Unblock both blockers, which recovers the global state, but the popups
340 blocker2
.SetNotificationsEnabled(true);
341 EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
342 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
345 TEST_F(MessageCenterImplTest
, NotificationsDuringBlocked
) {
346 NotifierId
notifier_id(NotifierId::APPLICATION
, "app1");
347 ToggledNotificationBlocker
blocker(message_center());
349 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
350 NOTIFICATION_TYPE_SIMPLE
,
352 UTF8ToUTF16("title"),
353 UTF8ToUTF16("message"),
354 gfx::Image() /* icon */,
355 base::string16() /* display_source */,
357 RichNotificationData(),
359 EXPECT_EQ(1u, message_center()->GetPopupNotifications().size());
360 EXPECT_EQ(1u, message_center()->GetVisibleNotifications().size());
362 // Create a notification during blocked. Still no popups.
363 blocker
.SetNotificationsEnabled(false);
364 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
365 NOTIFICATION_TYPE_SIMPLE
,
367 UTF8ToUTF16("title"),
368 UTF8ToUTF16("message"),
369 gfx::Image() /* icon */,
370 base::string16() /* display_source */,
372 RichNotificationData(),
374 EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
375 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
377 // Unblock notifications, the id1 should appear as a popup.
378 blocker
.SetNotificationsEnabled(true);
379 NotificationList::PopupNotifications popups
=
380 message_center()->GetPopupNotifications();
381 EXPECT_EQ(1u, popups
.size());
382 EXPECT_TRUE(PopupNotificationsContain(popups
, "id2"));
383 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
386 // Similar to other blocker cases but this test case allows |notifier_id2| even
388 TEST_F(MessageCenterImplTest
, NotificationBlockerAllowsPopups
) {
389 NotifierId
notifier_id1(NotifierId::APPLICATION
, "app1");
390 NotifierId
notifier_id2(NotifierId::APPLICATION
, "app2");
391 PopupNotificationBlocker
blocker(message_center(), notifier_id2
);
393 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
394 NOTIFICATION_TYPE_SIMPLE
,
396 UTF8ToUTF16("title"),
397 UTF8ToUTF16("message"),
398 gfx::Image() /* icon */,
399 base::string16() /* display_source */,
401 RichNotificationData(),
403 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
404 NOTIFICATION_TYPE_SIMPLE
,
406 UTF8ToUTF16("title"),
407 UTF8ToUTF16("message"),
408 gfx::Image() /* icon */,
409 base::string16() /* display_source */,
411 RichNotificationData(),
414 // "id1" is closed but "id2" is still visible as a popup.
415 blocker
.SetNotificationsEnabled(false);
416 NotificationList::PopupNotifications popups
=
417 message_center()->GetPopupNotifications();
418 EXPECT_EQ(1u, popups
.size());
419 EXPECT_TRUE(PopupNotificationsContain(popups
, "id2"));
420 EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
422 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
423 NOTIFICATION_TYPE_SIMPLE
,
425 UTF8ToUTF16("title"),
426 UTF8ToUTF16("message"),
427 gfx::Image() /* icon */,
428 base::string16() /* display_source */,
430 RichNotificationData(),
432 message_center()->AddNotification(scoped_ptr
<Notification
>(new Notification(
433 NOTIFICATION_TYPE_SIMPLE
,
435 UTF8ToUTF16("title"),
436 UTF8ToUTF16("message"),
437 gfx::Image() /* icon */,
438 base::string16() /* display_source */,
440 RichNotificationData(),
442 popups
= message_center()->GetPopupNotifications();
443 EXPECT_EQ(2u, popups
.size());
444 EXPECT_TRUE(PopupNotificationsContain(popups
, "id2"));
445 EXPECT_TRUE(PopupNotificationsContain(popups
, "id4"));
446 EXPECT_EQ(4u, message_center()->GetVisibleNotifications().size());
448 blocker
.SetNotificationsEnabled(true);
449 popups
= message_center()->GetPopupNotifications();
450 EXPECT_EQ(3u, popups
.size());
451 EXPECT_TRUE(PopupNotificationsContain(popups
, "id2"));
452 EXPECT_TRUE(PopupNotificationsContain(popups
, "id3"));
453 EXPECT_TRUE(PopupNotificationsContain(popups
, "id4"));
454 EXPECT_EQ(4u, message_center()->GetVisibleNotifications().size());
457 TEST_F(MessageCenterImplTest
, QueueUpdatesWithCenterVisible
) {
458 std::string
id("id1");
459 std::string
id2("id2");
460 NotifierId
notifier_id1(NotifierId::APPLICATION
, "app1");
462 // First, add and update a notification to ensure updates happen
464 scoped_ptr
<Notification
> notification(CreateSimpleNotification(id
));
465 message_center()->AddNotification(notification
.Pass());
466 notification
.reset(CreateSimpleNotification(id2
));
467 message_center()->UpdateNotification(id
, notification
.Pass());
468 EXPECT_TRUE(message_center()->HasNotification(id2
));
469 EXPECT_FALSE(message_center()->HasNotification(id
));
471 // Then open the message center.
472 message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER
);
474 // Then update a notification; nothing should have happened.
475 notification
.reset(CreateSimpleNotification(id
));
476 message_center()->UpdateNotification(id2
, notification
.Pass());
477 EXPECT_TRUE(message_center()->HasNotification(id2
));
478 EXPECT_FALSE(message_center()->HasNotification(id
));
480 // Close the message center; then the update should have propagated.
481 message_center()->SetVisibility(VISIBILITY_TRANSIENT
);
482 EXPECT_FALSE(message_center()->HasNotification(id2
));
483 EXPECT_TRUE(message_center()->HasNotification(id
));
486 TEST_F(MessageCenterImplTest
, ComplexQueueing
) {
487 std::string ids
[5] = {"0", "1", "2", "3", "4p"};
488 NotifierId
notifier_id1(NotifierId::APPLICATION
, "app1");
490 scoped_ptr
<Notification
> notification
;
491 // Add some notifications
494 notification
.reset(CreateSimpleNotification(ids
[i
]));
495 message_center()->AddNotification(notification
.Pass());
497 for (i
= 0; i
< 3; i
++) {
498 EXPECT_TRUE(message_center()->HasNotification(ids
[i
]));
501 EXPECT_FALSE(message_center()->HasNotification(ids
[i
]));
504 notification
.reset(CreateNotification(ids
[4], NOTIFICATION_TYPE_PROGRESS
));
505 message_center()->AddNotification(notification
.Pass());
507 // Now start queueing.
508 // NL: ["0", "1", "2", "4p"]
509 message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER
);
511 // This should update notification "1" to have id "3".
512 notification
.reset(CreateSimpleNotification(ids
[3]));
513 message_center()->UpdateNotification(ids
[1], notification
.Pass());
515 notification
.reset(CreateSimpleNotification(ids
[4]));
516 message_center()->UpdateNotification(ids
[4], notification
.Pass());
518 notification
.reset(CreateNotification(ids
[4], NOTIFICATION_TYPE_PROGRESS
));
519 message_center()->UpdateNotification(ids
[4], notification
.Pass());
521 // This should update notification "3" to a new ID after we go TRANSIENT.
522 notification
.reset(CreateSimpleNotification("New id"));
523 message_center()->UpdateNotification(ids
[3], notification
.Pass());
525 // This should create a new "3", that doesn't overwrite the update to 3
527 notification
.reset(CreateSimpleNotification(ids
[3]));
528 message_center()->AddNotification(notification
.Pass());
530 // The NL should still be the same: ["0", "1", "2", "4p"]
531 EXPECT_TRUE(message_center()->HasNotification(ids
[0]));
532 EXPECT_TRUE(message_center()->HasNotification(ids
[1]));
533 EXPECT_TRUE(message_center()->HasNotification(ids
[2]));
534 EXPECT_FALSE(message_center()->HasNotification(ids
[3]));
535 EXPECT_TRUE(message_center()->HasNotification(ids
[4]));
536 EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 4u);
537 message_center()->SetVisibility(VISIBILITY_TRANSIENT
);
539 EXPECT_TRUE(message_center()->HasNotification(ids
[0]));
540 EXPECT_FALSE(message_center()->HasNotification(ids
[1]));
541 EXPECT_TRUE(message_center()->HasNotification(ids
[2]));
542 EXPECT_TRUE(message_center()->HasNotification(ids
[3]));
543 EXPECT_TRUE(message_center()->HasNotification(ids
[4]));
544 EXPECT_TRUE(message_center()->HasNotification("New id"));
545 EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 5u);
548 } // namespace internal
549 } // namespace message_center