• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/chromeos/notifications/desktop_notifications_unittest.h"
6 
7 #include "base/stringprintf.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/prefs/browser_prefs.h"
10 #include "chrome/browser/prefs/pref_service.h"
11 #include "content/common/desktop_notification_messages.h"
12 
13 namespace chromeos {
14 
15 // static
16 std::string DesktopNotificationsTest::log_output_;
17 
18 class MockNotificationUI : public BalloonCollectionImpl::NotificationUI {
19  public:
Add(Balloon * balloon)20   virtual void Add(Balloon* balloon) {}
Update(Balloon * balloon)21   virtual bool Update(Balloon* balloon) { return false; }
Remove(Balloon * balloon)22   virtual void Remove(Balloon* balloon) {}
Show(Balloon * balloon)23   virtual void Show(Balloon* balloon) {}
ResizeNotification(Balloon * balloon,const gfx::Size & size)24   virtual void ResizeNotification(Balloon* balloon,
25                                   const gfx::Size& size) {}
SetActiveView(BalloonViewImpl * view)26   virtual void SetActiveView(BalloonViewImpl* view) {}
27 };
28 
MockBalloonCollection()29 MockBalloonCollection::MockBalloonCollection() {
30   set_notification_ui(new MockNotificationUI());
31 }
32 
Add(const Notification & notification,Profile * profile)33 void MockBalloonCollection::Add(const Notification& notification,
34                                 Profile* profile) {
35   // Swap in a logging proxy for the purpose of logging calls that
36   // would be made into javascript, then pass this down to the
37   // balloon collection.
38   Notification test_notification(
39       notification.origin_url(),
40       notification.content_url(),
41       notification.display_source(),
42       notification.replace_id(),
43       new LoggingNotificationProxy(notification.notification_id()));
44   BalloonCollectionImpl::Add(test_notification, profile);
45 }
46 
MakeBalloon(const Notification & notification,Profile * profile)47 Balloon* MockBalloonCollection::MakeBalloon(const Notification& notification,
48                                             Profile* profile) {
49   // Start with a normal balloon but mock out the view.
50   Balloon* balloon = BalloonCollectionImpl::MakeBalloon(notification, profile);
51   balloon->set_view(new MockBalloonView(balloon));
52   balloons_.insert(balloon);
53   return balloon;
54 }
55 
OnBalloonClosed(Balloon * source)56 void MockBalloonCollection::OnBalloonClosed(Balloon* source) {
57   balloons_.erase(source);
58   BalloonCollectionImpl::OnBalloonClosed(source);
59 }
60 
UppermostVerticalPosition()61 int MockBalloonCollection::UppermostVerticalPosition() {
62   int min = 0;
63   std::set<Balloon*>::iterator iter;
64   for (iter = balloons_.begin(); iter != balloons_.end(); ++iter) {
65     int pos = (*iter)->GetPosition().y();
66     if (iter == balloons_.begin() || pos < min)
67       min = pos;
68   }
69   return min;
70 }
71 
DesktopNotificationsTest()72 DesktopNotificationsTest::DesktopNotificationsTest()
73     : ui_thread_(BrowserThread::UI, &message_loop_) {
74 }
75 
~DesktopNotificationsTest()76 DesktopNotificationsTest::~DesktopNotificationsTest() {
77 }
78 
SetUp()79 void DesktopNotificationsTest::SetUp() {
80   browser::RegisterLocalState(&local_state_);
81   profile_.reset(new TestingProfile());
82   balloon_collection_ = new MockBalloonCollection();
83   ui_manager_.reset(new NotificationUIManager(&local_state_));
84   ui_manager_->Initialize(balloon_collection_);
85   balloon_collection_->set_space_change_listener(ui_manager_.get());
86   service_.reset(new DesktopNotificationService(profile(), ui_manager_.get()));
87   log_output_.clear();
88 }
89 
TearDown()90 void DesktopNotificationsTest::TearDown() {
91   service_.reset(NULL);
92   ui_manager_.reset(NULL);
93   profile_.reset(NULL);
94 }
95 
96 DesktopNotificationHostMsg_Show_Params
StandardTestNotification()97 DesktopNotificationsTest::StandardTestNotification() {
98   DesktopNotificationHostMsg_Show_Params params;
99   params.notification_id = 0;
100   params.origin = GURL("http://www.google.com");
101   params.is_html = false;
102   params.icon_url = GURL("/icon.png");
103   params.title = ASCIIToUTF16("Title");
104   params.body = ASCIIToUTF16("Text");
105   params.direction = WebKit::WebTextDirectionDefault;
106   return params;
107 }
108 
TEST_F(DesktopNotificationsTest,TestShow)109 TEST_F(DesktopNotificationsTest, TestShow) {
110   DesktopNotificationHostMsg_Show_Params params = StandardTestNotification();
111   params.notification_id = 1;
112   EXPECT_TRUE(service_->ShowDesktopNotification(
113       params, 0, 0, DesktopNotificationService::PageNotification));
114 
115   MessageLoopForUI::current()->RunAllPending();
116   EXPECT_EQ(1, balloon_collection_->count());
117 
118   DesktopNotificationHostMsg_Show_Params params2;
119   params2.origin = GURL("http://www.google.com");
120   params2.is_html = true;
121   params2.contents_url = GURL("http://www.google.com/notification.html");
122   params2.notification_id = 2;
123 
124   EXPECT_TRUE(service_->ShowDesktopNotification(
125       params2, 0, 0, DesktopNotificationService::PageNotification));
126   MessageLoopForUI::current()->RunAllPending();
127   EXPECT_EQ(2, balloon_collection_->count());
128 
129   EXPECT_EQ("notification displayed\n"
130             "notification displayed\n",
131             log_output_);
132 }
133 
TEST_F(DesktopNotificationsTest,TestClose)134 TEST_F(DesktopNotificationsTest, TestClose) {
135   DesktopNotificationHostMsg_Show_Params params = StandardTestNotification();
136   params.notification_id = 1;
137 
138   // Request a notification; should open a balloon.
139   EXPECT_TRUE(service_->ShowDesktopNotification(
140       params, 0, 0, DesktopNotificationService::PageNotification));
141   MessageLoopForUI::current()->RunAllPending();
142   EXPECT_EQ(1, balloon_collection_->count());
143 
144   // Close all the open balloons.
145   std::set<Balloon*> balloons = balloon_collection_->balloons();
146   std::set<Balloon*>::iterator iter;
147   for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
148     (*iter)->OnClose(true);
149   }
150 
151   // Verify that the balloon collection is now empty.
152   EXPECT_EQ(0, balloon_collection_->count());
153 
154   EXPECT_EQ("notification displayed\n"
155             "notification closed by user\n",
156             log_output_);
157 }
158 
TEST_F(DesktopNotificationsTest,TestCancel)159 TEST_F(DesktopNotificationsTest, TestCancel) {
160   int process_id = 0;
161   int route_id = 0;
162   int notification_id = 1;
163 
164   DesktopNotificationHostMsg_Show_Params params = StandardTestNotification();
165   params.notification_id = notification_id;
166 
167   // Request a notification; should open a balloon.
168   EXPECT_TRUE(service_->ShowDesktopNotification(
169       params, process_id, route_id,
170       DesktopNotificationService::PageNotification));
171   MessageLoopForUI::current()->RunAllPending();
172   EXPECT_EQ(1, balloon_collection_->count());
173 
174   // Cancel the same notification
175   service_->CancelDesktopNotification(process_id,
176                                       route_id,
177                                       notification_id);
178   MessageLoopForUI::current()->RunAllPending();
179   // Verify that the balloon collection is now empty.
180   EXPECT_EQ(0, balloon_collection_->count());
181 
182   EXPECT_EQ("notification displayed\n"
183             "notification closed by script\n",
184             log_output_);
185 }
186 
TEST_F(DesktopNotificationsTest,TestManyNotifications)187 TEST_F(DesktopNotificationsTest, TestManyNotifications) {
188   int process_id = 0;
189   int route_id = 0;
190 
191   // Request lots of identical notifications.
192   const int kLotsOfToasts = 20;
193   for (int id = 1; id <= kLotsOfToasts; ++id) {
194     SCOPED_TRACE(base::StringPrintf("Creation loop: id=%d", id));
195     DesktopNotificationHostMsg_Show_Params params = StandardTestNotification();
196     params.notification_id = id;
197     EXPECT_TRUE(service_->ShowDesktopNotification(
198         params, process_id, route_id,
199         DesktopNotificationService::PageNotification));
200   }
201   MessageLoopForUI::current()->RunAllPending();
202 
203   // Build up an expected log of what should be happening.
204   std::string expected_log;
205   for (int i = 0; i < kLotsOfToasts; ++i) {
206     expected_log.append("notification displayed\n");
207   }
208 
209   EXPECT_EQ(kLotsOfToasts, balloon_collection_->count());
210   EXPECT_EQ(expected_log, log_output_);
211 
212   // Cancel half of the notifications from the start
213   int id;
214   int cancelled = kLotsOfToasts / 2;
215   for (id = 1;
216        id <= cancelled;
217        ++id) {
218     SCOPED_TRACE(base::StringPrintf("Cancel half of notifications: id=%d", id));
219     service_->CancelDesktopNotification(process_id, route_id, id);
220     MessageLoopForUI::current()->RunAllPending();
221     expected_log.append("notification closed by script\n");
222     EXPECT_EQ(kLotsOfToasts - id,
223               balloon_collection_->count());
224     EXPECT_EQ(expected_log, log_output_);
225   }
226 
227   // Now cancel the rest.  It should empty the balloon space.
228   for (; id <= kLotsOfToasts; ++id) {
229     SCOPED_TRACE(base::StringPrintf("Cancel loop: id=%d", id));
230     service_->CancelDesktopNotification(process_id, route_id, id);
231     expected_log.append("notification closed by script\n");
232     MessageLoopForUI::current()->RunAllPending();
233     EXPECT_EQ(expected_log, log_output_);
234   }
235 
236   // Verify that the balloon collection is now empty.
237   EXPECT_EQ(0, balloon_collection_->count());
238 }
239 
TEST_F(DesktopNotificationsTest,TestEarlyDestruction)240 TEST_F(DesktopNotificationsTest, TestEarlyDestruction) {
241   // Create some toasts and then prematurely delete the notification service,
242   // just to make sure nothing crashes/leaks.
243   for (int id = 0; id <= 3; ++id) {
244     SCOPED_TRACE(base::StringPrintf("Show Text loop: id=%d", id));
245 
246     EXPECT_TRUE(service_->ShowDesktopNotification(
247         StandardTestNotification(), 0, 0,
248         DesktopNotificationService::PageNotification));
249   }
250   service_.reset(NULL);
251 }
252 
TEST_F(DesktopNotificationsTest,TestUserInputEscaping)253 TEST_F(DesktopNotificationsTest, TestUserInputEscaping) {
254   // Create a test script with some HTML; assert that it doesn't get into the
255   // data:// URL that's produced for the balloon.
256   DesktopNotificationHostMsg_Show_Params params = StandardTestNotification();
257   params.title = ASCIIToUTF16("<script>window.alert('uh oh');</script>");
258   params.body = ASCIIToUTF16("<i>this text is in italics</i>");
259   params.notification_id = 1;
260   EXPECT_TRUE(service_->ShowDesktopNotification(
261       params, 0, 0, DesktopNotificationService::PageNotification));
262 
263   MessageLoopForUI::current()->RunAllPending();
264   EXPECT_EQ(1, balloon_collection_->count());
265   Balloon* balloon = (*balloon_collection_->balloons().begin());
266   GURL data_url = balloon->notification().content_url();
267   EXPECT_EQ(std::string::npos, data_url.spec().find("<script>"));
268   EXPECT_EQ(std::string::npos, data_url.spec().find("<i>"));
269 }
270 
271 }  // namespace chromeos
272