diff options
author | fgorski@chromium.org <fgorski@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-17 04:52:12 +0000 |
---|---|---|
committer | fgorski@chromium.org <fgorski@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-17 04:52:12 +0000 |
commit | 7f154a57cb75adefa6741f1b157967b5eb127d7c (patch) | |
tree | 5d70a9132364974465fbf5c35bca7436f72ece2a /google_apis | |
parent | 68f404105a46cf9f09b6b5cd30170e883e71be91 (diff) | |
download | chromium_src-7f154a57cb75adefa6741f1b157967b5eb127d7c.zip chromium_src-7f154a57cb75adefa6741f1b157967b5eb127d7c.tar.gz chromium_src-7f154a57cb75adefa6741f1b157967b5eb127d7c.tar.bz2 |
Adding GServicesSettings class and tests
BUG=359254
Review URL: https://codereview.chromium.org/226923002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264419 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'google_apis')
-rw-r--r-- | google_apis/gcm/engine/gservices_settings.cc | 150 | ||||
-rw-r--r-- | google_apis/gcm/engine/gservices_settings.h | 89 | ||||
-rw-r--r-- | google_apis/gcm/engine/gservices_settings_unittest.cc | 234 | ||||
-rw-r--r-- | google_apis/gcm/gcm.gyp | 3 |
4 files changed, 476 insertions, 0 deletions
diff --git a/google_apis/gcm/engine/gservices_settings.cc b/google_apis/gcm/engine/gservices_settings.cc new file mode 100644 index 0000000..fc38e9d --- /dev/null +++ b/google_apis/gcm/engine/gservices_settings.cc @@ -0,0 +1,150 @@ +// 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 "google_apis/gcm/engine/gservices_settings.h" + +#include "base/bind.h" +#include "base/strings/string_number_conversions.h" + +namespace { +// The expected time in seconds between periodic checkins. +const char kCheckinIntervalKey[] = "checkin_interval"; +// The override URL to the checkin server. +const char kCheckinURLKey[] = "checkin_url"; +// The MCS machine name to connect to. +const char kMCSHostnameKey[] = "gcm_hostname"; +// The MCS port to connect to. +const char kMCSSecurePortKey[] = "gcm_secure_port"; +// The URL to get MCS registration IDs. +const char kRegistrationURLKey[] = "gcm_registration_url"; + +const int64 kDefaultCheckinInterval = 2 * 24 * 60 * 60; // seconds = 2 days. +const char kDefaultCheckinURL[] = "https://android.clients.google.com/checkin"; +const char kDefaultMCSHostname[] = "https://mtalk.google.com"; +const int kDefaultMCSSecurePort = 5228; +const char kDefaultRegistrationURL[] = + "https://android.clients.google.com/c2dm/register3"; + +} // namespace + +namespace gcm { + +GServicesSettings::GServicesSettings(GCMStore* gcm_store) + : gcm_store_(gcm_store), + checkin_interval_(kDefaultCheckinInterval), + checkin_url_(kDefaultCheckinURL), + mcs_hostname_(kDefaultMCSHostname), + mcs_secure_port_(kDefaultMCSSecurePort), + registration_url_(kDefaultRegistrationURL), + weak_ptr_factory_(this) { +} + +GServicesSettings::~GServicesSettings() {} + +void GServicesSettings::UpdateFromCheckinResponse( + const checkin_proto::AndroidCheckinResponse& checkin_response) { + if (!checkin_response.has_digest() || + checkin_response.digest() == digest_) { + // There are no changes as digest is the same or no settings provided. + return; + } + + std::map<std::string, std::string> settings; + for (int i = 0; i < checkin_response.setting_size(); ++i) { + std::string name = checkin_response.setting(i).name(); + std::string value = checkin_response.setting(i).value(); + settings[name] = value; + } + + // Only update the settings in store and digest, if the settings actually + // passed the verificaiton in update settings. + if (UpdateSettings(settings)) { + digest_ = checkin_response.digest(); + gcm_store_->SetGServicesSettings( + settings, + digest_, + base::Bind(&GServicesSettings::SetGServicesSettingsCallback, + weak_ptr_factory_.GetWeakPtr())); + } +} + +void GServicesSettings::UpdateFromLoadResult( + const GCMStore::LoadResult& load_result) { + if (UpdateSettings(load_result.gservices_settings)) + digest_ = load_result.gservices_digest; +} + +bool GServicesSettings::UpdateSettings( + const std::map<std::string, std::string>& settings) { + int64 new_checkin_interval = 0LL; + std::map<std::string, std::string>::const_iterator iter = + settings.find(kCheckinIntervalKey); + if (iter != settings.end()) { + if (!base::StringToInt64(iter->second, &new_checkin_interval)) { + LOG(ERROR) << "Failed to parse checkin interval: " << iter->second; + return false; + } + if (new_checkin_interval <= 0LL) { + LOG(ERROR) << "Checkin interval not positive: " << new_checkin_interval; + return false; + } + } + + std::string new_mcs_hostname; + int new_mcs_secure_port = -1; + iter = settings.find(kMCSHostnameKey); + if (iter != settings.end()) { + new_mcs_hostname = iter->second; + if (new_mcs_hostname.empty()) { + LOG(ERROR) << "Empty MCS hostname provided."; + return false; + } + + iter = settings.find(kMCSSecurePortKey); + if (iter != settings.end()) { + if (!base::StringToInt(iter->second, &new_mcs_secure_port)) { + LOG(ERROR) << "Failed to parse MCS secure port: " << iter->second; + return false; + } + if (new_mcs_secure_port < 0 || 65535 < new_mcs_secure_port) { + LOG(ERROR) << "Incorrect port value: " << new_mcs_secure_port; + return false; + } + } + } + + std::string new_checkin_url; + iter = settings.find(kCheckinURLKey); + if (iter != settings.end()) { + new_checkin_url = iter->second; + if (new_checkin_url.empty()) { + LOG(ERROR) << "Empty checkin URL provided."; + return false; + } + } + + std::string new_registration_url; + iter = settings.find(kRegistrationURLKey); + if (iter != settings.end()) { + new_registration_url = iter->second; + if (new_registration_url.empty()) { + LOG(ERROR) << "Empty registration URL provided."; + return false; + } + } + + // We only update the settings once all of them are correct. + checkin_interval_ = new_checkin_interval; + mcs_hostname_ = new_mcs_hostname; + mcs_secure_port_ = new_mcs_secure_port; + checkin_url_ = new_checkin_url; + registration_url_ = new_registration_url; + return true; +} + +void GServicesSettings::SetGServicesSettingsCallback(bool success) { + DCHECK(success); +} + +} // namespace gcm diff --git a/google_apis/gcm/engine/gservices_settings.h b/google_apis/gcm/engine/gservices_settings.h new file mode 100644 index 0000000..db3c6b0 --- /dev/null +++ b/google_apis/gcm/engine/gservices_settings.h @@ -0,0 +1,89 @@ +// 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 GOOGLE_APIS_GCM_ENGINE_GSERVICES_SETTINGS_H_ +#define GOOGLE_APIS_GCM_ENGINE_GSERVICES_SETTINGS_H_ + +#include <map> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "google_apis/gcm/base/gcm_export.h" +#include "google_apis/gcm/engine/gcm_store.h" +#include "google_apis/gcm/protocol/checkin.pb.h" + +namespace gcm { + +// Class responsible for handling G-services settings. It takes care of +// extracting them from checkin response and storing in GCMStore. +class GCM_EXPORT GServicesSettings { + public: + // Create an instance of GServicesSettings class. |gcm_store| is used to store + // the settings after they are extracted from checkin response. + explicit GServicesSettings(GCMStore* gcm_store); + ~GServicesSettings(); + + // Udpates the settings based on |checkin_response|. + void UpdateFromCheckinResponse( + const checkin_proto::AndroidCheckinResponse& checkin_response); + + // Updates the settings based on |load_result|. + void UpdateFromLoadResult(const GCMStore::LoadResult& load_result); + + const std::string& digest() const { return digest_; } + + // TODO(fgorski): Consider returning TimeDelta. + int64 checkin_interval() const { return checkin_interval_; } + + // TODO(fgorski): Consider returning GURL and use it for validation. + const std::string& checkin_url() const { return checkin_url_; } + + // TODO(fgorski): Consider returning GURL and use it for validation. + const std::string& mcs_hostname() const { return mcs_hostname_; } + + int mcs_secure_port() const { return mcs_secure_port_; } + + // TODO(fgorski): Consider returning GURL and use it for validation. + const std::string& registration_url() const { return registration_url_; } + + private: + // Parses the |settings| to fill in specific fields. + // TODO(fgorski): Change to a status variable that can be logged to UMA. + bool UpdateSettings(const std::map<std::string, std::string>& settings); + + // Callback passed to GCMStore::SetGServicesSettings. + void SetGServicesSettingsCallback(bool success); + + // GCM store to persist the settings. Not owned. + GCMStore* gcm_store_; + + // Digest (hash) of the settings, used to check whether settings need update. + // It is meant to be sent with checkin request, instead of sending the whole + // settings table. + std::string digest_; + + // Time in seconds between periodic checkins. + int64 checkin_interval_; + + // URL that should be used for checkins. + std::string checkin_url_; + + // Hostname of the MCS server. + std::string mcs_hostname_; + + // Secure port to connect to on MCS sever. + int mcs_secure_port_; + + // URL that should be used for regisrations and unregistrations. + std::string registration_url_; + + // Factory for creating references in callbacks. + base::WeakPtrFactory<GServicesSettings> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(GServicesSettings); +}; + +} // namespace gcm + +#endif // GOOGLE_APIS_GCM_ENGINE_GSERVICES_SETTINGS_H_ diff --git a/google_apis/gcm/engine/gservices_settings_unittest.cc b/google_apis/gcm/engine/gservices_settings_unittest.cc new file mode 100644 index 0000000..ada4194 --- /dev/null +++ b/google_apis/gcm/engine/gservices_settings_unittest.cc @@ -0,0 +1,234 @@ +// 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/string_number_conversions.h" +#include "google_apis/gcm/engine/gservices_settings.h" +#include "google_apis/gcm/engine/registration_info.h" +#include "google_apis/gcm/gcm_client.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gcm { + +namespace { + +const int64 kAlternativeCheckinInterval = 2000LL; +const char kAlternativeCheckinURL[] = "http://alternative.url/checkin"; +const char kAlternativeMCSHostname[] = "http://alternative.gcm.host"; +const int kAlternativeMCSSecurePort = 443; +const char kAlternativeRegistrationURL[] = + "http://alternative.url/registration"; + +const int64 kDefaultCheckinInterval = 2 * 24 * 60 * 60; // seconds = 2 days. +const char kDefaultCheckinURL[] = "https://android.clients.google.com/checkin"; +const char kDefaultMCSHostname[] = "https://mtalk.google.com"; +const int kDefaultMCSSecurePort = 5228; +const char kDefaultRegistrationURL[] = + "https://android.clients.google.com/c2dm/register3"; + +class FakeGCMStore : public GCMStore { + public: + FakeGCMStore(); + virtual ~FakeGCMStore(); + + virtual void Load(const gcm::GCMStore::LoadCallback& callback) OVERRIDE {} + virtual void Close() OVERRIDE {} + virtual void Destroy(const gcm::GCMStore::UpdateCallback& callback) OVERRIDE { + } + virtual void SetDeviceCredentials( + uint64 device_android_id, + uint64 device_security_token, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void AddRegistration( + const std::string& app_id, + const linked_ptr<gcm::RegistrationInfo>& registration, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void RemoveRegistration( + const std::string& app_id, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void AddIncomingMessage( + const std::string& persistent_id, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void RemoveIncomingMessage( + const std::string& persistent_id, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void RemoveIncomingMessages( + const PersistentIdList& persistent_ids, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual bool AddOutgoingMessage( + const std::string& persistent_id, + const gcm::MCSMessage& message, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE { + return true; + } + virtual void OverwriteOutgoingMessage( + const std::string& persistent_id, + const gcm::MCSMessage& message, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void RemoveOutgoingMessage( + const std::string& persistent_id, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void RemoveOutgoingMessages( + const PersistentIdList& persistent_ids, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + virtual void SetLastCheckinTime( + const base::Time& last_checkin_time, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE {} + + // G-service settings handling. + virtual void SetGServicesSettings( + const std::map<std::string, std::string>& settings, + const std::string& settings_digest, + const gcm::GCMStore::UpdateCallback& callback) OVERRIDE { + settings_saved_ = true; + } + + void Reset() { + settings_saved_ = false; + } + + bool settings_saved() const { return settings_saved_; } + + private: + bool settings_saved_; +}; + +FakeGCMStore::FakeGCMStore() : settings_saved_(false) {} + +FakeGCMStore::~FakeGCMStore() {} + +} // namespace + +class GServicesSettingsTest : public testing::Test { + public: + GServicesSettingsTest(); + virtual ~GServicesSettingsTest(); + + virtual void SetUp() OVERRIDE; + + void CheckAllSetToDefault(); + void CheckAllSetToAlternative(); + void SetWithAlternativeSettings( + checkin_proto::AndroidCheckinResponse& checkin_response); + + GServicesSettings& settings() { + return gserivces_settings_; + } + + const std::map<std::string, std::string>& alternative_settings() { + return alternative_settings_; + } + + FakeGCMStore& gcm_store() { return gcm_store_; } + + private: + FakeGCMStore gcm_store_; + GServicesSettings gserivces_settings_; + std::map<std::string, std::string> alternative_settings_; +}; + +GServicesSettingsTest::GServicesSettingsTest() + : gserivces_settings_(&gcm_store_) { +} + +GServicesSettingsTest::~GServicesSettingsTest() {} + +void GServicesSettingsTest::SetUp() { + alternative_settings_["checkin_interval"] = + base::Int64ToString(kAlternativeCheckinInterval); + alternative_settings_["checkin_url"] = kAlternativeCheckinURL; + alternative_settings_["gcm_hostname"] = kAlternativeMCSHostname; + alternative_settings_["gcm_secure_port"] = + base::IntToString(kAlternativeMCSSecurePort); + alternative_settings_["gcm_registration_url"] = kAlternativeRegistrationURL; +} + +void GServicesSettingsTest::CheckAllSetToDefault() { + EXPECT_EQ(kDefaultCheckinInterval, settings().checkin_interval()); + EXPECT_EQ(kDefaultCheckinURL, settings().checkin_url()); + EXPECT_EQ(kDefaultMCSHostname, settings().mcs_hostname()); + EXPECT_EQ(kDefaultMCSSecurePort, settings().mcs_secure_port()); + EXPECT_EQ(kDefaultRegistrationURL, settings().registration_url()); +} + +void GServicesSettingsTest::CheckAllSetToAlternative() { + EXPECT_EQ(kAlternativeCheckinInterval, settings().checkin_interval()); + EXPECT_EQ(kAlternativeCheckinURL, settings().checkin_url()); + EXPECT_EQ(kAlternativeMCSHostname, settings().mcs_hostname()); + EXPECT_EQ(kAlternativeMCSSecurePort, settings().mcs_secure_port()); + EXPECT_EQ(kAlternativeRegistrationURL, settings().registration_url()); +} + +void GServicesSettingsTest::SetWithAlternativeSettings( + checkin_proto::AndroidCheckinResponse& checkin_response) { + for (std::map<std::string, std::string>::const_iterator iter = + alternative_settings_.begin(); + iter != alternative_settings_.end(); ++iter) { + checkin_proto::GservicesSetting* setting = checkin_response.add_setting(); + setting->set_name(iter->first); + setting->set_value(iter->second); + } +} + +// Verifies default values of the G-services settings and settings digest. +TEST_F(GServicesSettingsTest, DefaultSettingsAndDigest) { + CheckAllSetToDefault(); + EXPECT_EQ(std::string(), settings().digest()); +} + +// Verifies that the settings are set correctly based on the load result. +TEST_F(GServicesSettingsTest, UpdateFromLoadResult) { + GCMStore::LoadResult result; + result.gservices_settings = alternative_settings(); + result.gservices_digest = "digest_value"; + settings().UpdateFromLoadResult(result); + + CheckAllSetToAlternative(); + EXPECT_EQ("digest_value", settings().digest()); +} + +// Verifies that the settings are set correctly after parsing a checkin +// response. +TEST_F(GServicesSettingsTest, UpdateFromCheckinResponse) { + checkin_proto::AndroidCheckinResponse checkin_response; + + checkin_response.set_digest("digest_value"); + SetWithAlternativeSettings(checkin_response); + + settings().UpdateFromCheckinResponse(checkin_response); + EXPECT_TRUE(gcm_store().settings_saved()); + + CheckAllSetToAlternative(); + EXPECT_EQ("digest_value", settings().digest()); +} + +// Verifies that no update is done, when a checkin response misses digest. +TEST_F(GServicesSettingsTest, UpdateFromCheckinResponseNoDigest) { + checkin_proto::AndroidCheckinResponse checkin_response; + + SetWithAlternativeSettings(checkin_response); + settings().UpdateFromCheckinResponse(checkin_response); + EXPECT_FALSE(gcm_store().settings_saved()); + + CheckAllSetToDefault(); + EXPECT_EQ(std::string(), settings().digest()); +} + +// Verifies that no update is done, when a checkin response digest is the same. +TEST_F(GServicesSettingsTest, UpdateFromCheckinResponseSameDigest) { + GCMStore::LoadResult load_result; + load_result.gservices_digest = "old_digest"; + load_result.gservices_settings = alternative_settings(); + settings().UpdateFromLoadResult(load_result); + + checkin_proto::AndroidCheckinResponse checkin_response; + checkin_response.set_digest("old_digest"); + SetWithAlternativeSettings(checkin_response); + settings().UpdateFromCheckinResponse(checkin_response); + EXPECT_FALSE(gcm_store().settings_saved()); + + CheckAllSetToAlternative(); + EXPECT_EQ("old_digest", settings().digest()); +} + +} // namespace gcm diff --git a/google_apis/gcm/gcm.gyp b/google_apis/gcm/gcm.gyp index 9843776..c065818 100644 --- a/google_apis/gcm/gcm.gyp +++ b/google_apis/gcm/gcm.gyp @@ -58,6 +58,8 @@ 'engine/gcm_store.h', 'engine/gcm_store_impl.cc', 'engine/gcm_store_impl.h', + 'engine/gservices_settings.cc', + 'engine/gservices_settings.h', 'engine/heartbeat_manager.cc', 'engine/heartbeat_manager.h', 'engine/mcs_client.cc', @@ -134,6 +136,7 @@ 'engine/fake_connection_handler.cc', 'engine/fake_connection_handler.h', 'engine/gcm_store_impl_unittest.cc', + 'engine/gservices_settings_unittest.cc', 'engine/heartbeat_manager_unittest.cc', 'engine/mcs_client_unittest.cc', 'engine/registration_request_unittest.cc', |