1// Copyright (c) 2011 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/memory/ref_counted.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/message_loop.h"
8#include "base/string16.h"
9#include "base/string_util.h"
10#include "base/stringprintf.h"
11#include "base/utf_string_conversions.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h"
14#include "chrome/browser/chromeos/notifications/balloon_view.h"
15#include "chrome/browser/chromeos/notifications/notification_panel.h"
16#include "chrome/browser/chromeos/notifications/system_notification_factory.h"
17#include "chrome/browser/notifications/notification_test_util.h"
18#include "chrome/browser/notifications/notification_ui_manager.h"
19#include "chrome/browser/ui/browser.h"
20#include "chrome/test/in_process_browser_test.h"
21#include "chrome/test/ui_test_utils.h"
22#include "content/common/notification_service.h"
23#include "ui/base/x/x11_util.h"
24
25namespace {
26
27// The name of ChromeOS's window manager.
28const char* kChromeOsWindowManagerName = "chromeos-wm";
29
30}  // namespace
31
32namespace chromeos {
33
34class NotificationTest : public InProcessBrowserTest,
35                         public NotificationObserver {
36 public:
37  NotificationTest()
38      : under_chromeos_(false),
39        state_(PanelController::INITIAL),
40        expected_(PanelController::INITIAL) {
41  }
42
43  void HandleWebUIMessage(const ListValue* value) {
44    MessageLoop::current()->Quit();
45  }
46
47 protected:
48  virtual void SetUp() {
49    // Detect if we're running under ChromeOS WindowManager. See
50    // the description for "under_chromeos_" below for why we need this.
51    std::string wm_name;
52    bool wm_name_valid = ui::GetWindowManagerName(&wm_name);
53    // NOTE: On Chrome OS the wm and Chrome are started in parallel. This
54    // means it's possible for us not to be able to get the name of the window
55    // manager. We assume that when this happens we're on Chrome OS.
56    under_chromeos_ = (!wm_name_valid ||
57                       wm_name == kChromeOsWindowManagerName);
58    InProcessBrowserTest::SetUp();
59  }
60
61  BalloonCollectionImpl* GetBalloonCollectionImpl() {
62    return static_cast<BalloonCollectionImpl*>(
63        g_browser_process->notification_ui_manager()->balloon_collection());
64  }
65
66  NotificationPanel* GetNotificationPanel() {
67    return static_cast<NotificationPanel*>(
68        GetBalloonCollectionImpl()->notification_ui());
69  }
70
71  Notification NewMockNotification(const std::string& id) {
72    return NewMockNotification(new MockNotificationDelegate(id));
73  }
74
75  Notification NewMockNotification(NotificationDelegate* delegate) {
76    std::string text = delegate->id();
77    return SystemNotificationFactory::Create(
78        GURL(), ASCIIToUTF16(text.c_str()), ASCIIToUTF16(text.c_str()),
79        delegate);
80  }
81
82  void MarkStale(const char* id) {
83    GetNotificationPanel()->GetTester()->MarkStale(NewMockNotification(id));
84  }
85
86  // Waits untilt the panel's state becomes the specified state.
87  // Does nothing if it's not running with ChromeOS Window Manager.
88  void WaitForPanelState(NotificationPanelTester* tester,
89                         PanelController::State state) {
90    if (under_chromeos_ && state != state_) {
91      expected_ = state;
92      ui_test_utils::RunAllPendingInMessageLoop();
93    }
94  }
95
96  // Busy loop to wait until the view becomes visible in the panel.
97  void WaitForVisible(BalloonViewImpl* view) {
98    WaitForResize(view);
99    NotificationPanelTester* tester = GetNotificationPanel()->GetTester();
100    while (!tester->IsVisible(view)) {
101      ui_test_utils::RunAllPendingInMessageLoop();
102    }
103  }
104
105  // Busy loop to wait until the webkit give some size to the notification.
106  void WaitForResize(BalloonViewImpl* view) {
107    while (view->bounds().IsEmpty()) {
108      ui_test_utils::RunAllPendingInMessageLoop();
109    }
110  }
111
112  // NotificationObserver overrides.
113  virtual void Observe(NotificationType type,
114                       const NotificationSource& source,
115                       const NotificationDetails& details) {
116    ASSERT_TRUE(NotificationType::PANEL_STATE_CHANGED == type);
117    PanelController::State* state =
118        reinterpret_cast<PanelController::State*>(details.map_key());
119    state_ = *state;
120    if (under_chromeos_ && expected_ == state_) {
121      expected_ = PanelController::INITIAL;
122      MessageLoop::current()->Quit();
123    }
124  }
125
126 private:
127  // ChromeOS build of chrome communicates with ChromeOS's
128  // WindowManager, and behaves differently if it runs under a
129  // chromeos window manager.  ChromeOS WindowManager sends
130  // EXPANDED/MINIMIED state change message when the panels's state
131  // changed (regardless of who changed it), and to avoid
132  // mis-recognizing such events as user-initiated actions, we need to
133  // wait and eat them before moving to a next step.
134  bool under_chromeos_;
135  PanelController::State state_;
136  PanelController::State expected_;
137};
138
139IN_PROC_BROWSER_TEST_F(NotificationTest, TestBasic) {
140  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
141  NotificationPanel* panel = GetNotificationPanel();
142  NotificationPanelTester* tester = panel->GetTester();
143
144  // Using system notification as regular notification.
145  collection->Add(NewMockNotification("1"), browser()->profile());
146
147  EXPECT_EQ(1, tester->GetNewNotificationCount());
148  EXPECT_EQ(1, tester->GetNotificationCount());
149  EXPECT_EQ(0, tester->GetStickyNotificationCount());
150  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
151
152  collection->Add(NewMockNotification("2"), browser()->profile());
153
154  EXPECT_EQ(2, tester->GetNewNotificationCount());
155  EXPECT_EQ(2, tester->GetNotificationCount());
156  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
157
158  collection->RemoveById("1");
159  ui_test_utils::RunAllPendingInMessageLoop();
160
161  EXPECT_EQ(1, tester->GetNewNotificationCount());
162  EXPECT_EQ(1, tester->GetNotificationCount());
163  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
164
165  collection->RemoveById("2");
166  ui_test_utils::RunAllPendingInMessageLoop();
167  EXPECT_EQ(0, tester->GetNewNotificationCount());
168  EXPECT_EQ(0, tester->GetNotificationCount());
169  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
170
171  // CLOSE is asynchronous. Run the all pending tasks to finish closing
172  // task.
173  ui_test_utils::RunAllPendingInMessageLoop();
174}
175
176// [CLOSED] -add->[STICKY_AND_NEW] -mouse-> [KEEP_SIZE] -remove/add->
177// [KEEP_SIZE] -remove-> [CLOSED] -add-> [STICKY_AND_NEW] -remove-> [CLOSED]
178IN_PROC_BROWSER_TEST_F(NotificationTest, TestKeepSizeState) {
179  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
180  NotificationPanel* panel = GetNotificationPanel();
181  NotificationPanelTester* tester = panel->GetTester();
182
183  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
184
185  // Using system notification as regular notification.
186  collection->Add(NewMockNotification("1"), browser()->profile());
187  collection->Add(NewMockNotification("2"), browser()->profile());
188
189  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
190
191  panel->OnMouseMotion(gfx::Point(10, 10));
192  EXPECT_EQ(NotificationPanel::KEEP_SIZE, tester->state());
193
194  collection->RemoveById("1");
195  ui_test_utils::RunAllPendingInMessageLoop();
196  EXPECT_EQ(1, tester->GetNewNotificationCount());
197  EXPECT_EQ(1, tester->GetNotificationCount());
198  EXPECT_EQ(NotificationPanel::KEEP_SIZE, tester->state());
199
200  collection->Add(NewMockNotification("1"), browser()->profile());
201  ui_test_utils::RunAllPendingInMessageLoop();
202  EXPECT_EQ(2, tester->GetNewNotificationCount());
203  EXPECT_EQ(2, tester->GetNotificationCount());
204  EXPECT_EQ(NotificationPanel::KEEP_SIZE, tester->state());
205
206  collection->RemoveById("1");
207  ui_test_utils::RunAllPendingInMessageLoop();
208  EXPECT_EQ(1, tester->GetNewNotificationCount());
209  EXPECT_EQ(1, tester->GetNotificationCount());
210  EXPECT_EQ(NotificationPanel::KEEP_SIZE, tester->state());
211
212  collection->RemoveById("2");
213  ui_test_utils::RunAllPendingInMessageLoop();
214  EXPECT_EQ(0, tester->GetNotificationCount());
215  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
216
217  collection->Add(NewMockNotification("3"), browser()->profile());
218  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
219  collection->RemoveById("3");
220
221  ui_test_utils::RunAllPendingInMessageLoop();
222  EXPECT_EQ(0, tester->GetNotificationCount());
223  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
224}
225
226IN_PROC_BROWSER_TEST_F(NotificationTest, TestSystemNotification) {
227  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
228  NotificationPanel* panel = GetNotificationPanel();
229  scoped_refptr<MockNotificationDelegate> delegate(
230      new MockNotificationDelegate("power"));
231  NotificationPanelTester* tester = panel->GetTester();
232
233  Notification notify = NewMockNotification(delegate.get());
234  collection->AddSystemNotification(notify, browser()->profile(), true, false);
235
236  EXPECT_EQ(1, tester->GetNewNotificationCount());
237  EXPECT_EQ(1, tester->GetStickyNotificationCount());
238
239  Notification update = SystemNotificationFactory::Create(
240      GURL(), ASCIIToUTF16("Title"), ASCIIToUTF16("updated"), delegate.get());
241  collection->UpdateNotification(update);
242
243  EXPECT_EQ(1, tester->GetStickyNotificationCount());
244
245  Notification update_and_show = SystemNotificationFactory::Create(
246      GURL(), ASCIIToUTF16("Title"), ASCIIToUTF16("updated and shown"),
247      delegate.get());
248  collection->UpdateAndShowNotification(update_and_show);
249
250  EXPECT_EQ(1, tester->GetStickyNotificationCount());
251
252  // Dismiss the notification.
253  collection->RemoveById(delegate->id());
254  ui_test_utils::RunAllPendingInMessageLoop();
255
256  EXPECT_EQ(0, tester->GetStickyNotificationCount());
257  EXPECT_EQ(0, tester->GetNewNotificationCount());
258  // TODO(oshima): check content, etc..
259}
260
261// [CLOSED] -add,add->[STICKY_AND_NEW] -stale-> [MINIMIZED] -remove->
262// [MINIMIZED] -remove-> [CLOSED]
263IN_PROC_BROWSER_TEST_F(NotificationTest, TestStateTransition1) {
264  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
265  NotificationPanel* panel = GetNotificationPanel();
266  NotificationPanelTester* tester = panel->GetTester();
267
268  tester->SetStaleTimeout(0);
269  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
270
271  collection->Add(NewMockNotification("1"), browser()->profile());
272  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
273
274  collection->Add(NewMockNotification("2"), browser()->profile());
275  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
276
277  ui_test_utils::RunAllPendingInMessageLoop();
278  EXPECT_EQ(NotificationPanel::MINIMIZED, tester->state());
279
280  collection->RemoveById("2");
281  ui_test_utils::RunAllPendingInMessageLoop();
282  EXPECT_EQ(NotificationPanel::MINIMIZED, tester->state());
283
284  collection->RemoveById("1");
285  ui_test_utils::RunAllPendingInMessageLoop();
286  EXPECT_EQ(0, tester->GetNotificationCount());
287  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
288
289  ui_test_utils::RunAllPendingInMessageLoop();
290}
291
292// [CLOSED] -add->[STICKY_AND_NEW] -stale-> [MINIMIZED] -add->
293// [STICKY_AND_NEW] -stale-> [MINIMIZED] -add sys-> [STICKY_NEW]
294// -stale-> [STICKY_NEW] -remove-> [STICKY_NEW] -remove sys->
295// [MINIMIZED] -remove-> [CLOSED]
296//
297// This test depends on the fact that the panel state change occurs
298// quicker than stale timeout, thus the stale timeout cannot be set to
299// 0. This test explicitly controls the stale state instead.
300IN_PROC_BROWSER_TEST_F(NotificationTest, TestStateTransition2) {
301  // Register observer here as the registration does not work in SetUp().
302  NotificationRegistrar registrar;
303  registrar.Add(this,
304                NotificationType::PANEL_STATE_CHANGED,
305                NotificationService::AllSources());
306
307  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
308  NotificationPanel* panel = GetNotificationPanel();
309  NotificationPanelTester* tester = panel->GetTester();
310
311  // See description above.
312  tester->SetStaleTimeout(100000);
313
314  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
315
316  collection->Add(NewMockNotification("1"), browser()->profile());
317  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
318  ui_test_utils::RunAllPendingInMessageLoop();
319
320  // Make the notification stale and make sure panel is minimized state.
321  MarkStale("1");
322  ui_test_utils::RunAllPendingInMessageLoop();
323  EXPECT_EQ(NotificationPanel::MINIMIZED, tester->state());
324  WaitForPanelState(tester, PanelController::MINIMIZED);
325
326  // Adding new notification expands the panel.
327  collection->Add(NewMockNotification("2"), browser()->profile());
328  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
329  WaitForPanelState(tester, PanelController::EXPANDED);
330
331  // The panel must be minimzied when the new notification becomes stale.
332  MarkStale("2");
333  ui_test_utils::RunAllPendingInMessageLoop();
334  EXPECT_EQ(NotificationPanel::MINIMIZED, tester->state());
335  WaitForPanelState(tester, PanelController::MINIMIZED);
336
337  // The panel must be expanded again when a new system notification is added.
338  collection->AddSystemNotification(
339      NewMockNotification("3"), browser()->profile(), true, false);
340  EXPECT_EQ(3, tester->GetNotificationCount());
341  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
342  WaitForPanelState(tester, PanelController::EXPANDED);
343
344  // Running all events nor removing non sticky should not change the state.
345  ui_test_utils::RunAllPendingInMessageLoop();
346  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
347
348  collection->RemoveById("1");
349  ui_test_utils::RunAllPendingInMessageLoop();
350  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
351
352  // Removing the system notification should minimize the panel.
353  collection->RemoveById("3");
354  ui_test_utils::RunAllPendingInMessageLoop();
355  EXPECT_EQ(1, tester->GetNotificationCount());
356  EXPECT_EQ(NotificationPanel::MINIMIZED, tester->state());
357  WaitForPanelState(tester, PanelController::MINIMIZED);
358
359  // Removing the last notification. Should close the panel.
360  collection->RemoveById("2");
361  ui_test_utils::RunAllPendingInMessageLoop();
362  EXPECT_EQ(0, tester->GetNotificationCount());
363  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
364
365  ui_test_utils::RunAllPendingInMessageLoop();
366}
367
368IN_PROC_BROWSER_TEST_F(NotificationTest, TestCleanupOnExit) {
369  NotificationRegistrar registrar;
370  registrar.Add(this,
371                NotificationType::PANEL_STATE_CHANGED,
372                NotificationService::AllSources());
373
374  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
375  NotificationPanel* panel = GetNotificationPanel();
376  NotificationPanelTester* tester = panel->GetTester();
377
378  // Don't become stale.
379  tester->SetStaleTimeout(100000);
380
381  collection->Add(NewMockNotification("1"), browser()->profile());
382  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
383  WaitForPanelState(tester, PanelController::EXPANDED);
384  // end without closing.
385}
386
387IN_PROC_BROWSER_TEST_F(NotificationTest, TestCloseOpen) {
388  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
389  NotificationPanel* panel = GetNotificationPanel();
390  NotificationPanelTester* tester = panel->GetTester();
391  Profile* profile = browser()->profile();
392
393  collection->Add(NewMockNotification("1"), profile);
394  collection->Add(NewMockNotification("2"), profile);
395  ui_test_utils::RunAllPendingInMessageLoop();
396  WaitForPanelState(tester, PanelController::EXPANDED);
397  PanelController* controller = tester->GetPanelController();
398  // close now
399  panel->ClosePanel();
400  controller->Close();
401  ui_test_utils::RunAllPendingInMessageLoop();
402  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
403  // open again
404  collection->Add(NewMockNotification("3"), profile);
405  WaitForPanelState(tester, PanelController::EXPANDED);
406  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
407
408  // close again
409  controller = tester->GetPanelController();
410  panel->ClosePanel();
411  controller->Close();
412  ui_test_utils::RunAllPendingInMessageLoop();
413  EXPECT_EQ(NotificationPanel::CLOSED, tester->state());
414}
415
416IN_PROC_BROWSER_TEST_F(NotificationTest, TestScrollBalloonToVisible) {
417  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
418  NotificationPanel* panel = GetNotificationPanel();
419  NotificationPanelTester* tester = panel->GetTester();
420  Profile* profile = browser()->profile();
421
422  // Create notifications enough to overflow the panel size.
423  const int create_count = 15;
424
425  // new notification is always visible
426  for (int i = 0; i < create_count; i++) {
427    {
428      SCOPED_TRACE(base::StringPrintf("new normal %d", i));
429      std::string id = base::StringPrintf("n%d", i);
430      collection->Add(NewMockNotification(id), profile);
431      EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
432      BalloonViewImpl* view =
433          tester->GetBalloonView(collection, NewMockNotification(id));
434      WaitForVisible(view);
435    }
436    {
437      SCOPED_TRACE(base::StringPrintf("new system %d", i));
438      std::string id = base::StringPrintf("s%d", i);
439      collection->AddSystemNotification(
440          NewMockNotification(id), browser()->profile(), true, false);
441      BalloonViewImpl* view =
442          tester->GetBalloonView(collection, NewMockNotification(id));
443      WaitForVisible(view);
444    }
445  }
446
447  // Update should not change the visibility
448  for (int i = 0; i < create_count; i++) {
449    {
450      SCOPED_TRACE(base::StringPrintf("update n%d", i));
451      Notification notify = NewMockNotification(base::StringPrintf("n%d", i));
452      // The last shown notification is sticky, which makes all non sticky
453      // invisible.
454      EXPECT_TRUE(collection->UpdateNotification(notify));
455      ui_test_utils::RunAllPendingInMessageLoop();
456      BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
457      EXPECT_FALSE(tester->IsVisible(view));
458    }
459    {
460      SCOPED_TRACE(base::StringPrintf("update s%d", i));
461      Notification notify = NewMockNotification(base::StringPrintf("s%d", i));
462      BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
463      bool currently_visible = tester->IsVisible(view);
464      EXPECT_TRUE(collection->UpdateNotification(notify));
465      ui_test_utils::RunAllPendingInMessageLoop();
466      EXPECT_EQ(view, tester->GetBalloonView(collection, notify));
467      EXPECT_EQ(currently_visible, tester->IsVisible(view));
468    }
469  }
470  // UpdateAndShowNotification makes notification visible
471  for (int i = 0; i < create_count; i++) {
472    {
473      SCOPED_TRACE(base::StringPrintf("update and show n%d", i));
474      Notification notify = NewMockNotification(base::StringPrintf("n%d", i));
475      EXPECT_TRUE(collection->UpdateAndShowNotification(notify));
476      ui_test_utils::RunAllPendingInMessageLoop();
477      BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
478      EXPECT_TRUE(tester->IsVisible(view));
479    }
480    {
481      SCOPED_TRACE(base::StringPrintf("update and show s%d", i));
482      Notification notify = NewMockNotification(base::StringPrintf("s%d", i));
483      EXPECT_TRUE(collection->UpdateAndShowNotification(notify));
484      ui_test_utils::RunAllPendingInMessageLoop();
485      BalloonViewImpl* view = tester->GetBalloonView(collection, notify);
486      EXPECT_TRUE(tester->IsVisible(view));
487    }
488  }
489}
490
491IN_PROC_BROWSER_TEST_F(NotificationTest, TestActivateDeactivate) {
492  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
493  NotificationPanel* panel = GetNotificationPanel();
494  NotificationPanelTester* tester = panel->GetTester();
495  Profile* profile = browser()->profile();
496
497  collection->Add(NewMockNotification("1"), profile);
498  collection->AddSystemNotification(
499      NewMockNotification("2"), profile, true, false);
500  ui_test_utils::RunAllPendingInMessageLoop();
501  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
502  BalloonViewImpl* view1 =
503      tester->GetBalloonView(collection, NewMockNotification("1"));
504  BalloonViewImpl* view2 =
505      tester->GetBalloonView(collection, NewMockNotification("2"));
506  // Wait until all renderers get size.
507  WaitForResize(view1);
508  WaitForResize(view2);
509  EXPECT_LT(view2->size().height(), 50) << "view size is bigger than expected";
510
511  panel->OnMouseMotion(gfx::Point(10, 50));
512  EXPECT_TRUE(tester->IsActive(view1));
513  EXPECT_FALSE(tester->IsActive(view2));
514
515  panel->OnMouseMotion(gfx::Point(10, 10));
516  EXPECT_FALSE(tester->IsActive(view1));
517  EXPECT_TRUE(tester->IsActive(view2));
518
519  panel->OnMouseMotion(gfx::Point(500, 500));
520  EXPECT_FALSE(tester->IsActive(view1));
521  EXPECT_FALSE(tester->IsActive(view2));
522}
523
524IN_PROC_BROWSER_TEST_F(NotificationTest, TestCloseDismissAllNonSticky) {
525  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
526  NotificationPanel* panel = GetNotificationPanel();
527  NotificationPanelTester* tester = panel->GetTester();
528  Profile* profile = browser()->profile();
529
530  collection->Add(NewMockNotification("1"), profile);
531  collection->AddSystemNotification(
532      NewMockNotification("2"), profile, true, false);
533  collection->Add(NewMockNotification("3"), profile);
534
535  ui_test_utils::RunAllPendingInMessageLoop();
536  EXPECT_EQ(NotificationPanel::STICKY_AND_NEW, tester->state());
537  EXPECT_EQ(3, tester->GetNotificationCount());
538  EXPECT_EQ(1, tester->GetStickyNotificationCount());
539
540  // Hide
541  panel->Hide();
542  ui_test_utils::RunAllPendingInMessageLoop();
543  EXPECT_EQ(1, tester->GetNotificationCount());
544  EXPECT_EQ(1, tester->GetStickyNotificationCount());
545}
546
547IN_PROC_BROWSER_TEST_F(NotificationTest, TestAddWebUIMessageCallback) {
548  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
549  Profile* profile = browser()->profile();
550
551  collection->AddSystemNotification(
552      NewMockNotification("1"), profile, false, false);
553
554  EXPECT_TRUE(collection->AddWebUIMessageCallback(
555      NewMockNotification("1"),
556      "test",
557      NewCallback(
558          static_cast<NotificationTest*>(this),
559          &NotificationTest::HandleWebUIMessage)));
560
561  // Adding callback for the same message twice should fail.
562  EXPECT_FALSE(collection->AddWebUIMessageCallback(
563      NewMockNotification("1"),
564      "test",
565      NewCallback(
566          static_cast<NotificationTest*>(this),
567          &NotificationTest::HandleWebUIMessage)));
568
569  // Adding callback to nonexistent notification should fail.
570  EXPECT_FALSE(collection->AddWebUIMessageCallback(
571      NewMockNotification("2"),
572      "test1",
573      NewCallback(
574          static_cast<NotificationTest*>(this),
575          &NotificationTest::HandleWebUIMessage)));
576}
577
578IN_PROC_BROWSER_TEST_F(NotificationTest, TestWebUIMessageCallback) {
579  BalloonCollectionImpl* collection = GetBalloonCollectionImpl();
580  Profile* profile = browser()->profile();
581  // A notification that sends 'test' WebUI message back to chrome.
582  const GURL content_url(
583      "data:text/html;charset=utf-8,"
584      "<html><script>function send() { chrome.send('test', ['']); }</script>"
585      "<body onload='send()'></body></html>");
586  collection->AddSystemNotification(
587      Notification(GURL(), content_url, string16(), string16(),
588                   new MockNotificationDelegate("1")),
589      profile,
590      false,
591      false);
592  EXPECT_TRUE(collection->AddWebUIMessageCallback(
593      NewMockNotification("1"),
594      "test",
595      NewCallback(
596          static_cast<NotificationTest*>(this),
597          &NotificationTest::HandleWebUIMessage)));
598  MessageLoop::current()->Run();
599}
600
601}  // namespace chromeos
602