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. 4 5 #include "chrome/browser/notifications/welcome_notification.h" 6 7 #include <string> 8 9 #include "base/memory/scoped_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "chrome/browser/notifications/notification.h" 14 #include "chrome/common/pref_names.h" 15 #include "chrome/test/base/testing_pref_service_syncable.h" 16 #include "chrome/test/base/testing_profile.h" 17 #include "components/user_prefs/pref_registry_syncable.h" 18 #include "sync/api/sync_error_factory_mock.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "ui/message_center/fake_message_center.h" 21 #include "ui/message_center/notification.h" 22 23 const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh"; 24 25 class MockMessageCenter : public message_center::FakeMessageCenter { 26 public: 27 MockMessageCenter() 28 : add_notification_calls_(0), 29 remove_notification_calls_(0), 30 notifications_with_shown_as_popup_(0) {}; 31 32 int add_notification_calls() { return add_notification_calls_; } 33 int remove_notification_calls() { return remove_notification_calls_; } 34 int notifications_with_shown_as_popup() { 35 return notifications_with_shown_as_popup_; 36 } 37 38 // message_center::FakeMessageCenter Overrides 39 virtual bool HasNotification(const std::string& id) OVERRIDE { 40 return last_notification.get() && 41 (last_notification->id() == id); 42 } 43 44 virtual void AddNotification( 45 scoped_ptr<message_center::Notification> notification) OVERRIDE { 46 EXPECT_FALSE(last_notification.get()); 47 last_notification.swap(notification); 48 add_notification_calls_++; 49 if (last_notification->shown_as_popup()) 50 notifications_with_shown_as_popup_++; 51 } 52 53 virtual void RemoveNotification(const std::string& id, bool by_user) 54 OVERRIDE { 55 EXPECT_TRUE(last_notification.get()); 56 last_notification.reset(); 57 remove_notification_calls_++; 58 } 59 60 void CloseCurrentNotification() { 61 EXPECT_TRUE(last_notification.get()); 62 last_notification->delegate()->Close(true); 63 RemoveNotification(last_notification->id(), true); 64 } 65 66 private: 67 scoped_ptr<message_center::Notification> last_notification; 68 int add_notification_calls_; 69 int remove_notification_calls_; 70 int notifications_with_shown_as_popup_; 71 }; 72 73 class TestSyncProcessor : public syncer::SyncChangeProcessor { 74 virtual syncer::SyncError ProcessSyncChanges( 75 const tracked_objects::Location& from_here, 76 const syncer::SyncChangeList& change_list) OVERRIDE { 77 return syncer::SyncError(); 78 } 79 80 virtual syncer::SyncDataList GetAllSyncData( 81 syncer::ModelType type) const OVERRIDE { 82 return syncer::SyncDataList(); 83 } 84 }; 85 86 class WelcomeNotificationTest : public testing::Test { 87 protected: 88 WelcomeNotificationTest() { 89 scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry( 90 new user_prefs::PrefRegistrySyncable()); 91 WelcomeNotification::RegisterProfilePrefs(pref_registry.get()); 92 } 93 94 virtual void SetUp() { 95 message_loop_.reset(new base::MessageLoop()); 96 profile_.reset(new TestingProfile()); 97 message_center_.reset(new MockMessageCenter()); 98 welcome_notification_.reset( 99 new WelcomeNotification(profile_.get(), message_center_.get())); 100 } 101 102 virtual void TearDown() { 103 welcome_notification_.reset(); 104 message_center_.reset(); 105 profile_.reset(); 106 message_loop_.reset(); 107 } 108 109 void StartPreferenceSyncing() { 110 PrefServiceSyncable::FromProfile(profile())->GetSyncableService( 111 syncer::PREFERENCES)->MergeDataAndStartSyncing( 112 syncer::PREFERENCES, 113 syncer::SyncDataList(), 114 scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessor), 115 scoped_ptr<syncer::SyncErrorFactory>( 116 new syncer::SyncErrorFactoryMock())); 117 } 118 119 void ShowChromeNowNotification() { 120 ShowNotification( 121 "ChromeNowNotification", 122 message_center::NotifierId( 123 message_center::NotifierId::APPLICATION, 124 kChromeNowExtensionID)); 125 } 126 127 void ShowRegularNotification() { 128 ShowNotification( 129 "RegularNotification", 130 message_center::NotifierId( 131 message_center::NotifierId::APPLICATION, 132 "aaaabbbbccccddddeeeeffffggghhhhi")); 133 } 134 135 void FlushMessageLoop() { 136 message_loop_->RunUntilIdle(); 137 } 138 139 TestingProfile* profile() { return profile_.get(); } 140 MockMessageCenter* message_center() { return message_center_.get(); } 141 142 private: 143 class TestNotificationDelegate : public NotificationDelegate { 144 public: 145 explicit TestNotificationDelegate(const std::string& id) 146 : id_(id) {} 147 148 // Overridden from NotificationDelegate: 149 virtual void Display() OVERRIDE {} 150 virtual void Error() OVERRIDE {} 151 virtual void Close(bool by_user) OVERRIDE {} 152 virtual void Click() OVERRIDE {} 153 virtual void ButtonClick(int index) OVERRIDE {} 154 155 virtual std::string id() const OVERRIDE { return id_; } 156 157 virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE { 158 return NULL; 159 } 160 161 private: 162 virtual ~TestNotificationDelegate() {} 163 164 const std::string id_; 165 166 DISALLOW_COPY_AND_ASSIGN(TestNotificationDelegate); 167 }; 168 169 void ShowNotification( 170 std::string notification_id, 171 const message_center::NotifierId& notifier_id) { 172 message_center::RichNotificationData rich_notification_data; 173 rich_notification_data.priority = 0; 174 Notification notification( 175 message_center::NOTIFICATION_TYPE_BASE_FORMAT, 176 GURL("http://tests.url"), 177 base::UTF8ToUTF16("Title"), 178 base::UTF8ToUTF16("Body"), 179 gfx::Image(), 180 blink::WebTextDirectionDefault, 181 notifier_id, 182 base::UTF8ToUTF16("Source"), 183 base::UTF8ToUTF16(notification_id), 184 rich_notification_data, 185 new TestNotificationDelegate("TestNotification")); 186 welcome_notification_->ShowWelcomeNotificationIfNecessary(notification); 187 } 188 189 scoped_ptr<TestingProfile> profile_; 190 scoped_ptr<MockMessageCenter> message_center_; 191 scoped_ptr<WelcomeNotification> welcome_notification_; 192 scoped_ptr<base::MessageLoop> message_loop_; 193 }; 194 195 // Show a regular notification. Expect that WelcomeNotification will 196 // not show a welcome notification. 197 TEST_F(WelcomeNotificationTest, FirstRunShowRegularNotification) { 198 StartPreferenceSyncing(); 199 EXPECT_FALSE( 200 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 201 EXPECT_FALSE( 202 profile()->GetPrefs()->GetBoolean( 203 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 204 205 ShowRegularNotification(); 206 207 EXPECT_TRUE(message_center()->add_notification_calls() == 0); 208 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 209 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 210 EXPECT_FALSE( 211 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 212 EXPECT_FALSE( 213 profile()->GetPrefs()->GetBoolean( 214 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 215 } 216 217 // Show a Chrome Now notification. Expect that WelcomeNotification will 218 // show a welcome notification. 219 TEST_F(WelcomeNotificationTest, FirstRunChromeNowNotification) { 220 StartPreferenceSyncing(); 221 EXPECT_FALSE( 222 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 223 EXPECT_FALSE( 224 profile()->GetPrefs()->GetBoolean( 225 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 226 227 ShowChromeNowNotification(); 228 229 EXPECT_TRUE(message_center()->add_notification_calls() == 1); 230 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 231 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 232 EXPECT_FALSE( 233 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 234 EXPECT_TRUE( 235 profile()->GetPrefs()->GetBoolean( 236 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 237 } 238 239 // Show a Chrome Now notification that was already shown before. 240 TEST_F(WelcomeNotificationTest, ShowWelcomeNotificationAgain) { 241 StartPreferenceSyncing(); 242 profile()->GetPrefs()->SetBoolean( 243 prefs::kWelcomeNotificationPreviouslyPoppedUp, true); 244 EXPECT_FALSE( 245 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 246 EXPECT_TRUE( 247 profile()->GetPrefs()->GetBoolean( 248 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 249 250 ShowChromeNowNotification(); 251 252 EXPECT_TRUE(message_center()->add_notification_calls() == 1); 253 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 254 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 1); 255 EXPECT_FALSE( 256 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 257 EXPECT_TRUE( 258 profile()->GetPrefs()->GetBoolean( 259 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 260 } 261 262 // Don't show a welcome notification if it was previously dismissed 263 TEST_F(WelcomeNotificationTest, WelcomeNotificationPreviouslyDismissed) { 264 StartPreferenceSyncing(); 265 profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true); 266 EXPECT_TRUE( 267 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 268 EXPECT_FALSE( 269 profile()->GetPrefs()->GetBoolean( 270 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 271 272 ShowChromeNowNotification(); 273 274 EXPECT_TRUE(message_center()->add_notification_calls() == 0); 275 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 276 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 277 EXPECT_TRUE( 278 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 279 EXPECT_FALSE( 280 profile()->GetPrefs()->GetBoolean( 281 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 282 } 283 284 // Show a Chrome Now notification and dismiss it. 285 // Expect welcome toast dismissed to be true. 286 TEST_F(WelcomeNotificationTest, DismissWelcomeNotification) { 287 StartPreferenceSyncing(); 288 EXPECT_FALSE( 289 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 290 EXPECT_FALSE( 291 profile()->GetPrefs()->GetBoolean( 292 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 293 294 ShowChromeNowNotification(); 295 message_center()->CloseCurrentNotification(); 296 FlushMessageLoop(); 297 298 EXPECT_TRUE(message_center()->add_notification_calls() == 1); 299 EXPECT_TRUE(message_center()->remove_notification_calls() == 1); 300 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 301 EXPECT_TRUE( 302 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 303 EXPECT_TRUE( 304 profile()->GetPrefs()->GetBoolean( 305 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 306 } 307 308 // Show a Chrome Now notification and dismiss it via a synced preference change. 309 // Expect welcome toast dismissed to be true. 310 TEST_F(WelcomeNotificationTest, SyncedDismissalWelcomeNotification) { 311 StartPreferenceSyncing(); 312 EXPECT_FALSE( 313 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 314 EXPECT_FALSE( 315 profile()->GetPrefs()->GetBoolean( 316 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 317 318 ShowChromeNowNotification(); 319 profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true); 320 321 EXPECT_TRUE(message_center()->add_notification_calls() == 1); 322 EXPECT_TRUE(message_center()->remove_notification_calls() == 1); 323 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 324 EXPECT_TRUE( 325 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 326 EXPECT_TRUE( 327 profile()->GetPrefs()->GetBoolean( 328 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 329 } 330 331 // Simulate a delayed preference sync when the welcome notification was 332 // previously dismissed. 333 TEST_F(WelcomeNotificationTest, DelayedPreferenceSyncPreviouslyDismissed) { 334 // Show a notification while the preference system is not syncing. 335 EXPECT_FALSE( 336 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 337 EXPECT_FALSE( 338 profile()->GetPrefs()->GetBoolean( 339 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 340 341 ShowChromeNowNotification(); 342 343 EXPECT_TRUE(message_center()->add_notification_calls() == 0); 344 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 345 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 346 EXPECT_FALSE( 347 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 348 EXPECT_FALSE( 349 profile()->GetPrefs()->GetBoolean( 350 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 351 352 // Now start the preference syncing with a previously dismissed welcome. 353 profile()->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true); 354 EXPECT_TRUE( 355 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 356 EXPECT_FALSE( 357 profile()->GetPrefs()->GetBoolean( 358 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 359 360 StartPreferenceSyncing(); 361 362 EXPECT_TRUE(message_center()->add_notification_calls() == 0); 363 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 364 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 365 EXPECT_TRUE( 366 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 367 EXPECT_FALSE( 368 profile()->GetPrefs()->GetBoolean( 369 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 370 } 371 372 // Simulate a delayed preference sync when the welcome notification was 373 // never shown. 374 TEST_F(WelcomeNotificationTest, DelayedPreferenceSyncNeverShown) { 375 // Show a notification while the preference system is not syncing. 376 EXPECT_FALSE( 377 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 378 EXPECT_FALSE( 379 profile()->GetPrefs()->GetBoolean( 380 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 381 382 ShowChromeNowNotification(); 383 384 EXPECT_TRUE(message_center()->add_notification_calls() == 0); 385 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 386 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 387 EXPECT_FALSE( 388 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 389 EXPECT_FALSE( 390 profile()->GetPrefs()->GetBoolean( 391 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 392 393 // Now start the preference syncing with the default preference values. 394 EXPECT_FALSE( 395 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 396 EXPECT_FALSE( 397 profile()->GetPrefs()->GetBoolean( 398 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 399 400 StartPreferenceSyncing(); 401 402 EXPECT_TRUE(message_center()->add_notification_calls() == 1); 403 EXPECT_TRUE(message_center()->remove_notification_calls() == 0); 404 EXPECT_TRUE(message_center()->notifications_with_shown_as_popup() == 0); 405 EXPECT_FALSE( 406 profile()->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed)); 407 EXPECT_TRUE( 408 profile()->GetPrefs()->GetBoolean( 409 prefs::kWelcomeNotificationPreviouslyPoppedUp)); 410 } 411