Commit f3f824cd authored by miguelg's avatar miguelg Committed by Commit bot

Test the platform notification context synchronize operation

- Extract the mock implementation used for layout tests
- Add the ability to synchronize notifications to the mock implementation
- Create a small class with a custom content browser client
- Use all of that in the test

BUG=596161

Review-Url: https://codereview.chromium.org/2672313004
Cr-Commit-Position: refs/heads/master@{#449282}
parent 0284803b
......@@ -15,8 +15,11 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/notification_database_data.h"
#include "content/public/common/notification_resources.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/mock_platform_notification_service.h"
#include "content/test/test_content_browser_client.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
......@@ -25,6 +28,19 @@ namespace content {
// Fake Service Worker registration id to use in tests requiring one.
const int64_t kFakeServiceWorkerRegistrationId = 42;
class NotificationBrowserClient : public TestContentBrowserClient {
public:
NotificationBrowserClient()
: platform_notification_service_(new MockPlatformNotificationService()) {}
PlatformNotificationService* GetPlatformNotificationService() override {
return platform_notification_service_.get();
}
private:
std::unique_ptr<PlatformNotificationService> platform_notification_service_;
};
class PlatformNotificationContextTest : public ::testing::Test {
public:
PlatformNotificationContextTest()
......@@ -484,4 +500,69 @@ TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataFilled) {
}
}
TEST_F(PlatformNotificationContextTest, SynchronizeNotifications) {
NotificationBrowserClient notification_browser_client;
SetBrowserClientForTesting(&notification_browser_client);
scoped_refptr<PlatformNotificationContextImpl> context =
CreatePlatformNotificationContext();
GURL origin("https://example.com");
NotificationDatabaseData notification_database_data;
notification_database_data.service_worker_registration_id =
kFakeServiceWorkerRegistrationId;
PlatformNotificationData notification_data;
content::NotificationResources notification_resources;
context->WriteNotificationData(
origin, notification_database_data,
base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(success());
EXPECT_FALSE(notification_id().empty());
PlatformNotificationService* service =
notification_browser_client.GetPlatformNotificationService();
service->DisplayPersistentNotification(browser_context(), notification_id(),
origin, origin, notification_data,
notification_resources);
std::vector<NotificationDatabaseData> notification_database_datas;
context->ReadAllNotificationDataForServiceWorkerRegistration(
origin, kFakeServiceWorkerRegistrationId,
base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
base::Unretained(this), &notification_database_datas));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(success());
ASSERT_EQ(1u, notification_database_datas.size());
// Delete the notification from the display service without removing it from
// the database. It should automatically synchronize on the next read.
service->ClosePersistentNotification(browser_context(), notification_id());
context->ReadAllNotificationDataForServiceWorkerRegistration(
origin, kFakeServiceWorkerRegistrationId,
base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
base::Unretained(this), &notification_database_datas));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(success());
ASSERT_EQ(0u, notification_database_datas.size());
context->ReadNotificationData(
notification_id(), origin,
base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
// The notification was removed, so we shouldn't be able to read it from
// the database anymore.
EXPECT_FALSE(success());
}
} // namespace content
......@@ -18,71 +18,10 @@
#include "content/shell/browser/layout_test/layout_test_permission_manager.h"
namespace content {
namespace {
// The Web Notification layout tests don't care about the lifetime of the
// Service Worker when a notificationclick event has been dispatched.
void OnEventDispatchComplete(PersistentNotificationStatus status) {}
} // namespace
LayoutTestNotificationManager::LayoutTestNotificationManager()
: weak_factory_(this) {}
LayoutTestNotificationManager::LayoutTestNotificationManager() {}
LayoutTestNotificationManager::~LayoutTestNotificationManager() {}
void LayoutTestNotificationManager::DisplayNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources,
std::unique_ptr<DesktopNotificationDelegate> delegate,
base::Closure* cancel_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(cancel_callback);
*cancel_callback = base::Bind(&LayoutTestNotificationManager::Close,
weak_factory_.GetWeakPtr(), notification_id);
ReplaceNotificationIfNeeded(notification_id);
non_persistent_notifications_[notification_id] = std::move(delegate);
non_persistent_notifications_[notification_id]->NotificationDisplayed();
notification_id_map_[base::UTF16ToUTF8(notification_data.title)] =
notification_id;
}
void LayoutTestNotificationManager::DisplayPersistentNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& service_worker_scope,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ReplaceNotificationIfNeeded(notification_id);
PersistentNotification notification;
notification.browser_context = browser_context;
notification.origin = origin;
persistent_notifications_[notification_id] = notification;
notification_id_map_[base::UTF16ToUTF8(notification_data.title)] =
notification_id;
}
void LayoutTestNotificationManager::ClosePersistentNotification(
BrowserContext* browser_context,
const std::string& notification_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
persistent_notifications_.erase(notification_id);
}
bool LayoutTestNotificationManager::GetDisplayedNotifications(
BrowserContext* browser_context,
std::set<std::string>* displayed_notifications) {
......@@ -93,101 +32,6 @@ bool LayoutTestNotificationManager::GetDisplayedNotifications(
return false;
}
void LayoutTestNotificationManager::SimulateClick(
const std::string& title,
int action_index,
const base::NullableString16& reply) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const auto notification_id_iter = notification_id_map_.find(title);
if (notification_id_iter == notification_id_map_.end())
return;
const std::string& notification_id = notification_id_iter->second;
const auto persistent_iter = persistent_notifications_.find(notification_id);
const auto non_persistent_iter =
non_persistent_notifications_.find(notification_id);
if (persistent_iter != persistent_notifications_.end()) {
DCHECK(non_persistent_iter == non_persistent_notifications_.end());
const PersistentNotification& notification = persistent_iter->second;
content::NotificationEventDispatcher::GetInstance()
->DispatchNotificationClickEvent(
notification.browser_context, notification_id, notification.origin,
action_index, reply, base::Bind(&OnEventDispatchComplete));
} else if (non_persistent_iter != non_persistent_notifications_.end()) {
DCHECK_EQ(action_index, -1) << "Action buttons are only supported for "
"persistent notifications";
non_persistent_iter->second->NotificationClick();
}
}
void LayoutTestNotificationManager::SimulateClose(const std::string& title,
bool by_user) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const auto notification_id_iter = notification_id_map_.find(title);
if (notification_id_iter == notification_id_map_.end())
return;
const std::string& notification_id = notification_id_iter->second;
const auto& persistent_iter = persistent_notifications_.find(notification_id);
if (persistent_iter == persistent_notifications_.end())
return;
const PersistentNotification& notification = persistent_iter->second;
content::NotificationEventDispatcher::GetInstance()
->DispatchNotificationCloseEvent(
notification.browser_context, notification_id, notification.origin,
by_user, base::Bind(&OnEventDispatchComplete));
}
blink::mojom::PermissionStatus
LayoutTestNotificationManager::CheckPermissionOnUIThread(
BrowserContext* browser_context,
const GURL& origin,
int render_process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return CheckPermission(origin);
}
blink::mojom::PermissionStatus
LayoutTestNotificationManager::CheckPermissionOnIOThread(
ResourceContext* resource_context,
const GURL& origin,
int render_process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return CheckPermission(origin);
}
void LayoutTestNotificationManager::Close(const std::string& notification_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto iterator = non_persistent_notifications_.find(notification_id);
if (iterator == non_persistent_notifications_.end())
return;
iterator->second->NotificationClosed();
}
void LayoutTestNotificationManager::ReplaceNotificationIfNeeded(
const std::string& notification_id) {
const auto persistent_iter = persistent_notifications_.find(notification_id);
const auto non_persistent_iter =
non_persistent_notifications_.find(notification_id);
if (persistent_iter != persistent_notifications_.end()) {
DCHECK(non_persistent_iter == non_persistent_notifications_.end());
persistent_notifications_.erase(persistent_iter);
} else if (non_persistent_iter != non_persistent_notifications_.end()) {
non_persistent_iter->second->NotificationClosed();
non_persistent_notifications_.erase(non_persistent_iter);
}
}
blink::mojom::PermissionStatus
LayoutTestNotificationManager::CheckPermission(const GURL& origin) {
return LayoutTestContentBrowserClient::Get()
......
......@@ -5,14 +5,10 @@
#ifndef CONTENT_SHELL_BROWSER_LAYOUT_TEST_LAYOUT_TEST_NOTIFICATION_MANAGER_H_
#define CONTENT_SHELL_BROWSER_LAYOUT_TEST_LAYOUT_TEST_NOTIFICATION_MANAGER_H_
#include <stdint.h>
#include <string>
#include <unordered_map>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/platform_notification_service.h"
#include "content/test/mock_platform_notification_service.h"
#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
#include "url/gurl.h"
......@@ -22,87 +18,20 @@ class NullableString16;
namespace content {
class DesktopNotificationDelegate;
struct NotificationResources;
struct PlatformNotificationData;
// Responsible for tracking active notifications and allowed origins for the
// Web Notification API when running layout tests.
class LayoutTestNotificationManager : public PlatformNotificationService {
class LayoutTestNotificationManager : public MockPlatformNotificationService {
public:
LayoutTestNotificationManager();
~LayoutTestNotificationManager() override;
// Simulates a click on the notification titled |title|. |action_index|
// indicates which action was clicked, or -1 if the main notification body was
// clicked. |reply| indicates the user reply, if any.
// Must be called on the UI thread.
void SimulateClick(const std::string& title,
int action_index,
const base::NullableString16& reply);
// Simulates the closing a notification titled |title|. Must be called on
// the UI thread.
void SimulateClose(const std::string& title, bool by_user);
// PlatformNotificationService implementation.
blink::mojom::PermissionStatus CheckPermissionOnUIThread(
BrowserContext* browser_context,
const GURL& origin,
int render_process_id) override;
blink::mojom::PermissionStatus CheckPermissionOnIOThread(
ResourceContext* resource_context,
const GURL& origin,
int render_process_id) override;
void DisplayNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources,
std::unique_ptr<DesktopNotificationDelegate> delegate,
base::Closure* cancel_callback) override;
void DisplayPersistentNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& service_worker_scope,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources) override;
void ClosePersistentNotification(BrowserContext* browser_context,
const std::string& notification_id) override;
// MockPlatformNotificationService overrides.
bool GetDisplayedNotifications(
BrowserContext* browser_context,
std::set<std::string>* displayed_notifications) override;
private:
// Structure to represent the information of a persistent notification.
struct PersistentNotification {
BrowserContext* browser_context = nullptr;
GURL origin;
};
// Closes the notification titled |title|. Must be called on the UI thread.
void Close(const std::string& title);
// Fakes replacing the notification identified by |notification_id|. Both
// persistent and non-persistent notifications will be considered for this.
void ReplaceNotificationIfNeeded(const std::string& notification_id);
// Checks if |origin| has permission to display notifications. May be called
// on both the IO and the UI threads.
blink::mojom::PermissionStatus CheckPermission(const GURL& origin);
std::unordered_map<std::string, PersistentNotification>
persistent_notifications_;
std::unordered_map<std::string, std::unique_ptr<DesktopNotificationDelegate>>
non_persistent_notifications_;
// Mapping of titles to notification ids giving test a usable identifier.
std::unordered_map<std::string, std::string> notification_id_map_;
base::WeakPtrFactory<LayoutTestNotificationManager> weak_factory_;
blink::mojom::PermissionStatus CheckPermission(const GURL& origin) override;
DISALLOW_COPY_AND_ASSIGN(LayoutTestNotificationManager);
};
......
......@@ -15,7 +15,6 @@
#include "content/public/browser/permission_type.h"
#include "content/public/browser/web_contents.h"
#include "content/shell/browser/layout_test/layout_test_content_browser_client.h"
#include "content/shell/browser/layout_test/layout_test_notification_manager.h"
namespace content {
......
......@@ -164,6 +164,8 @@ static_library("test_support") {
"mock_leveldb_database.h",
"mock_permission_manager.cc",
"mock_permission_manager.h",
"mock_platform_notification_service.cc",
"mock_platform_notification_service.h",
"mock_render_process.cc",
"mock_render_process.h",
"mock_ssl_host_state_delegate.cc",
......
// 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 "content/test/mock_platform_notification_service.h"
#include "base/guid.h"
#include "base/strings/nullable_string16.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_notification_delegate.h"
#include "content/public/browser/notification_event_dispatcher.h"
#include "content/public/browser/permission_type.h"
#include "content/public/common/persistent_notification_status.h"
#include "content/public/common/platform_notification_data.h"
namespace content {
namespace {
// The Web Notification layout tests don't care about the lifetime of the
// Service Worker when a notificationclick event has been dispatched.
void OnEventDispatchComplete(PersistentNotificationStatus status) {}
} // namespace
MockPlatformNotificationService::MockPlatformNotificationService()
: weak_factory_(this) {}
MockPlatformNotificationService::~MockPlatformNotificationService() {}
void MockPlatformNotificationService::DisplayNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources,
std::unique_ptr<DesktopNotificationDelegate> delegate,
base::Closure* cancel_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(cancel_callback);
*cancel_callback = base::Bind(&MockPlatformNotificationService::Close,
weak_factory_.GetWeakPtr(), notification_id);
ReplaceNotificationIfNeeded(notification_id);
non_persistent_notifications_[notification_id] = std::move(delegate);
non_persistent_notifications_[notification_id]->NotificationDisplayed();
notification_id_map_[base::UTF16ToUTF8(notification_data.title)] =
notification_id;
}
void MockPlatformNotificationService::DisplayPersistentNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& service_worker_scope,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ReplaceNotificationIfNeeded(notification_id);
PersistentNotification notification;
notification.browser_context = browser_context;
notification.origin = origin;
persistent_notifications_[notification_id] = notification;
notification_id_map_[base::UTF16ToUTF8(notification_data.title)] =
notification_id;
}
void MockPlatformNotificationService::ClosePersistentNotification(
BrowserContext* browser_context,
const std::string& notification_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
persistent_notifications_.erase(notification_id);
}
bool MockPlatformNotificationService::GetDisplayedNotifications(
BrowserContext* browser_context,
std::set<std::string>* displayed_notifications) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(displayed_notifications);
for (const auto& kv : persistent_notifications_)
displayed_notifications->insert(kv.first);
return true;
}
void MockPlatformNotificationService::SimulateClick(
const std::string& title,
int action_index,
const base::NullableString16& reply) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const auto notification_id_iter = notification_id_map_.find(title);
if (notification_id_iter == notification_id_map_.end())
return;
const std::string& notification_id = notification_id_iter->second;
const auto persistent_iter = persistent_notifications_.find(notification_id);
const auto non_persistent_iter =
non_persistent_notifications_.find(notification_id);
if (persistent_iter != persistent_notifications_.end()) {
DCHECK(non_persistent_iter == non_persistent_notifications_.end());
const PersistentNotification& notification = persistent_iter->second;
content::NotificationEventDispatcher::GetInstance()
->DispatchNotificationClickEvent(
notification.browser_context, notification_id, notification.origin,
action_index, reply, base::Bind(&OnEventDispatchComplete));
} else if (non_persistent_iter != non_persistent_notifications_.end()) {
DCHECK_EQ(action_index, -1) << "Action buttons are only supported for "
"persistent notifications";
non_persistent_iter->second->NotificationClick();
}
}
void MockPlatformNotificationService::SimulateClose(const std::string& title,
bool by_user) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const auto notification_id_iter = notification_id_map_.find(title);
if (notification_id_iter == notification_id_map_.end())
return;
const std::string& notification_id = notification_id_iter->second;
const auto& persistent_iter = persistent_notifications_.find(notification_id);
if (persistent_iter == persistent_notifications_.end())
return;
const PersistentNotification& notification = persistent_iter->second;
content::NotificationEventDispatcher::GetInstance()
->DispatchNotificationCloseEvent(
notification.browser_context, notification_id, notification.origin,
by_user, base::Bind(&OnEventDispatchComplete));
}
blink::mojom::PermissionStatus
MockPlatformNotificationService::CheckPermissionOnUIThread(
BrowserContext* browser_context,
const GURL& origin,
int render_process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return CheckPermission(origin);
}
blink::mojom::PermissionStatus
MockPlatformNotificationService::CheckPermissionOnIOThread(
ResourceContext* resource_context,
const GURL& origin,
int render_process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return CheckPermission(origin);
}
void MockPlatformNotificationService::Close(
const std::string& notification_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto iterator = non_persistent_notifications_.find(notification_id);
if (iterator == non_persistent_notifications_.end())
return;
iterator->second->NotificationClosed();
}
void MockPlatformNotificationService::ReplaceNotificationIfNeeded(
const std::string& notification_id) {
const auto persistent_iter = persistent_notifications_.find(notification_id);
const auto non_persistent_iter =
non_persistent_notifications_.find(notification_id);
if (persistent_iter != persistent_notifications_.end()) {
DCHECK(non_persistent_iter == non_persistent_notifications_.end());
persistent_notifications_.erase(persistent_iter);
} else if (non_persistent_iter != non_persistent_notifications_.end()) {
non_persistent_iter->second->NotificationClosed();
non_persistent_notifications_.erase(non_persistent_iter);
}
}
blink::mojom::PermissionStatus MockPlatformNotificationService::CheckPermission(
const GURL& origin) {
return blink::mojom::PermissionStatus::GRANTED;
}
} // namespace content
// 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.
#ifndef CONTENT_TEST_MOCK_PLATFORM_NOTIFICATION_SERVICE_H_
#define CONTENT_TEST_MOCK_PLATFORM_NOTIFICATION_SERVICE_H_
#include <stdint.h>
#include <string>
#include <unordered_map>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/platform_notification_service.h"
#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
#include "url/gurl.h"
namespace base {
class NullableString16;
}
namespace content {
class DesktopNotificationDelegate;
struct NotificationResources;
struct PlatformNotificationData;
// Responsible for tracking active notifications and allowed origins for the
// Web Notification API when running layout and content tests.
class MockPlatformNotificationService : public PlatformNotificationService {
public:
MockPlatformNotificationService();
~MockPlatformNotificationService() override;
// Simulates a click on the notification titled |title|. |action_index|
// indicates which action was clicked, or -1 if the main notification body was
// clicked. |reply| indicates the user reply, if any.
// Must be called on the UI thread.
void SimulateClick(const std::string& title,
int action_index,
const base::NullableString16& reply);
// Simulates the closing a notification titled |title|. Must be called on
// the UI thread.
void SimulateClose(const std::string& title, bool by_user);
// PlatformNotificationService implementation.
blink::mojom::PermissionStatus CheckPermissionOnUIThread(
BrowserContext* browser_context,
const GURL& origin,
int render_process_id) override;
blink::mojom::PermissionStatus CheckPermissionOnIOThread(
ResourceContext* resource_context,
const GURL& origin,
int render_process_id) override;
void DisplayNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources,
std::unique_ptr<DesktopNotificationDelegate> delegate,
base::Closure* cancel_callback) override;
void DisplayPersistentNotification(
BrowserContext* browser_context,
const std::string& notification_id,
const GURL& service_worker_scope,
const GURL& origin,
const PlatformNotificationData& notification_data,
const NotificationResources& notification_resources) override;
void ClosePersistentNotification(BrowserContext* browser_context,
const std::string& notification_id) override;
bool GetDisplayedNotifications(
BrowserContext* browser_context,
std::set<std::string>* displayed_notifications) override;
protected:
// Checks if |origin| has permission to display notifications. May be called
// on both the IO and the UI threads.
virtual blink::mojom::PermissionStatus CheckPermission(const GURL& origin);
private:
// Structure to represent the information of a persistent notification.
struct PersistentNotification {
BrowserContext* browser_context = nullptr;
GURL origin;
};
// Closes the notification titled |title|. Must be called on the UI thread.
void Close(const std::string& title);
// Fakes replacing the notification identified by |notification_id|. Both
// persistent and non-persistent notifications will be considered for this.
void ReplaceNotificationIfNeeded(const std::string& notification_id);
std::unordered_map<std::string, PersistentNotification>
persistent_notifications_;
std::unordered_map<std::string, std::unique_ptr<DesktopNotificationDelegate>>
non_persistent_notifications_;
// Mapping of titles to notification ids giving test a usable identifier.
std::unordered_map<std::string, std::string> notification_id_map_;
base::WeakPtrFactory<MockPlatformNotificationService> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MockPlatformNotificationService);
};
} // content
#endif // CONTENT_TEST_MOCK_PLATFORM_NOTIFICATION_SERVICE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment