Commit 77895c86 authored by Xing Liu's avatar Xing Liu Committed by Commit Bot

Notification scheduler: Cache API calls before initialization is done.

This CL adds a class to cache API calls before NotificationScheduler
async initialization is done.

Bug: 930968
Change-Id: Ic4bff46205393d684ec7c825e96daad788d0a914
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1573240Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Commit-Queue: Xing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#652398}
parent 09bb2c1c
......@@ -78,6 +78,8 @@ source_set("lib") {
"impression_store.h",
"impression_types.cc",
"impression_types.h",
"init_aware_scheduler.cc",
"init_aware_scheduler.h",
"internal_types.h",
"notification_entry.cc",
"notification_entry.h",
......@@ -115,6 +117,7 @@ source_set("unit_tests") {
"icon_store_unittest.cc",
"impression_history_tracker_unittest.cc",
"impression_store_unittest.cc",
"init_aware_scheduler_unittest.cc",
"proto_conversion_unittest.cc",
"scheduled_notification_manager_unittest.cc",
"scheduler_utils_unittest.cc",
......
// Copyright 2019 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 "chrome/browser/notifications/scheduler/init_aware_scheduler.h"
#include "base/bind.h"
#include "chrome/browser/notifications/scheduler/notification_params.h"
namespace notifications {
InitAwareNotificationScheduler::InitAwareNotificationScheduler(
std::unique_ptr<NotificationScheduler> impl)
: impl_(std::move(impl)), weak_ptr_factory_(this) {}
InitAwareNotificationScheduler::~InitAwareNotificationScheduler() = default;
void InitAwareNotificationScheduler::Init(InitCallback init_callback) {
DCHECK(!init_success_.has_value());
impl_->Init(base::BindOnce(&InitAwareNotificationScheduler::OnInitialized,
weak_ptr_factory_.GetWeakPtr(),
std::move(init_callback)));
}
void InitAwareNotificationScheduler::Schedule(
std::unique_ptr<NotificationParams> params) {
if (init_success_.has_value() && *init_success_) {
impl_->Schedule(std::move(params));
return;
}
if (init_success_.has_value() && !*init_success_)
return;
cached_closures_.emplace_back(
base::BindOnce(&InitAwareNotificationScheduler::Schedule,
weak_ptr_factory_.GetWeakPtr(), std::move(params)));
}
void InitAwareNotificationScheduler::OnInitialized(InitCallback init_callback,
bool success) {
init_success_ = success;
if (!success) {
cached_closures_.clear();
std::move(init_callback).Run(false);
return;
}
// Flush all cached calls.
for (auto it = cached_closures_.begin(); it != cached_closures_.end(); ++it) {
std::move(*it).Run();
}
cached_closures_.clear();
std::move(init_callback).Run(true);
}
} // namespace notifications
// Copyright 2019 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 CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_INIT_AWARE_SCHEDULER_H_
#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_INIT_AWARE_SCHEDULER_H_
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chrome/browser/notifications/scheduler/notification_scheduler.h"
namespace notifications {
struct NotificationParams;
// NotificationScheduler implementation that caches NotificationScheduler API
// calls and flush them to the actual implementation after initialization
// succeeded.
class InitAwareNotificationScheduler : public NotificationScheduler {
public:
explicit InitAwareNotificationScheduler(
std::unique_ptr<NotificationScheduler> impl);
~InitAwareNotificationScheduler() override;
private:
// NotificationScheduler implementation.
void Init(InitCallback init_callback) override;
void Schedule(
std::unique_ptr<NotificationParams> notification_params) override;
// Called after initialization is done.
void OnInitialized(InitCallback init_callback, bool success);
// Whether the initialization is successful. No value if initialization is not
// finished.
base::Optional<bool> init_success_;
// Cached calls.
std::vector<base::OnceClosure> cached_closures_;
// Actual implementation.
std::unique_ptr<NotificationScheduler> impl_;
base::WeakPtrFactory<InitAwareNotificationScheduler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(InitAwareNotificationScheduler);
};
} // namespace notifications
#endif // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_INIT_AWARE_SCHEDULER_H_
// Copyright 2019 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 "chrome/browser/notifications/scheduler/init_aware_scheduler.h"
#include <memory>
#include "base/bind_helpers.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/browser/notifications/scheduler/notification_params.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::InSequence;
using testing::Invoke;
namespace notifications {
namespace {
class MockNotificationScheduler : public NotificationScheduler {
public:
MockNotificationScheduler() = default;
~MockNotificationScheduler() override = default;
MOCK_METHOD1(Init, void(InitCallback));
MOCK_METHOD1(Schedule, void(std::unique_ptr<NotificationParams>));
private:
DISALLOW_COPY_AND_ASSIGN(MockNotificationScheduler);
};
class InitAwareNotificationSchedulerTest : public testing::Test {
public:
InitAwareNotificationSchedulerTest() : scheduler_impl_(nullptr) {}
~InitAwareNotificationSchedulerTest() override = default;
void SetUp() override {
auto scheduler = std::make_unique<MockNotificationScheduler>();
scheduler_impl_ = scheduler.get();
init_aware_scheduler_ =
std::make_unique<InitAwareNotificationScheduler>(std::move(scheduler));
}
protected:
std::unique_ptr<NotificationParams> BuildParams() {
return std::make_unique<NotificationParams>(
SchedulerClientType::kUnknown, NotificationData(), ScheduleParams());
}
NotificationScheduler* init_aware_scheduler() {
return init_aware_scheduler_.get();
}
MockNotificationScheduler* scheduler_impl() { return scheduler_impl_; }
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
MockNotificationScheduler* scheduler_impl_;
std::unique_ptr<NotificationScheduler> init_aware_scheduler_;
DISALLOW_COPY_AND_ASSIGN(InitAwareNotificationSchedulerTest);
};
// Checks std::unique_ptr<NotificationParams> has specific guid.
MATCHER_P(GuidIs, expected_guid, "") {
return arg->guid == expected_guid;
}
// Verifies cached calls are flushed into the actual implementation.
TEST_F(InitAwareNotificationSchedulerTest, FlushCachedCalls) {
auto params = BuildParams();
std::string guid = params->guid;
EXPECT_FALSE(guid.empty());
{
InSequence sequence;
EXPECT_CALL(*scheduler_impl(), Init(_))
.WillOnce(Invoke([](NotificationScheduler::InitCallback cb) {
std::move(cb).Run(true /*success*/);
}));
EXPECT_CALL(*scheduler_impl(), Schedule(GuidIs(guid)));
// Schedule() call before Init() will be cached.
init_aware_scheduler()->Schedule(std::move(params));
init_aware_scheduler()->Init(base::DoNothing());
}
}
// Verifies that API calls after successful initialization will call into the
// actual implementation.
TEST_F(InitAwareNotificationSchedulerTest, CallAfterInitSuccess) {
auto params = BuildParams();
std::string guid = params->guid;
EXPECT_FALSE(guid.empty());
{
InSequence sequence;
EXPECT_CALL(*scheduler_impl(), Init(_))
.WillOnce(Invoke([](NotificationScheduler::InitCallback cb) {
std::move(cb).Run(true /*success*/);
}));
EXPECT_CALL(*scheduler_impl(), Schedule(GuidIs(guid)));
// Schedule() call after Init().
init_aware_scheduler()->Init(base::DoNothing());
init_aware_scheduler()->Schedule(std::move(params));
}
}
// Verifies no calls are flushed to actual implementation if initialization
// failed.
TEST_F(InitAwareNotificationSchedulerTest, NoFlushOnInitFailure) {
auto params1 = BuildParams();
auto params2 = BuildParams();
EXPECT_CALL(*scheduler_impl(), Init(_))
.WillOnce(Invoke([](NotificationScheduler::InitCallback cb) {
std::move(cb).Run(false /*success*/);
}));
EXPECT_CALL(*scheduler_impl(), Schedule(_)).Times(0);
init_aware_scheduler()->Schedule(std::move(params1));
init_aware_scheduler()->Init(base::DoNothing());
init_aware_scheduler()->Schedule(std::move(params2));
}
} // namespace
} // namespace notifications
......@@ -22,6 +22,8 @@ class NotificationSchedulerImpl : public NotificationScheduler {
private:
// NotificationScheduler implementation.
void Init(InitCallback init_callback) override { NOTIMPLEMENTED(); }
void Schedule(
std::unique_ptr<NotificationParams> notification_params) override {
NOTIMPLEMENTED();
......
......@@ -7,6 +7,7 @@
#include <memory>
#include "base/callback.h"
#include "base/macros.h"
namespace notifications {
......@@ -18,12 +19,16 @@ struct NotificationParams;
// glues all the subsystems together for notification scheduling system.
class NotificationScheduler {
public:
using InitCallback = base::OnceCallback<void(bool)>;
static std::unique_ptr<NotificationScheduler> Create(
std::unique_ptr<NotificationSchedulerContext> context);
NotificationScheduler();
virtual ~NotificationScheduler();
// Initializes the scheduler.
virtual void Init(InitCallback init_callback) = 0;
// Schedules a notification to show in the future. Throttling logic may apply
// based on |notification_params|.
virtual void Schedule(
......
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