1 // Copyright 2014 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 "chrome/browser/notifications/extension_welcome_notification.h"
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 "base/test/test_simple_task_runner.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "chrome/browser/notifications/notification.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/testing_pref_service_syncable.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "components/user_prefs/pref_registry_syncable.h"
20 #include "sync/api/sync_error_factory_mock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "ui/message_center/fake_message_center.h"
23 #include "ui/message_center/notification.h"
25 const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
27 class MockMessageCenter : public message_center::FakeMessageCenter {
30 : add_notification_calls_(0),
31 remove_notification_calls_(0),
32 notifications_with_shown_as_popup_(0) {
35 int add_notification_calls() { return add_notification_calls_; }
36 int remove_notification_calls() { return remove_notification_calls_; }
37 int notifications_with_shown_as_popup() {
38 return notifications_with_shown_as_popup_;
41 // message_center::FakeMessageCenter Overrides
42 virtual bool HasNotification(const std::string& id) OVERRIDE {
43 return last_notification.get() && (last_notification->id() == id);
46 virtual void AddNotification(
47 scoped_ptr<message_center::Notification> notification) OVERRIDE {
48 EXPECT_FALSE(last_notification.get());
49 last_notification.swap(notification);
50 add_notification_calls_++;
51 if (last_notification->shown_as_popup())
52 notifications_with_shown_as_popup_++;
55 virtual void RemoveNotification(const std::string& id,
56 bool by_user) OVERRIDE {
57 EXPECT_TRUE(last_notification.get());
58 last_notification.reset();
59 remove_notification_calls_++;
62 void CloseCurrentNotification() {
63 EXPECT_TRUE(last_notification.get());
64 last_notification->delegate()->Close(true);
65 RemoveNotification(last_notification->id(), true);
69 scoped_ptr<message_center::Notification> last_notification;
70 int add_notification_calls_;
71 int remove_notification_calls_;
72 int notifications_with_shown_as_popup_;
74 DISALLOW_COPY_AND_ASSIGN(MockMessageCenter);
77 class WelcomeNotificationDelegate
78 : public ExtensionWelcomeNotification::Delegate {
80 WelcomeNotificationDelegate()
81 : start_time_(base::Time::Now()),
82 message_center_(new MockMessageCenter()) {
85 // ExtensionWelcomeNotification::Delegate
86 virtual message_center::MessageCenter* GetMessageCenter() OVERRIDE {
87 return message_center_.get();
90 virtual base::Time GetCurrentTime() OVERRIDE {
91 return start_time_ + elapsed_time_;
94 virtual void PostTask(
95 const tracked_objects::Location& from_here,
96 const base::Closure& task) OVERRIDE {
97 EXPECT_TRUE(pending_task_.is_null());
101 // WelcomeNotificationDelegate
102 MockMessageCenter* message_center() const { return message_center_.get(); }
104 base::Time GetStartTime() const { return start_time_; }
106 void SetElapsedTime(base::TimeDelta elapsed_time) {
107 elapsed_time_ = elapsed_time;
110 void RunPendingTask() {
111 base::Closure task_to_run = pending_task_;
112 pending_task_.Reset();
117 const base::Time start_time_;
118 base::TimeDelta elapsed_time_;
119 scoped_ptr<MockMessageCenter> message_center_;
120 base::Closure pending_task_;
122 DISALLOW_COPY_AND_ASSIGN(WelcomeNotificationDelegate);
125 class TestSyncProcessor : public syncer::SyncChangeProcessor {
127 TestSyncProcessor() {}
129 virtual syncer::SyncError ProcessSyncChanges(
130 const tracked_objects::Location& from_here,
131 const syncer::SyncChangeList& change_list) OVERRIDE {
132 return syncer::SyncError();
135 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
137 return syncer::SyncDataList();
141 DISALLOW_COPY_AND_ASSIGN(TestSyncProcessor);
144 class ExtensionWelcomeNotificationTest : public testing::Test {
146 ExtensionWelcomeNotificationTest() {
147 scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry(
148 new user_prefs::PrefRegistrySyncable());
149 ExtensionWelcomeNotification::RegisterProfilePrefs(pref_registry.get());
152 virtual void SetUp() {
153 task_runner_ = new base::TestSimpleTaskRunner();
154 thread_task_runner_handle_.reset(
155 new base::ThreadTaskRunnerHandle(task_runner_));
156 profile_.reset(new TestingProfile());
157 delegate_ = new WelcomeNotificationDelegate();
158 welcome_notification_ = ExtensionWelcomeNotification::Create(
159 kChromeNowExtensionID, profile_.get(), delegate_);
162 virtual void TearDown() {
164 welcome_notification_.reset();
166 thread_task_runner_handle_.reset();
170 void StartPreferenceSyncing() const {
171 PrefServiceSyncable::FromProfile(profile_.get())
172 ->GetSyncableService(syncer::PREFERENCES)
173 ->MergeDataAndStartSyncing(
175 syncer::SyncDataList(),
176 scoped_ptr<syncer::SyncChangeProcessor>(new TestSyncProcessor),
177 scoped_ptr<syncer::SyncErrorFactory>(
178 new syncer::SyncErrorFactoryMock()));
181 void ShowChromeNowNotification() const {
183 "ChromeNowNotification",
184 message_center::NotifierId(message_center::NotifierId::APPLICATION,
185 kChromeNowExtensionID));
188 void ShowRegularNotification() const {
190 "RegularNotification",
191 message_center::NotifierId(message_center::NotifierId::APPLICATION,
192 "aaaabbbbccccddddeeeeffffggghhhhi"));
195 void FlushMessageLoop() { delegate_->RunPendingTask(); }
197 MockMessageCenter* message_center() const {
198 return delegate_->message_center();
200 base::TestSimpleTaskRunner* task_runner() const {
201 return task_runner_.get();
203 base::Time GetStartTime() const {
204 return delegate_->GetStartTime();
206 void SetElapsedTime(base::TimeDelta elapsed_time) const {
207 delegate_->SetElapsedTime(elapsed_time);
209 bool GetBooleanPref(const char* path) const {
210 return profile_->GetPrefs()->GetBoolean(path);
212 void SetBooleanPref(const char* path, bool value) const {
213 profile_->GetPrefs()->SetBoolean(path, value);
215 int64 GetInt64Pref(const char* path) const {
216 return profile_->GetPrefs()->GetInt64(path);
218 void SetInt64Pref(const char* path, int64 value) const {
219 profile_->GetPrefs()->SetInt64(path, value);
223 class TestNotificationDelegate : public NotificationDelegate {
225 explicit TestNotificationDelegate(const std::string& id) : id_(id) {}
227 // Overridden from NotificationDelegate:
228 virtual void Display() OVERRIDE {}
229 virtual void Error() OVERRIDE {}
230 virtual void Close(bool by_user) OVERRIDE {}
231 virtual void Click() OVERRIDE {}
232 virtual void ButtonClick(int index) OVERRIDE {}
234 virtual std::string id() const OVERRIDE { return id_; }
236 virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
241 virtual ~TestNotificationDelegate() {}
243 const std::string id_;
245 DISALLOW_COPY_AND_ASSIGN(TestNotificationDelegate);
248 void ShowNotification(std::string notification_id,
249 const message_center::NotifierId& notifier_id) const {
250 message_center::RichNotificationData rich_notification_data;
251 rich_notification_data.priority = 0;
252 Notification notification(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
253 GURL("http://tests.url"),
254 base::UTF8ToUTF16("Title"),
255 base::UTF8ToUTF16("Body"),
257 blink::WebTextDirectionDefault,
259 base::UTF8ToUTF16("Source"),
260 base::UTF8ToUTF16(notification_id),
261 rich_notification_data,
262 new TestNotificationDelegate("TestNotification"));
263 welcome_notification_->ShowWelcomeNotificationIfNecessary(notification);
266 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
267 scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
268 scoped_ptr<TestingProfile> profile_;
269 // Weak Ref owned by welcome_notification_
270 WelcomeNotificationDelegate* delegate_;
271 scoped_ptr<ExtensionWelcomeNotification> welcome_notification_;
273 DISALLOW_COPY_AND_ASSIGN(ExtensionWelcomeNotificationTest);
276 // Show a regular notification. Expect that WelcomeNotification will
277 // not show a welcome notification.
278 TEST_F(ExtensionWelcomeNotificationTest, FirstRunShowRegularNotification) {
279 StartPreferenceSyncing();
280 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
281 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
283 ShowRegularNotification();
285 EXPECT_EQ(message_center()->add_notification_calls(), 0);
286 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
287 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
288 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
289 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
292 // Show a Chrome Now notification. Expect that WelcomeNotification will
293 // show a welcome notification.
294 TEST_F(ExtensionWelcomeNotificationTest, FirstRunChromeNowNotification) {
295 StartPreferenceSyncing();
296 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
297 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
299 ShowChromeNowNotification();
301 EXPECT_EQ(message_center()->add_notification_calls(), 1);
302 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
303 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
304 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
305 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
308 // Show a Chrome Now notification that was already shown before.
309 TEST_F(ExtensionWelcomeNotificationTest, ShowWelcomeNotificationAgain) {
310 StartPreferenceSyncing();
311 SetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
312 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
313 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
315 ShowChromeNowNotification();
317 EXPECT_EQ(message_center()->add_notification_calls(), 1);
318 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
319 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 1);
320 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
321 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
324 // Don't show a welcome notification if it was previously dismissed
325 TEST_F(ExtensionWelcomeNotificationTest,
326 WelcomeNotificationPreviouslyDismissed) {
327 StartPreferenceSyncing();
328 SetBooleanPref(prefs::kWelcomeNotificationDismissed, true);
329 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
330 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
332 ShowChromeNowNotification();
334 EXPECT_EQ(message_center()->add_notification_calls(), 0);
335 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
336 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
337 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
338 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
341 // Show a Chrome Now notification and dismiss it.
342 // Expect welcome toast dismissed to be true.
343 TEST_F(ExtensionWelcomeNotificationTest, DismissWelcomeNotification) {
344 StartPreferenceSyncing();
345 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
346 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
348 ShowChromeNowNotification();
349 message_center()->CloseCurrentNotification();
352 EXPECT_EQ(message_center()->add_notification_calls(), 1);
353 EXPECT_EQ(message_center()->remove_notification_calls(), 1);
354 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
355 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
356 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
359 // Show a Chrome Now notification and dismiss it via a synced preference change.
360 // Expect welcome toast dismissed to be true.
361 TEST_F(ExtensionWelcomeNotificationTest, SyncedDismissalWelcomeNotification) {
362 StartPreferenceSyncing();
363 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
364 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
366 ShowChromeNowNotification();
367 SetBooleanPref(prefs::kWelcomeNotificationDismissed, true);
369 EXPECT_EQ(message_center()->add_notification_calls(), 1);
370 EXPECT_EQ(message_center()->remove_notification_calls(), 1);
371 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
372 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
373 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
376 // Simulate a delayed preference sync when the welcome notification was
377 // previously dismissed.
378 TEST_F(ExtensionWelcomeNotificationTest,
379 DelayedPreferenceSyncPreviouslyDismissed) {
380 // Show a notification while the preference system is not syncing.
381 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
382 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
384 ShowChromeNowNotification();
386 EXPECT_EQ(message_center()->add_notification_calls(), 0);
387 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
388 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
389 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
390 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
392 // Now start the preference syncing with a previously dismissed welcome.
393 SetBooleanPref(prefs::kWelcomeNotificationDismissed, true);
394 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
395 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
397 StartPreferenceSyncing();
399 EXPECT_EQ(message_center()->add_notification_calls(), 0);
400 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
401 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
402 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
403 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
406 // Simulate a delayed preference sync when the welcome notification was
408 TEST_F(ExtensionWelcomeNotificationTest, DelayedPreferenceSyncNeverShown) {
409 // Show a notification while the preference system is not syncing.
410 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
411 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
413 ShowChromeNowNotification();
415 EXPECT_EQ(message_center()->add_notification_calls(), 0);
416 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
417 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
418 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
419 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
421 // Now start the preference syncing with the default preference values.
422 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
423 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
425 StartPreferenceSyncing();
427 EXPECT_EQ(message_center()->add_notification_calls(), 1);
428 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
429 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
430 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
431 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
434 // Simulate the passage of time when the welcome notification
435 // automatically dismisses.
436 TEST_F(ExtensionWelcomeNotificationTest, TimeExpiredNotification) {
437 StartPreferenceSyncing();
438 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
439 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
440 EXPECT_EQ(GetInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp), 0);
441 EXPECT_TRUE(task_runner()->GetPendingTasks().empty());
443 ShowChromeNowNotification();
445 base::TimeDelta requested_show_time =
446 base::TimeDelta::FromDays(
447 ExtensionWelcomeNotification::kRequestedShowTimeDays);
449 EXPECT_EQ(task_runner()->GetPendingTasks().size(), 1U);
450 EXPECT_EQ(task_runner()->NextPendingTaskDelay(), requested_show_time);
452 EXPECT_EQ(message_center()->add_notification_calls(), 1);
453 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
454 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
455 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
456 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
458 GetInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp),
459 (GetStartTime() + requested_show_time).ToInternalValue());
461 SetElapsedTime(requested_show_time);
462 task_runner()->RunPendingTasks();
464 EXPECT_TRUE(task_runner()->GetPendingTasks().empty());
465 EXPECT_EQ(message_center()->add_notification_calls(), 1);
466 EXPECT_EQ(message_center()->remove_notification_calls(), 1);
467 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
468 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
469 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
471 GetInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp),
472 (GetStartTime() + requested_show_time).ToInternalValue());
475 // Simulate the passage of time after Chrome is closed and the welcome
476 // notification expiration elapses.
477 TEST_F(ExtensionWelcomeNotificationTest, NotificationPreviouslyExpired) {
478 StartPreferenceSyncing();
479 SetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
480 SetInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp, 1);
481 EXPECT_FALSE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
482 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
483 EXPECT_EQ(GetInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp), 1);
484 EXPECT_TRUE(task_runner()->GetPendingTasks().empty());
486 const base::TimeDelta requested_show_time =
487 base::TimeDelta::FromDays(
488 ExtensionWelcomeNotification::kRequestedShowTimeDays);
489 SetElapsedTime(requested_show_time);
490 ShowChromeNowNotification();
492 EXPECT_TRUE(task_runner()->GetPendingTasks().empty());
493 EXPECT_EQ(message_center()->add_notification_calls(), 0);
494 EXPECT_EQ(message_center()->remove_notification_calls(), 0);
495 EXPECT_EQ(message_center()->notifications_with_shown_as_popup(), 0);
496 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationDismissed));
497 EXPECT_TRUE(GetBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp));
498 EXPECT_EQ(GetInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp), 1);
501 // C++ Readability Review Change Trigger