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