// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/strings/utf_string_conversions.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "chrome/browser/notifications/notification_test_util.h" #include "chrome/browser/notifications/platform_notification_service_impl.h" #include "chrome/test/base/testing_profile.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "content/public/browser/desktop_notification_delegate.h" #include "content/public/common/platform_notification_data.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" namespace { class MockDesktopNotificationDelegate : public content::DesktopNotificationDelegate { public: MockDesktopNotificationDelegate() : displayed_(false), clicked_(false) {} ~MockDesktopNotificationDelegate() override {} // content::DesktopNotificationDelegate implementation. void NotificationDisplayed() override { displayed_ = true; } void NotificationClosed() override {} void NotificationClick() override { clicked_ = true; } bool displayed() const { return displayed_; } bool clicked() const { return clicked_; } private: bool displayed_; bool clicked_; }; } // namespace class PlatformNotificationServiceTest : public testing::Test { public: void SetUp() override { ui_manager_.reset(new StubNotificationUIManager); profile_.reset(new TestingProfile()); service()->SetNotificationUIManagerForTesting(ui_manager_.get()); } void TearDown() override { service()->SetNotificationUIManagerForTesting(nullptr); profile_.reset(); ui_manager_.reset(); } protected: // Displays a simple, fake notifications and returns a weak pointer to the // delegate receiving events for it (ownership is transferred to the service). MockDesktopNotificationDelegate* CreateSimplePageNotification() const { return CreateSimplePageNotificationWithCloseClosure(nullptr); } // Displays a simple, fake notification and returns a weak pointer to the // delegate receiving events for it (ownership is transferred to the service). // The close closure may be specified if so desired. MockDesktopNotificationDelegate* CreateSimplePageNotificationWithCloseClosure( base::Closure* close_closure) const { content::PlatformNotificationData notification_data; notification_data.title = base::ASCIIToUTF16("My Notification"); notification_data.body = base::ASCIIToUTF16("Hello, world!"); MockDesktopNotificationDelegate* delegate = new MockDesktopNotificationDelegate(); service()->DisplayNotification(profile(), GURL("https://chrome.com/"), SkBitmap(), notification_data, make_scoped_ptr(delegate), close_closure); return delegate; } // Returns the Platform Notification Service these unit tests are for. PlatformNotificationServiceImpl* service() const { return PlatformNotificationServiceImpl::GetInstance(); } // Returns the Profile to be used for these tests. Profile* profile() const { return profile_.get(); } // Returns the UI Manager on which notifications will be displayed. StubNotificationUIManager* ui_manager() const { return ui_manager_.get(); } private: scoped_ptr ui_manager_; scoped_ptr profile_; content::TestBrowserThreadBundle thread_bundle_; }; TEST_F(PlatformNotificationServiceTest, DisplayPageDisplayedEvent) { auto* delegate = CreateSimplePageNotification(); EXPECT_EQ(1u, ui_manager()->GetNotificationCount()); EXPECT_TRUE(delegate->displayed()); } TEST_F(PlatformNotificationServiceTest, DisplayPageCloseClosure) { base::Closure close_closure; CreateSimplePageNotificationWithCloseClosure(&close_closure); EXPECT_EQ(1u, ui_manager()->GetNotificationCount()); ASSERT_FALSE(close_closure.is_null()); close_closure.Run(); EXPECT_EQ(0u, ui_manager()->GetNotificationCount()); // Note that we cannot verify whether the closed event was called on the // delegate given that it'd result in a use-after-free. } TEST_F(PlatformNotificationServiceTest, PersistentNotificationDisplay) { content::PlatformNotificationData notification_data; notification_data.title = base::ASCIIToUTF16("My notification's title"); notification_data.body = base::ASCIIToUTF16("Hello, world!"); service()->DisplayPersistentNotification( profile(), 42 /* sw_registration_id */, GURL("https://chrome.com/"), SkBitmap(), notification_data); ASSERT_EQ(1u, ui_manager()->GetNotificationCount()); const Notification& notification = ui_manager()->GetNotificationAt(0); EXPECT_EQ("https://chrome.com/", notification.origin_url().spec()); EXPECT_EQ("My notification's title", base::UTF16ToUTF8(notification.title())); EXPECT_EQ("Hello, world!", base::UTF16ToUTF8(notification.message())); service()->ClosePersistentNotification(profile(), notification.delegate_id()); EXPECT_EQ(0u, ui_manager()->GetNotificationCount()); } TEST_F(PlatformNotificationServiceTest, DisplayPageNotificationMatches) { content::PlatformNotificationData notification_data; notification_data.title = base::ASCIIToUTF16("My notification's title"); notification_data.body = base::ASCIIToUTF16("Hello, world!"); notification_data.silent = true; MockDesktopNotificationDelegate* delegate = new MockDesktopNotificationDelegate(); service()->DisplayNotification(profile(), GURL("https://chrome.com/"), SkBitmap(), notification_data, make_scoped_ptr(delegate), nullptr); ASSERT_EQ(1u, ui_manager()->GetNotificationCount()); const Notification& notification = ui_manager()->GetNotificationAt(0); EXPECT_EQ("https://chrome.com/", notification.origin_url().spec()); EXPECT_EQ("My notification's title", base::UTF16ToUTF8(notification.title())); EXPECT_EQ("Hello, world!", base::UTF16ToUTF8(notification.message())); EXPECT_TRUE(notification.silent()); } TEST_F(PlatformNotificationServiceTest, DisplayNameForOrigin) { base::string16 display_name = service()->DisplayNameForOrigin(profile(), GURL("https://chrome.com/")); EXPECT_EQ(base::ASCIIToUTF16("chrome.com"), display_name); // TODO(peter): Include unit tests for the extension-name translation // functionality of DisplayNameForOriginInProcessId. } TEST_F(PlatformNotificationServiceTest, TestWebOriginDisplayName) { std::string language("en-us"); GURL https_origin("https://mail.google.com/"); base::string16 expected_display_name = base::ASCIIToUTF16("mail.google.com"); EXPECT_EQ(expected_display_name, PlatformNotificationServiceImpl::WebOriginDisplayName(https_origin, language)); GURL https_origin_standard_port("https://mail.google.com:443/"); expected_display_name = base::ASCIIToUTF16("mail.google.com"); EXPECT_EQ(expected_display_name, PlatformNotificationServiceImpl::WebOriginDisplayName( https_origin_standard_port, language)); GURL https_origin_nonstandard_port("https://mail.google.com:444/"); expected_display_name = base::ASCIIToUTF16("mail.google.com:444"); EXPECT_EQ(expected_display_name, PlatformNotificationServiceImpl::WebOriginDisplayName( https_origin_nonstandard_port, language)); GURL http_origin("http://mail.google.com/"); expected_display_name = base::ASCIIToUTF16("http://mail.google.com"); EXPECT_EQ(expected_display_name, PlatformNotificationServiceImpl::WebOriginDisplayName(http_origin, language)); GURL http_origin_standard_port("http://mail.google.com:80/"); expected_display_name = base::ASCIIToUTF16("http://mail.google.com"); EXPECT_EQ(expected_display_name, PlatformNotificationServiceImpl::WebOriginDisplayName( http_origin_standard_port, language)); GURL http_origin_nonstandard_port("http://mail.google.com:81/"); expected_display_name = base::ASCIIToUTF16("http://mail.google.com:81"); EXPECT_EQ(expected_display_name, PlatformNotificationServiceImpl::WebOriginDisplayName( http_origin_nonstandard_port, language)); // TODO(dewittj): Add file origin once it's supported. } TEST_F(PlatformNotificationServiceTest, NotificationPermissionLastUsage) { // Both page and persistent notifications should update the last usage // time of the notification permission for the origin. GURL origin("https://chrome.com/"); base::Time begin_time; CreateSimplePageNotification(); base::Time after_page_notification = profile()->GetHostContentSettingsMap()->GetLastUsage( origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); EXPECT_GT(after_page_notification, begin_time); // Ensure that there is at least some time between the two calls. base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); service()->DisplayPersistentNotification( profile(), 42 /* sw_registration_id */, origin, SkBitmap(), content::PlatformNotificationData()); base::Time after_persistent_notification = profile()->GetHostContentSettingsMap()->GetLastUsage( origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); EXPECT_GT(after_persistent_notification, after_page_notification); }