blob: a2c60f1e0bf6f55d9dd4ac16a0dab700412aae37 [file] [log] [blame]
// 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 <stdint.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/notifications/metrics/mock_notification_metrics_logger.h"
#include "chrome/browser/notifications/metrics/notification_metrics_logger_factory.h"
#include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/notifications/platform_notification_service_impl.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/permission_type.h"
#include "content/public/common/notification_resources.h"
#include "content/public/common/platform_notification_data.h"
#include "content/public/test/mock_permission_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "extensions/buildflags/buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/test_extension_system.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/value_builder.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
using ::testing::_;
using ::testing::Return;
using content::NotificationResources;
using content::PlatformNotificationData;
using message_center::Notification;
namespace {
const char kNotificationId[] = "my-notification-id";
const int kNotificationVibrationPattern[] = { 100, 200, 300 };
class TestingProfileWithPermissionManager : public TestingProfile {
public:
TestingProfileWithPermissionManager()
: permission_manager_(
std::make_unique<
testing::NiceMock<content::MockPermissionManager>>()) {}
~TestingProfileWithPermissionManager() override = default;
// Sets the notification permission status to |permission_status|.
void SetNotificationPermissionStatus(
blink::mojom::PermissionStatus permission_status) {
ON_CALL(*permission_manager_,
GetPermissionStatus(content::PermissionType::NOTIFICATIONS, _, _))
.WillByDefault(Return(permission_status));
}
// TestingProfile overrides:
content::PermissionControllerDelegate* GetPermissionControllerDelegate()
override {
return permission_manager_.get();
}
private:
std::unique_ptr<content::MockPermissionManager> permission_manager_;
DISALLOW_COPY_AND_ASSIGN(TestingProfileWithPermissionManager);
};
} // namespace
class PlatformNotificationServiceTest : public testing::Test {
public:
void SetUp() override {
display_service_tester_ =
std::make_unique<NotificationDisplayServiceTester>(&profile_);
mock_logger_ = static_cast<MockNotificationMetricsLogger*>(
NotificationMetricsLoggerFactory::GetInstance()
->SetTestingFactoryAndUse(
&profile_, &MockNotificationMetricsLogger::FactoryForTests));
}
void TearDown() override {
display_service_tester_.reset();
}
protected:
// Returns the Platform Notification Service these unit tests are for.
PlatformNotificationServiceImpl* service() const {
return PlatformNotificationServiceImpl::GetInstance();
}
size_t GetNotificationCountForType(NotificationHandler::Type type) {
return display_service_tester_->GetDisplayedNotificationsForType(type)
.size();
}
Notification GetDisplayedNotificationForType(NotificationHandler::Type type) {
std::vector<Notification> notifications =
display_service_tester_->GetDisplayedNotificationsForType(type);
DCHECK_EQ(1u, notifications.size());
return notifications[0];
}
protected:
content::TestBrowserThreadBundle thread_bundle_;
TestingProfileWithPermissionManager profile_;
std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
// Owned by the |profile_| as a keyed service.
MockNotificationMetricsLogger* mock_logger_;
};
TEST_F(PlatformNotificationServiceTest, DisplayNonPersistentThenClose) {
PlatformNotificationData notification_data;
notification_data.title = base::ASCIIToUTF16("My Notification");
notification_data.body = base::ASCIIToUTF16("Hello, world!");
service()->DisplayNotification(&profile_, kNotificationId,
GURL("https://chrome.com/"), notification_data,
NotificationResources());
EXPECT_EQ(1u, GetNotificationCountForType(
NotificationHandler::Type::WEB_NON_PERSISTENT));
service()->CloseNotification(&profile_, kNotificationId);
EXPECT_EQ(0u, GetNotificationCountForType(
NotificationHandler::Type::WEB_NON_PERSISTENT));
}
TEST_F(PlatformNotificationServiceTest, DisplayPersistentThenClose) {
PlatformNotificationData notification_data;
notification_data.title = base::ASCIIToUTF16("My notification's title");
notification_data.body = base::ASCIIToUTF16("Hello, world!");
EXPECT_CALL(*mock_logger_, LogPersistentNotificationShown());
service()->DisplayPersistentNotification(
&profile_, kNotificationId, GURL() /* service_worker_scope */,
GURL("https://chrome.com/"), notification_data, NotificationResources());
ASSERT_EQ(1u, GetNotificationCountForType(
NotificationHandler::Type::WEB_PERSISTENT));
Notification notification = GetDisplayedNotificationForType(
NotificationHandler::Type::WEB_PERSISTENT);
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_, kNotificationId);
EXPECT_EQ(0u, GetNotificationCountForType(
NotificationHandler::Type::WEB_PERSISTENT));
}
TEST_F(PlatformNotificationServiceTest, OnPersistentNotificationClick) {
EXPECT_CALL(*mock_logger_, LogPersistentNotificationClickWithoutPermission());
profile_.SetNotificationPermissionStatus(
blink::mojom::PermissionStatus::DENIED);
service()->OnPersistentNotificationClick(
&profile_, "jskdcjdslkcjlds", GURL("https://example.com/"), base::nullopt,
base::nullopt, base::DoNothing());
}
TEST_F(PlatformNotificationServiceTest, OnPersistentNotificationClosedByUser) {
EXPECT_CALL(*mock_logger_, LogPersistentNotificationClosedByUser());
service()->OnPersistentNotificationClose(
&profile_, "some_random_id_123", GURL("https://example.com/"),
true /* by_user */, base::DoNothing());
}
TEST_F(PlatformNotificationServiceTest,
OnPersistentNotificationClosedProgrammatically) {
EXPECT_CALL(*mock_logger_, LogPersistentNotificationClosedProgrammatically());
service()->OnPersistentNotificationClose(
&profile_, "some_random_id_738", GURL("https://example.com/"),
false /* by_user */, base::DoNothing());
}
TEST_F(PlatformNotificationServiceTest, DisplayNonPersistentPropertiesMatch) {
std::vector<int> vibration_pattern(
kNotificationVibrationPattern,
kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
PlatformNotificationData notification_data;
notification_data.title = base::ASCIIToUTF16("My notification's title");
notification_data.body = base::ASCIIToUTF16("Hello, world!");
notification_data.vibration_pattern = vibration_pattern;
notification_data.silent = true;
service()->DisplayNotification(&profile_, kNotificationId,
GURL("https://chrome.com/"), notification_data,
NotificationResources());
ASSERT_EQ(1u, GetNotificationCountForType(
NotificationHandler::Type::WEB_NON_PERSISTENT));
Notification notification = GetDisplayedNotificationForType(
NotificationHandler::Type::WEB_NON_PERSISTENT);
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_THAT(notification.vibration_pattern(),
testing::ElementsAreArray(kNotificationVibrationPattern));
EXPECT_TRUE(notification.silent());
}
TEST_F(PlatformNotificationServiceTest, DisplayPersistentPropertiesMatch) {
std::vector<int> vibration_pattern(
kNotificationVibrationPattern,
kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
PlatformNotificationData notification_data;
notification_data.title = base::ASCIIToUTF16("My notification's title");
notification_data.body = base::ASCIIToUTF16("Hello, world!");
notification_data.vibration_pattern = vibration_pattern;
notification_data.silent = true;
notification_data.actions.resize(2);
notification_data.actions[0].type =
content::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
notification_data.actions[0].title = base::ASCIIToUTF16("Button 1");
notification_data.actions[1].type =
content::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
notification_data.actions[1].title = base::ASCIIToUTF16("Button 2");
NotificationResources notification_resources;
notification_resources.action_icons.resize(notification_data.actions.size());
EXPECT_CALL(*mock_logger_, LogPersistentNotificationShown());
service()->DisplayPersistentNotification(
&profile_, kNotificationId, GURL() /* service_worker_scope */,
GURL("https://chrome.com/"), notification_data, notification_resources);
ASSERT_EQ(1u, GetNotificationCountForType(
NotificationHandler::Type::WEB_PERSISTENT));
Notification notification = GetDisplayedNotificationForType(
NotificationHandler::Type::WEB_PERSISTENT);
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_THAT(notification.vibration_pattern(),
testing::ElementsAreArray(kNotificationVibrationPattern));
EXPECT_TRUE(notification.silent());
const auto& buttons = notification.buttons();
ASSERT_EQ(2u, buttons.size());
EXPECT_EQ("Button 1", base::UTF16ToUTF8(buttons[0].title));
EXPECT_FALSE(buttons[0].placeholder);
EXPECT_EQ("Button 2", base::UTF16ToUTF8(buttons[1].title));
EXPECT_TRUE(buttons[1].placeholder);
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(PlatformNotificationServiceTest, DisplayNameForContextMessage) {
base::string16 display_name = service()->DisplayNameForContextMessage(
&profile_, GURL("https://chrome.com/"));
EXPECT_TRUE(display_name.empty());
// Create a mocked extension.
scoped_refptr<extensions::Extension> extension =
extensions::ExtensionBuilder()
.SetID("honijodknafkokifofgiaalefdiedpko")
.SetManifest(extensions::DictionaryBuilder()
.Set("name", "NotificationTest")
.Set("version", "1.0")
.Set("manifest_version", 2)
.Set("description", "Test Extension")
.Build())
.Build();
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(&profile_);
EXPECT_TRUE(registry->AddEnabled(extension));
display_name = service()->DisplayNameForContextMessage(
&profile_,
GURL("chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"));
EXPECT_EQ("NotificationTest", base::UTF16ToUTF8(display_name));
}
TEST_F(PlatformNotificationServiceTest, CreateNotificationFromData) {
PlatformNotificationData notification_data;
notification_data.title = base::ASCIIToUTF16("My Notification");
notification_data.body = base::ASCIIToUTF16("Hello, world!");
GURL origin("https://chrome.com/");
Notification notification = service()->CreateNotificationFromData(
&profile_, origin, "id", notification_data, NotificationResources(),
nullptr /* delegate */);
EXPECT_TRUE(notification.context_message().empty());
// Create a mocked extension.
scoped_refptr<extensions::Extension> extension =
extensions::ExtensionBuilder()
.SetID("honijodknafkokifofgiaalefdiedpko")
.SetManifest(extensions::DictionaryBuilder()
.Set("name", "NotificationTest")
.Set("version", "1.0")
.Set("manifest_version", 2)
.Set("description", "Test Extension")
.Build())
.Build();
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(&profile_);
EXPECT_TRUE(registry->AddEnabled(extension));
notification = service()->CreateNotificationFromData(
&profile_,
GURL("chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"),
"id", notification_data, NotificationResources(), nullptr /* delegate */);
EXPECT_EQ("NotificationTest",
base::UTF16ToUTF8(notification.context_message()));
}
// Expect each call to ReadNextPersistentNotificationId to return a larger
// value.
TEST_F(PlatformNotificationServiceTest, NextPersistentNotificationId) {
int64_t first_id = service()->ReadNextPersistentNotificationId(&profile_);
int64_t second_id = service()->ReadNextPersistentNotificationId(&profile_);
EXPECT_LT(first_id, second_id);
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)