Commit 2dc910b0 authored by jianli's avatar jianli Committed by Commit bot

Reland: Add GCMChannelStatusSyncer to schedule requests and enable/disable GCM

BUG=384041
TEST=new tests added

Committed: https://crrev.com/3c23f4a188e171998f3042ad62f4aa5717e66d63
Cr-Commit-Position: refs/heads/master@{#295524}

Review URL: https://codereview.chromium.org/561943002

Cr-Commit-Position: refs/heads/master@{#295645}
parent 99fa5464
......@@ -1135,6 +1135,7 @@ void BrowserProcessImpl::CreateGCMDriver() {
CHECK(PathService::Get(chrome::DIR_GLOBAL_GCM_STORE, &store_path));
gcm_driver_ = gcm::CreateGCMDriverDesktop(
make_scoped_ptr(new gcm::GCMClientFactory),
local_state(),
store_path,
system_request_context());
// Sign-in is not required for device-level GCM usage. So we just call
......
......@@ -82,6 +82,7 @@
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/dom_distiller/core/distilled_page_prefs.h"
#include "components/gcm_driver/gcm_channel_status_syncer.h"
#include "components/google/core/browser/google_pref_names.h"
#include "components/google/core/browser/google_url_tracker.h"
#include "components/network_time/network_time_tracker.h"
......@@ -293,6 +294,8 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
AutomaticProfileResetterFactory::RegisterPrefs(registry);
BackgroundModeManager::RegisterPrefs(registry);
RegisterBrowserPrefs(registry);
// The native GCM is used on Android instead.
gcm::GCMChannelStatusSyncer::RegisterPrefs(registry);
#if !defined(OS_CHROMEOS)
RegisterDefaultBrowserPromptPrefs(registry);
#endif // !defined(OS_CHROMEOS)
......@@ -443,6 +446,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
extensions::ExtensionSettingsHandler::RegisterProfilePrefs(registry);
extensions::TabsCaptureVisibleTabFunction::RegisterProfilePrefs(registry);
first_run::RegisterProfilePrefs(registry);
gcm::GCMChannelStatusSyncer::RegisterProfilePrefs(registry);
NewTabUI::RegisterProfilePrefs(registry);
PepperFlashSettingsManager::RegisterProfilePrefs(registry);
PinnedTabCodec::RegisterProfilePrefs(registry);
......
......@@ -73,6 +73,7 @@ GCMClient::ChromeBuildInfo GetChromeBuildInfo() {
scoped_ptr<GCMDriver> CreateGCMDriverDesktop(
scoped_ptr<GCMClientFactory> gcm_client_factory,
PrefService* prefs,
const base::FilePath& store_path,
const scoped_refptr<net::URLRequestContextGetter>& request_context) {
scoped_refptr<base::SequencedWorkerPool> worker_pool(
......@@ -84,6 +85,7 @@ scoped_ptr<GCMDriver> CreateGCMDriverDesktop(
return scoped_ptr<GCMDriver>(new GCMDriverDesktop(
gcm_client_factory.Pass(),
GetChromeBuildInfo(),
prefs,
store_path,
request_context,
content::BrowserThread::GetMessageLoopProxyForThread(
......
......@@ -8,6 +8,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
class PrefService;
namespace base {
class FilePath;
}
......@@ -23,6 +24,7 @@ class GCMClientFactory;
scoped_ptr<GCMDriver> CreateGCMDriverDesktop(
scoped_ptr<GCMClientFactory> gcm_client_factory,
PrefService* prefs,
const base::FilePath& store_path,
const scoped_refptr<net::URLRequestContextGetter>& request_context);
......
......@@ -166,6 +166,7 @@ GCMProfileService::GCMProfileService(
driver_ = CreateGCMDriverDesktop(
gcm_client_factory.Pass(),
profile_->GetPrefs(),
profile_->GetPath().Append(chrome::kGCMStoreDirname),
profile_->GetRequestContext());
......
......@@ -33,6 +33,8 @@
'gcm_driver/gcm_backoff_policy.h',
'gcm_driver/gcm_channel_status_request.cc',
'gcm_driver/gcm_channel_status_request.h',
'gcm_driver/gcm_channel_status_syncer.cc',
'gcm_driver/gcm_channel_status_syncer.h',
'gcm_driver/gcm_client.cc',
'gcm_driver/gcm_client.h',
'gcm_driver/gcm_client_factory.cc',
......@@ -73,6 +75,8 @@
'gcm_driver/gcm_account_mapper.h',
'gcm_driver/gcm_channel_status_request.cc',
'gcm_driver/gcm_channel_status_request.h',
'gcm_driver/gcm_channel_status_syncer.cc',
'gcm_driver/gcm_channel_status_syncer.h',
'gcm_driver/gcm_client_factory.cc',
'gcm_driver/gcm_client_factory.h',
'gcm_driver/gcm_client_impl.cc',
......
......@@ -17,6 +17,8 @@ static_library("gcm_driver") {
"gcm_backoff_policy.h",
"gcm_channel_status_request.cc",
"gcm_channel_status_request.h",
"gcm_channel_status_syncer.cc",
"gcm_channel_status_syncer.h",
"gcm_client.cc",
"gcm_client.h",
"gcm_client_factory.cc",
......@@ -51,6 +53,8 @@ static_library("gcm_driver") {
sources -= [
"gcm_channel_status_request.cc",
"gcm_channel_status_request.h",
"gcm_channel_status_syncer.cc",
"gcm_channel_status_syncer.h",
"gcm_client_factory.cc",
"gcm_client_factory.h",
"gcm_client_impl.cc",
......
include_rules = [
"+components/os_crypt",
"+components/pref_registry",
# TODO(johnme): Fix this layering violation.
"!content/public/android/java",
"+google_apis/gaia",
......
......@@ -41,12 +41,12 @@ GCMChannelStatusRequest::~GCMChannelStatusRequest() {
}
// static
int GCMChannelStatusRequest::default_poll_interval_seconds_for_testing() {
int GCMChannelStatusRequest::default_poll_interval_seconds() {
return kDefaultPollIntervalSeconds;
}
// static
int GCMChannelStatusRequest::min_poll_interval_seconds_for_testing() {
int GCMChannelStatusRequest::min_poll_interval_seconds() {
return kMinPollIntervalSeconds;
}
......
......@@ -36,9 +36,8 @@ class GCMChannelStatusRequest : public net::URLFetcherDelegate {
void Start();
// Exposed for testing purpose.
static int default_poll_interval_seconds_for_testing();
static int min_poll_interval_seconds_for_testing();
static int default_poll_interval_seconds();
static int min_poll_interval_seconds();
private:
// Overridden from URLFetcherDelegate:
......
......@@ -136,7 +136,7 @@ TEST_F(GCMChannelStatusRequestTest, ResponseWithDisabledStatus) {
EXPECT_TRUE(request_callback_invoked_);
EXPECT_FALSE(enabled_);
EXPECT_EQ(
GCMChannelStatusRequest::default_poll_interval_seconds_for_testing(),
GCMChannelStatusRequest::default_poll_interval_seconds(),
poll_interval_seconds_);
}
......@@ -148,7 +148,7 @@ TEST_F(GCMChannelStatusRequestTest, ResponseWithEnabledStatus) {
EXPECT_TRUE(request_callback_invoked_);
EXPECT_TRUE(enabled_);
EXPECT_EQ(
GCMChannelStatusRequest::default_poll_interval_seconds_for_testing(),
GCMChannelStatusRequest::default_poll_interval_seconds(),
poll_interval_seconds_);
}
......@@ -156,8 +156,7 @@ TEST_F(GCMChannelStatusRequestTest, ResponseWithPollInterval) {
// Setting a poll interval 15 minutes longer than the minimum interval we
// enforce.
int poll_interval_seconds =
GCMChannelStatusRequest::min_poll_interval_seconds_for_testing() +
15 * 60;
GCMChannelStatusRequest::min_poll_interval_seconds() + 15 * 60;
StartRequest();
SetResponseProtoData(NOT_SPECIFIED, poll_interval_seconds);
CompleteFetch();
......@@ -171,22 +170,20 @@ TEST_F(GCMChannelStatusRequestTest, ResponseWithShortPollInterval) {
// Setting a poll interval 15 minutes shorter than the minimum interval we
// enforce.
int poll_interval_seconds =
GCMChannelStatusRequest::min_poll_interval_seconds_for_testing() -
15 * 60;
GCMChannelStatusRequest::min_poll_interval_seconds() - 15 * 60;
StartRequest();
SetResponseProtoData(NOT_SPECIFIED, poll_interval_seconds);
CompleteFetch();
EXPECT_TRUE(request_callback_invoked_);
EXPECT_TRUE(enabled_);
EXPECT_EQ(GCMChannelStatusRequest::min_poll_interval_seconds_for_testing(),
EXPECT_EQ(GCMChannelStatusRequest::min_poll_interval_seconds(),
poll_interval_seconds_);
}
TEST_F(GCMChannelStatusRequestTest, ResponseWithDisabledStatusAndPollInterval) {
int poll_interval_seconds =
GCMChannelStatusRequest::min_poll_interval_seconds_for_testing() +
15 * 60;
GCMChannelStatusRequest::min_poll_interval_seconds() + 15 * 60;
StartRequest();
SetResponseProtoData(GCM_DISABLED, poll_interval_seconds);
CompleteFetch();
......
// 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 "components/gcm_driver/gcm_channel_status_syncer.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/rand_util.h"
#include "components/gcm_driver/gcm_channel_status_request.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/pref_registry/pref_registry_syncable.h"
namespace gcm {
namespace {
// The GCM channel's enabled state.
const char kGCMChannelStatus[] = "gcm.channel_status";
// The GCM channel's polling interval (in seconds).
const char kGCMChannelPollIntervalSeconds[] = "gcm.poll_interval";
// Last time when checking with the GCM channel status server is done.
const char kGCMChannelLastCheckTime[] = "gcm.check_time";
// A small delay to avoid sending request at browser startup time for first-time
// request.
const int kFirstTimeDelaySeconds = 1 * 60; // 1 minute.
// The fuzzing variation added to the polling delay.
const int kGCMChannelRequestTimeJitterSeconds = 15 * 60; // 15 minues.
} // namespace
// static
void GCMChannelStatusSyncer::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kGCMChannelStatus, true);
registry->RegisterIntegerPref(
kGCMChannelPollIntervalSeconds,
GCMChannelStatusRequest::default_poll_interval_seconds());
registry->RegisterInt64Pref(kGCMChannelLastCheckTime, 0);
}
// static
void GCMChannelStatusSyncer::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(
kGCMChannelStatus,
true,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterIntegerPref(
kGCMChannelPollIntervalSeconds,
GCMChannelStatusRequest::default_poll_interval_seconds(),
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterInt64Pref(
kGCMChannelLastCheckTime,
0,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
// static
int GCMChannelStatusSyncer::first_time_delay_seconds() {
return kFirstTimeDelaySeconds;
}
GCMChannelStatusSyncer::GCMChannelStatusSyncer(
GCMDriver* driver,
PrefService* prefs,
const scoped_refptr<net::URLRequestContextGetter>& request_context)
: driver_(driver),
prefs_(prefs),
request_context_(request_context),
gcm_enabled_(true),
poll_interval_seconds_(
GCMChannelStatusRequest::default_poll_interval_seconds()),
delay_removed_for_testing_(false),
weak_ptr_factory_(this) {
gcm_enabled_ = prefs_->GetBoolean(kGCMChannelStatus);
poll_interval_seconds_ = prefs_->GetInteger(kGCMChannelPollIntervalSeconds);
if (poll_interval_seconds_ <
GCMChannelStatusRequest::min_poll_interval_seconds()) {
poll_interval_seconds_ =
GCMChannelStatusRequest::min_poll_interval_seconds();
}
last_check_time_ = base::Time::FromInternalValue(
prefs_->GetInt64(kGCMChannelLastCheckTime));
}
GCMChannelStatusSyncer::~GCMChannelStatusSyncer() {
}
void GCMChannelStatusSyncer::EnsureStarted() {
// Bail out if the request is already scheduled or started.
if (weak_ptr_factory_.HasWeakPtrs() || request_)
return;
ScheduleRequest();
}
void GCMChannelStatusSyncer::Stop() {
request_.reset();
weak_ptr_factory_.InvalidateWeakPtrs();
}
void GCMChannelStatusSyncer::OnRequestCompleted(bool enabled,
int poll_interval_seconds) {
DCHECK(request_);
request_.reset();
// Persist the current time as the last request complete time.
last_check_time_ = base::Time::Now();
prefs_->SetInt64(kGCMChannelLastCheckTime,
last_check_time_.ToInternalValue());
if (gcm_enabled_ != enabled) {
gcm_enabled_ = enabled;
prefs_->SetBoolean(kGCMChannelStatus, enabled);
if (gcm_enabled_)
driver_->Enable();
else
driver_->Disable();
}
DCHECK_GE(poll_interval_seconds,
GCMChannelStatusRequest::min_poll_interval_seconds());
if (poll_interval_seconds_ != poll_interval_seconds) {
poll_interval_seconds_ = poll_interval_seconds;
prefs_->SetInteger(kGCMChannelPollIntervalSeconds, poll_interval_seconds_);
}
ScheduleRequest();
}
void GCMChannelStatusSyncer::ScheduleRequest() {
current_request_delay_interval_ = GetRequestDelayInterval();
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&GCMChannelStatusSyncer::StartRequest,
weak_ptr_factory_.GetWeakPtr()),
current_request_delay_interval_);
}
void GCMChannelStatusSyncer::StartRequest() {
DCHECK(!request_);
request_.reset(new GCMChannelStatusRequest(
request_context_,
base::Bind(&GCMChannelStatusSyncer::OnRequestCompleted,
weak_ptr_factory_.GetWeakPtr())));
request_->Start();
}
base::TimeDelta GCMChannelStatusSyncer::GetRequestDelayInterval() const {
// No delay during testing.
if (delay_removed_for_testing_)
return base::TimeDelta();
// Make sure that checking with server occurs at polling interval, regardless
// whether the browser restarts.
int64 delay_seconds = poll_interval_seconds_ -
(base::Time::Now() - last_check_time_).InSeconds();
if (delay_seconds < 0)
delay_seconds = 0;
if (last_check_time_.is_null()) {
// For the first-time request, add a small delay to avoid sending request at
// browser startup time.
DCHECK(!delay_seconds);
delay_seconds = kFirstTimeDelaySeconds;
} else {
// Otherwise, add a fuzzing variation to the delay.
delay_seconds += base::RandInt(0, kGCMChannelRequestTimeJitterSeconds);
}
return base::TimeDelta::FromSeconds(delay_seconds);
}
} // namespace gcm
// 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 COMPONENTS_GCM_DRIVER_GCM_CHANNEL_STATUS_SYNCER_H_
#define COMPONENTS_GCM_DRIVER_GCM_CHANNEL_STATUS_SYNCER_H_
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
class PrefService;
class PrefRegistrySimple;
namespace net {
class URLRequestContextGetter;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace gcm {
class GCMChannelStatusRequest;
class GCMDriver;
// Syncing with the server for GCM channel status that controls if GCM
// functionality should be enabled or disabled.
class GCMChannelStatusSyncer {
public:
static void RegisterPrefs(PrefRegistrySimple* registry);
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
GCMChannelStatusSyncer(
GCMDriver* driver,
PrefService* prefs,
const scoped_refptr<net::URLRequestContextGetter>& request_context);
~GCMChannelStatusSyncer();
void EnsureStarted();
void Stop();
bool gcm_enabled() const { return gcm_enabled_; }
// For testing purpose.
void set_delay_removed_for_testing(bool delay_removed) {
delay_removed_for_testing_ = delay_removed;
}
base::TimeDelta current_request_delay_interval() const {
return current_request_delay_interval_;
}
static int first_time_delay_seconds();
private:
// Called when a request is completed.
void OnRequestCompleted(bool enabled, int poll_interval_seconds);
// Schedules next request to start after appropriate delay.
void ScheduleRequest();
// Creates and starts a request immediately.
void StartRequest();
// Computes and returns a delay with the fuzzing variation added if needed,
// after which the request could start.
base::TimeDelta GetRequestDelayInterval() const;
// GCMDriver owns GCMChannelStatusSyncer instance.
GCMDriver* driver_;
PrefService* prefs_;
scoped_refptr<net::URLRequestContextGetter> request_context_;
scoped_ptr<GCMChannelStatusRequest> request_;
bool gcm_enabled_;
int poll_interval_seconds_;
base::Time last_check_time_;
// The flag that indicates if the delay, including fuzzing variation and poll
// interval, is removed for testing purpose.
bool delay_removed_for_testing_;
// Tracked for testing purpose.
base::TimeDelta current_request_delay_interval_;
// Used to pass a weak pointer to a task.
base::WeakPtrFactory<GCMChannelStatusSyncer> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GCMChannelStatusSyncer);
};
} // namespace gcm
#endif // COMPONENTS_GCM_DRIVER_GCM_CHANNEL_STATUS_SYNCER_H_
......@@ -14,6 +14,7 @@
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/gcm_channel_status_syncer.h"
#include "components/gcm_driver/gcm_client_factory.h"
#include "components/gcm_driver/gcm_delayed_task_controller.h"
#include "components/gcm_driver/system_encryptor.h"
......@@ -329,18 +330,23 @@ void GCMDriverDesktop::IOWorker::RemoveAccountMapping(
GCMDriverDesktop::GCMDriverDesktop(
scoped_ptr<GCMClientFactory> gcm_client_factory,
const GCMClient::ChromeBuildInfo& chrome_build_info,
PrefService* prefs,
const base::FilePath& store_path,
const scoped_refptr<net::URLRequestContextGetter>& request_context,
const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
const scoped_refptr<base::SequencedTaskRunner>& io_thread,
const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner)
: signed_in_(false),
: gcm_channel_status_syncer_(
new GCMChannelStatusSyncer(this, prefs, request_context)),
signed_in_(false),
gcm_started_(false),
gcm_enabled_(true),
connected_(false),
ui_thread_(ui_thread),
io_thread_(io_thread),
weak_ptr_factory_(this) {
gcm_enabled_ = gcm_channel_status_syncer_->gcm_enabled();
// Create and initialize the GCMClient. Note that this does not initiate the
// GCM check-in.
io_worker_.reset(new IOWorker(ui_thread, io_thread));
......@@ -361,6 +367,12 @@ GCMDriverDesktop::~GCMDriverDesktop() {
void GCMDriverDesktop::Shutdown() {
DCHECK(ui_thread_->RunsTasksOnCurrentThread());
GCMDriver::Shutdown();
// Dispose the syncer in order to release the reference to
// URLRequestContextGetter that needs to be done before IOThread gets
// deleted.
gcm_channel_status_syncer_.reset();
io_thread_->DeleteSoon(FROM_HERE, io_worker_.release());
}
......@@ -442,6 +454,8 @@ void GCMDriverDesktop::Stop() {
if (!gcm_started_)
return;
gcm_channel_status_syncer_->Stop();
RemoveCachedData();
io_thread_->PostTask(
......@@ -627,6 +641,11 @@ GCMClient::Result GCMDriverDesktop::EnsureStarted() {
DCHECK(!delayed_task_controller_);
delayed_task_controller_.reset(new GCMDelayedTaskController);
// Polling for channel status is only needed when GCM is supported for all
// users.
if (GCMDriver::IsAllowedForAllUsers())
gcm_channel_status_syncer_->EnsureStarted();
// Note that we need to pass weak pointer again since the existing weak
// pointer in IOWorker might have been invalidated when check-out occurs.
io_thread_->PostTask(
......
......@@ -15,10 +15,13 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "components/gcm_driver/gcm_channel_status_syncer.h"
#include "components/gcm_driver/gcm_client.h"
#include "components/gcm_driver/gcm_connection_observer.h"
#include "components/gcm_driver/gcm_driver.h"
class PrefService;
namespace base {
class FilePath;
class SequencedTaskRunner;
......@@ -44,6 +47,7 @@ class GCMDriverDesktop : public GCMDriver {
GCMDriverDesktop(
scoped_ptr<GCMClientFactory> gcm_client_factory,
const GCMClient::ChromeBuildInfo& chrome_build_info,
PrefService* prefs,
const base::FilePath& store_path,
const scoped_refptr<net::URLRequestContextGetter>& request_context,
const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
......@@ -84,6 +88,12 @@ class GCMDriverDesktop : public GCMDriver {
void SetAccountsForCheckin(
const std::map<std::string, std::string>& account_tokens);
// Exposed for testing purpose.
bool gcm_enabled() const { return gcm_enabled_; }
GCMChannelStatusSyncer* gcm_channel_status_syncer_for_testing() {
return gcm_channel_status_syncer_.get();
}
protected:
// GCMDriver implementation:
virtual GCMClient::Result EnsureStarted() OVERRIDE;
......@@ -125,6 +135,8 @@ class GCMDriverDesktop : public GCMDriver {
void GetGCMStatisticsFinished(const GCMClient::GCMStatistics& stats);
scoped_ptr<GCMChannelStatusSyncer> gcm_channel_status_syncer_;
// Flag to indicate whether the user is signed in to a GAIA account.
// TODO(jianli): To be removed when sign-in enforcement is dropped.
bool signed_in_;
......@@ -133,6 +145,7 @@ class GCMDriverDesktop : public GCMDriver {
bool gcm_started_;
// Flag to indicate if GCM is enabled.
// TODO(jianli): Removed when we switch completely to support all users.
bool gcm_enabled_;
// Flag to indicate the last known state of the GCM client. Because this
......
......@@ -11,6 +11,8 @@
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/testing_pref_service.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/test/test_simple_task_runner.h"
......@@ -19,8 +21,13 @@
#include "components/gcm_driver/fake_gcm_client.h"
#include "components/gcm_driver/fake_gcm_client_factory.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/gcm_channel_status_request.h"
#include "components/gcm_driver/gcm_channel_status_syncer.h"
#include "components/gcm_driver/gcm_client_factory.h"
#include "components/gcm_driver/gcm_connection_observer.h"
#include "components/gcm_driver/proto/gcm_channel_status.pb.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -97,7 +104,7 @@ class GCMDriverTest : public testing::Test {
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
GCMDriver* driver() { return driver_.get(); }
GCMDriverDesktop* driver() { return driver_.get(); }
FakeGCMAppHandler* gcm_app_handler() { return gcm_app_handler_.get(); }
FakeGCMConnectionObserver* gcm_connection_observer() {
return gcm_connection_observer_.get();
......@@ -118,6 +125,7 @@ class GCMDriverTest : public testing::Test {
FakeGCMClient* GetGCMClient();
void CreateDriver(FakeGCMClient::StartMode gcm_client_start_mode);
void ShutdownDriver();
void AddAppHandlers();
void RemoveAppHandlers();
......@@ -142,11 +150,12 @@ class GCMDriverTest : public testing::Test {
void UnregisterCompleted(GCMClient::Result result);
base::ScopedTempDir temp_dir_;
TestingPrefServiceSimple prefs_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::MessageLoopForUI message_loop_;
base::Thread io_thread_;
base::FieldTrialList field_trial_list_;
scoped_ptr<GCMDriver> driver_;
scoped_ptr<GCMDriverDesktop> driver_;
scoped_ptr<FakeGCMAppHandler> gcm_app_handler_;
scoped_ptr<FakeGCMConnectionObserver> gcm_connection_observer_;
......@@ -174,6 +183,7 @@ GCMDriverTest::~GCMDriverTest() {
}
void GCMDriverTest::SetUp() {
GCMChannelStatusSyncer::RegisterPrefs(prefs_.registry());
io_thread_.Start();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
......@@ -182,9 +192,7 @@ void GCMDriverTest::TearDown() {
if (!driver_)
return;
if (gcm_connection_observer_.get())
driver_->RemoveConnectionObserver(gcm_connection_observer_.get());
driver_->Shutdown();
ShutdownDriver();
driver_.reset();
PumpIOLoop();
......@@ -229,6 +237,7 @@ void GCMDriverTest::CreateDriver(
base::MessageLoopProxy::current(),
io_thread_.message_loop_proxy())).Pass(),
GCMClient::ChromeBuildInfo(),
&prefs_,
temp_dir_.path(),
request_context,
base::MessageLoopProxy::current(),
......@@ -241,6 +250,12 @@ void GCMDriverTest::CreateDriver(
driver_->AddConnectionObserver(gcm_connection_observer_.get());
}
void GCMDriverTest::ShutdownDriver() {
if (gcm_connection_observer())
driver()->RemoveConnectionObserver(gcm_connection_observer());
driver()->Shutdown();
}
void GCMDriverTest::AddAppHandlers() {
driver_->AddAppHandler(kTestAppID1, gcm_app_handler_.get());
driver_->AddAppHandler(kTestAppID2, gcm_app_handler_.get());
......@@ -386,7 +401,7 @@ TEST_F(GCMDriverTest, Shutdown) {
AddAppHandlers();
EXPECT_TRUE(HasAppHandlers());
driver()->Shutdown();
ShutdownDriver();
EXPECT_FALSE(HasAppHandlers());
EXPECT_FALSE(driver()->IsConnected());
EXPECT_FALSE(gcm_connection_observer()->connected());
......@@ -941,4 +956,247 @@ TEST_F(GCMDriverFunctionalTest, MessagesDeleted) {
EXPECT_EQ(kTestAppID1, gcm_app_handler()->app_id());
}
// Tests a single instance of GCMDriver.
class GCMChannelStatusSyncerTest : public GCMDriverTest {
public:
GCMChannelStatusSyncerTest();
virtual ~GCMChannelStatusSyncerTest();
// testing::Test:
virtual void SetUp() OVERRIDE;
void CompleteGCMChannelStatusRequest(bool enabled, int poll_interval_seconds);
bool CompareDelaySeconds(bool expected_delay_seconds,
bool actual_delay_seconds);
GCMChannelStatusSyncer* syncer() {
return driver()->gcm_channel_status_syncer_for_testing();
}
private:
net::TestURLFetcherFactory url_fetcher_factory_;
DISALLOW_COPY_AND_ASSIGN(GCMChannelStatusSyncerTest);
};
GCMChannelStatusSyncerTest::GCMChannelStatusSyncerTest() {
}
GCMChannelStatusSyncerTest::~GCMChannelStatusSyncerTest() {
}
void GCMChannelStatusSyncerTest::SetUp() {
GCMDriverTest::SetUp();
// Turn on all-user support.
ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("GCM", "Enabled"));
}
void GCMChannelStatusSyncerTest::CompleteGCMChannelStatusRequest(
bool enabled, int poll_interval_seconds) {
gcm_proto::ExperimentStatusResponse response_proto;
response_proto.mutable_gcm_channel()->set_enabled(enabled);
if (poll_interval_seconds)
response_proto.set_poll_interval_seconds(poll_interval_seconds);
std::string response_string;
response_proto.SerializeToString(&response_string);
net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(response_string);
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
bool GCMChannelStatusSyncerTest::CompareDelaySeconds(
bool expected_delay_seconds, bool actual_delay_seconds) {
// Most of time, the actual delay should not be smaller than the expected
// delay.
if (actual_delay_seconds >= expected_delay_seconds)
return true;
// It is also OK that the actual delay is a bit smaller than the expected
// delay in case that the test runs slowly.
return expected_delay_seconds - actual_delay_seconds < 30;
}
TEST_F(GCMChannelStatusSyncerTest, DisableAndEnable) {
// Create GCMDriver first. GCM is not started.
CreateDriver(FakeGCMClient::NO_DELAY_START);
EXPECT_FALSE(driver()->IsStarted());
// By default, GCM is enabled.
EXPECT_TRUE(driver()->gcm_enabled());
EXPECT_TRUE(syncer()->gcm_enabled());
// Remove delay such that the request could be executed immediately.
syncer()->set_delay_removed_for_testing(true);
// GCM will be started after app handler is added.
AddAppHandlers();
EXPECT_TRUE(driver()->IsStarted());
// GCM is still enabled at this point.
EXPECT_TRUE(driver()->gcm_enabled());
EXPECT_TRUE(syncer()->gcm_enabled());
// Wait until the GCM channel status request gets triggered.
PumpUILoop();
// Complete the request that disables the GCM.
CompleteGCMChannelStatusRequest(false, 0);
EXPECT_FALSE(driver()->gcm_enabled());
EXPECT_FALSE(syncer()->gcm_enabled());
EXPECT_FALSE(driver()->IsStarted());
// Wait until next GCM channel status request gets triggered.
PumpUILoop();
// Complete the request that enables the GCM.
CompleteGCMChannelStatusRequest(true, 0);
EXPECT_TRUE(driver()->gcm_enabled());
EXPECT_TRUE(syncer()->gcm_enabled());
EXPECT_TRUE(driver()->IsStarted());
}
TEST_F(GCMChannelStatusSyncerTest, DisableAndRestart) {
// Create GCMDriver first. GCM is not started.
CreateDriver(FakeGCMClient::NO_DELAY_START);
EXPECT_FALSE(driver()->IsStarted());
// By default, GCM is enabled.
EXPECT_TRUE(driver()->gcm_enabled());
EXPECT_TRUE(syncer()->gcm_enabled());
// Remove delay such that the request could be executed immediately.
syncer()->set_delay_removed_for_testing(true);
// GCM will be started after app handler is added.
AddAppHandlers();
EXPECT_TRUE(driver()->IsStarted());
// GCM is still enabled at this point.
EXPECT_TRUE(driver()->gcm_enabled());
EXPECT_TRUE(syncer()->gcm_enabled());
// Wait until the GCM channel status request gets triggered.
PumpUILoop();
// Complete the request that disables the GCM.
CompleteGCMChannelStatusRequest(false, 0);
EXPECT_FALSE(driver()->gcm_enabled());
EXPECT_FALSE(syncer()->gcm_enabled());
EXPECT_FALSE(driver()->IsStarted());
// Simulate browser start by recreating GCMDriver.
ShutdownDriver();
CreateDriver(FakeGCMClient::NO_DELAY_START);
// GCM is still disabled.
EXPECT_FALSE(driver()->gcm_enabled());
EXPECT_FALSE(syncer()->gcm_enabled());
EXPECT_FALSE(driver()->IsStarted());
AddAppHandlers();
EXPECT_FALSE(driver()->gcm_enabled());
EXPECT_FALSE(syncer()->gcm_enabled());
EXPECT_FALSE(driver()->IsStarted());
}
TEST_F(GCMChannelStatusSyncerTest, FirstTimePolling) {
// Start GCM.
CreateDriver(FakeGCMClient::NO_DELAY_START);
AddAppHandlers();
// The 1st request should be triggered shortly without jittering.
EXPECT_EQ(GCMChannelStatusSyncer::first_time_delay_seconds(),
syncer()->current_request_delay_interval().InSeconds());
}
TEST_F(GCMChannelStatusSyncerTest, SubsequentPollingWithDefaultInterval) {
// Create GCMDriver first. GCM is not started.
CreateDriver(FakeGCMClient::NO_DELAY_START);
// Remove delay such that the request could be executed immediately.
syncer()->set_delay_removed_for_testing(true);
// Now GCM is started.
AddAppHandlers();
// Wait until the GCM channel status request gets triggered.
PumpUILoop();
// Keep delay such that we can find out the computed delay time.
syncer()->set_delay_removed_for_testing(false);
// Complete the request. The default interval is intact.
CompleteGCMChannelStatusRequest(true, 0);
// The next request should be scheduled at the expected default interval.
int64 actual_delay_seconds =
syncer()->current_request_delay_interval().InSeconds();
int64 expected_delay_seconds =
GCMChannelStatusRequest::default_poll_interval_seconds();
EXPECT_TRUE(CompareDelaySeconds(expected_delay_seconds, actual_delay_seconds))
<< "expected delay: " << expected_delay_seconds
<< " actual delay: " << actual_delay_seconds;
// Simulate browser start by recreating GCMDriver.
ShutdownDriver();
CreateDriver(FakeGCMClient::NO_DELAY_START);
AddAppHandlers();
// After start-up, the request should still be scheduled at the expected
// default interval.
actual_delay_seconds =
syncer()->current_request_delay_interval().InSeconds();
EXPECT_TRUE(CompareDelaySeconds(expected_delay_seconds, actual_delay_seconds))
<< "expected delay: " << expected_delay_seconds
<< " actual delay: " << actual_delay_seconds;
}
TEST_F(GCMChannelStatusSyncerTest, SubsequentPollingWithUpdatedInterval) {
// Create GCMDriver first. GCM is not started.
CreateDriver(FakeGCMClient::NO_DELAY_START);
// Remove delay such that the request could be executed immediately.
syncer()->set_delay_removed_for_testing(true);
// Now GCM is started.
AddAppHandlers();
// Wait until the GCM channel status request gets triggered.
PumpUILoop();
// Keep delay such that we can find out the computed delay time.
syncer()->set_delay_removed_for_testing(false);
// Complete the request. The interval is being changed.
int new_poll_interval_seconds =
GCMChannelStatusRequest::default_poll_interval_seconds() * 2;
CompleteGCMChannelStatusRequest(true, new_poll_interval_seconds);
// The next request should be scheduled at the expected updated interval.
int64 actual_delay_seconds =
syncer()->current_request_delay_interval().InSeconds();
int64 expected_delay_seconds = new_poll_interval_seconds;
EXPECT_TRUE(CompareDelaySeconds(expected_delay_seconds, actual_delay_seconds))
<< "expected delay: " << expected_delay_seconds
<< " actual delay: " << actual_delay_seconds;
// Simulate browser start by recreating GCMDriver.
ShutdownDriver();
CreateDriver(FakeGCMClient::NO_DELAY_START);
AddAppHandlers();
// After start-up, the request should still be scheduled at the expected
// updated interval.
actual_delay_seconds =
syncer()->current_request_delay_interval().InSeconds();
EXPECT_TRUE(CompareDelaySeconds(expected_delay_seconds, actual_delay_seconds))
<< "expected delay: " << expected_delay_seconds
<< " actual delay: " << actual_delay_seconds;
}
} // namespace gcm
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