Commit cb9c0005 authored by fgorski@chromium.org's avatar fgorski@chromium.org

GCM Checkin implementation with unit tests.

BUG=284553

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243729 0039d316-1c4b-4281-b951-d872f2087c98
parent 10390105
...@@ -47,9 +47,9 @@ void GCMClientMock::CheckIn(const std::string& username) { ...@@ -47,9 +47,9 @@ void GCMClientMock::CheckIn(const std::string& username) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
// Simulate the android_id and secret by some sort of hashing. // Simulate the android_id and secret by some sort of hashing.
CheckInInfo checkin_info; CheckinInfo checkin_info;
if (!simulate_server_error_) if (!simulate_server_error_)
checkin_info = GetCheckInInfoFromUsername(username); checkin_info = GetCheckinInfoFromUsername(username);
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
FROM_HERE, FROM_HERE,
...@@ -146,9 +146,9 @@ void GCMClientMock::SetIsLoading(bool is_loading) { ...@@ -146,9 +146,9 @@ void GCMClientMock::SetIsLoading(bool is_loading) {
} }
// static // static
GCMClient::CheckInInfo GCMClientMock::GetCheckInInfoFromUsername( GCMClient::CheckinInfo GCMClientMock::GetCheckinInfoFromUsername(
const std::string& username) { const std::string& username) {
CheckInInfo checkin_info; CheckinInfo checkin_info;
checkin_info.android_id = HashToUInt64(username); checkin_info.android_id = HashToUInt64(username);
checkin_info.secret = checkin_info.android_id / 10; checkin_info.secret = checkin_info.android_id / 10;
return checkin_info; return checkin_info;
...@@ -181,7 +181,7 @@ GCMClient::Delegate* GCMClientMock::GetDelegate( ...@@ -181,7 +181,7 @@ GCMClient::Delegate* GCMClientMock::GetDelegate(
} }
void GCMClientMock::CheckInFinished(std::string username, void GCMClientMock::CheckInFinished(std::string username,
CheckInInfo checkin_info) { CheckinInfo checkin_info) {
GetDelegate(username)->OnCheckInFinished( GetDelegate(username)->OnCheckInFinished(
checkin_info, checkin_info.IsValid() ? SUCCESS : SERVER_ERROR); checkin_info, checkin_info.IsValid() ? SUCCESS : SERVER_ERROR);
} }
......
...@@ -47,7 +47,7 @@ class GCMClientMock : public GCMClient { ...@@ -47,7 +47,7 @@ class GCMClientMock : public GCMClient {
void SetIsLoading(bool is_loading); void SetIsLoading(bool is_loading);
static CheckInInfo GetCheckInInfoFromUsername(const std::string& username); static CheckinInfo GetCheckinInfoFromUsername(const std::string& username);
static std::string GetRegistrationIdFromSenderIds( static std::string GetRegistrationIdFromSenderIds(
const std::vector<std::string>& sender_ids); const std::vector<std::string>& sender_ids);
...@@ -55,7 +55,8 @@ class GCMClientMock : public GCMClient { ...@@ -55,7 +55,8 @@ class GCMClientMock : public GCMClient {
Delegate* GetDelegate(const std::string& username) const; Delegate* GetDelegate(const std::string& username) const;
// Called on IO thread. // Called on IO thread.
void CheckInFinished(std::string username, CheckInInfo checkin_info); // TODO(fgorski): Update parameters to const ref.
void CheckInFinished(std::string username, CheckinInfo checkin_info);
void RegisterFinished(std::string username, void RegisterFinished(std::string username,
std::string app_id, std::string app_id,
std::string registrion_id); std::string registrion_id);
......
...@@ -166,7 +166,7 @@ class GCMProfileService::IOWorker ...@@ -166,7 +166,7 @@ class GCMProfileService::IOWorker
// Overridden from GCMClient::Delegate: // Overridden from GCMClient::Delegate:
// Called from IO thread. // Called from IO thread.
virtual void OnCheckInFinished(const GCMClient::CheckInInfo& checkin_info, virtual void OnCheckInFinished(const GCMClient::CheckinInfo& checkin_info,
GCMClient::Result result) OVERRIDE; GCMClient::Result result) OVERRIDE;
virtual void OnRegisterFinished(const std::string& app_id, virtual void OnRegisterFinished(const std::string& app_id,
const std::string& registration_id, const std::string& registration_id,
...@@ -181,7 +181,7 @@ class GCMProfileService::IOWorker ...@@ -181,7 +181,7 @@ class GCMProfileService::IOWorker
virtual void OnMessageSendError(const std::string& app_id, virtual void OnMessageSendError(const std::string& app_id,
const std::string& message_id, const std::string& message_id,
GCMClient::Result result) OVERRIDE; GCMClient::Result result) OVERRIDE;
virtual GCMClient::CheckInInfo GetCheckInInfo() const OVERRIDE; virtual GCMClient::CheckinInfo GetCheckinInfo() const OVERRIDE;
virtual void OnLoadingCompleted() OVERRIDE; virtual void OnLoadingCompleted() OVERRIDE;
virtual base::TaskRunner* GetFileTaskRunner() OVERRIDE; virtual base::TaskRunner* GetFileTaskRunner() OVERRIDE;
...@@ -189,7 +189,8 @@ class GCMProfileService::IOWorker ...@@ -189,7 +189,8 @@ class GCMProfileService::IOWorker
void SetUser(const std::string& username); void SetUser(const std::string& username);
void RemoveUser(const std::string& username); void RemoveUser(const std::string& username);
void CheckIn(); void CheckIn();
void SetCheckInInfo(GCMClient::CheckInInfo checkin_info); // TODO(fgorski): Update to pass by const ref.
void SetCheckinInfo(GCMClient::CheckinInfo checkin_info);
void CheckOut(); void CheckOut();
void Register(const std::string& app_id, void Register(const std::string& app_id,
const std::vector<std::string>& sender_ids, const std::vector<std::string>& sender_ids,
...@@ -210,7 +211,7 @@ class GCMProfileService::IOWorker ...@@ -210,7 +211,7 @@ class GCMProfileService::IOWorker
// The checkin info obtained from the server for the signed in user associated // The checkin info obtained from the server for the signed in user associated
// with the profile. // with the profile.
GCMClient::CheckInInfo checkin_info_; GCMClient::CheckinInfo checkin_info_;
}; };
GCMProfileService::IOWorker::IOWorker( GCMProfileService::IOWorker::IOWorker(
...@@ -222,7 +223,7 @@ GCMProfileService::IOWorker::~IOWorker() { ...@@ -222,7 +223,7 @@ GCMProfileService::IOWorker::~IOWorker() {
} }
void GCMProfileService::IOWorker::OnCheckInFinished( void GCMProfileService::IOWorker::OnCheckInFinished(
const GCMClient::CheckInInfo& checkin_info, const GCMClient::CheckinInfo& checkin_info,
GCMClient::Result result) { GCMClient::Result result) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
...@@ -310,7 +311,7 @@ void GCMProfileService::IOWorker::OnMessageSendError( ...@@ -310,7 +311,7 @@ void GCMProfileService::IOWorker::OnMessageSendError(
result)); result));
} }
GCMClient::CheckInInfo GCMProfileService::IOWorker::GetCheckInInfo() const { GCMClient::CheckinInfo GCMProfileService::IOWorker::GetCheckinInfo() const {
return checkin_info_; return checkin_info_;
} }
...@@ -360,8 +361,8 @@ void GCMProfileService::IOWorker::CheckIn() { ...@@ -360,8 +361,8 @@ void GCMProfileService::IOWorker::CheckIn() {
GCMClient::Get()->CheckIn(username_); GCMClient::Get()->CheckIn(username_);
} }
void GCMProfileService::IOWorker::SetCheckInInfo( void GCMProfileService::IOWorker::SetCheckinInfo(
GCMClient::CheckInInfo checkin_info) { GCMClient::CheckinInfo checkin_info) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
checkin_info_ = checkin_info; checkin_info_ = checkin_info;
...@@ -670,13 +671,13 @@ void GCMProfileService::AddUser(const std::string& username) { ...@@ -670,13 +671,13 @@ void GCMProfileService::AddUser(const std::string& username) {
Encryptor::DecryptString(encrypted_secret, &decrypted_secret); Encryptor::DecryptString(encrypted_secret, &decrypted_secret);
uint64 secret = 0; uint64 secret = 0;
if (base::StringToUint64(decrypted_secret, &secret) && secret) { if (base::StringToUint64(decrypted_secret, &secret) && secret) {
GCMClient::CheckInInfo checkin_info; GCMClient::CheckinInfo checkin_info;
checkin_info.android_id = android_id; checkin_info.android_id = android_id;
checkin_info.secret = secret; checkin_info.secret = secret;
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, content::BrowserThread::IO,
FROM_HERE, FROM_HERE,
base::Bind(&GCMProfileService::IOWorker::SetCheckInInfo, base::Bind(&GCMProfileService::IOWorker::SetCheckinInfo,
io_worker_, io_worker_,
checkin_info)); checkin_info));
...@@ -735,7 +736,7 @@ void GCMProfileService::Unregister(const std::string& app_id) { ...@@ -735,7 +736,7 @@ void GCMProfileService::Unregister(const std::string& app_id) {
app_id)); app_id));
} }
void GCMProfileService::CheckInFinished(GCMClient::CheckInInfo checkin_info, void GCMProfileService::CheckInFinished(GCMClient::CheckinInfo checkin_info,
GCMClient::Result result) { GCMClient::Result result) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
......
...@@ -50,7 +50,7 @@ class GCMProfileService : public BrowserContextKeyedService, ...@@ -50,7 +50,7 @@ class GCMProfileService : public BrowserContextKeyedService,
class TestingDelegate { class TestingDelegate {
public: public:
virtual GCMEventRouter* GetEventRouter() const = 0; virtual GCMEventRouter* GetEventRouter() const = 0;
virtual void CheckInFinished(const GCMClient::CheckInInfo& checkin_info, virtual void CheckInFinished(const GCMClient::CheckinInfo& checkin_info,
GCMClient::Result result) = 0; GCMClient::Result result) = 0;
}; };
...@@ -140,7 +140,8 @@ class GCMProfileService : public BrowserContextKeyedService, ...@@ -140,7 +140,8 @@ class GCMProfileService : public BrowserContextKeyedService,
const GCMClient::OutgoingMessage& message); const GCMClient::OutgoingMessage& message);
// Callbacks posted from IO thread to UI thread. // Callbacks posted from IO thread to UI thread.
void CheckInFinished(GCMClient::CheckInInfo checkin_info, // TODO(fgorski): Update parameters to be passed by const ref.
void CheckInFinished(GCMClient::CheckinInfo checkin_info,
GCMClient::Result result); GCMClient::Result result);
void RegisterFinished(std::string app_id, void RegisterFinished(std::string app_id,
std::string registration_id, std::string registration_id,
......
...@@ -168,7 +168,7 @@ class GCMProfileServiceTest : public testing::Test, ...@@ -168,7 +168,7 @@ class GCMProfileServiceTest : public testing::Test,
return gcm_event_router_mock_.get(); return gcm_event_router_mock_.get();
} }
virtual void CheckInFinished(const GCMClient::CheckInInfo& checkin_info, virtual void CheckInFinished(const GCMClient::CheckinInfo& checkin_info,
GCMClient::Result result) OVERRIDE { GCMClient::Result result) OVERRIDE {
checkin_info_ = checkin_info; checkin_info_ = checkin_info;
SignalCompleted(); SignalCompleted();
...@@ -229,7 +229,7 @@ class GCMProfileServiceTest : public testing::Test, ...@@ -229,7 +229,7 @@ class GCMProfileServiceTest : public testing::Test,
ExtensionService* extension_service_; // Not owned. ExtensionService* extension_service_; // Not owned.
scoped_ptr<base::RunLoop> run_loop_; scoped_ptr<base::RunLoop> run_loop_;
scoped_ptr<GCMEventRouterMock> gcm_event_router_mock_; scoped_ptr<GCMEventRouterMock> gcm_event_router_mock_;
GCMClient::CheckInInfo checkin_info_; GCMClient::CheckinInfo checkin_info_;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
...@@ -300,8 +300,8 @@ void GCMEventRouterMock::OnSendError(const std::string& app_id, ...@@ -300,8 +300,8 @@ void GCMEventRouterMock::OnSendError(const std::string& app_id,
TEST_F(GCMProfileServiceTest, CheckIn) { TEST_F(GCMProfileServiceTest, CheckIn) {
EXPECT_TRUE(checkin_info_.IsValid()); EXPECT_TRUE(checkin_info_.IsValid());
GCMClient::CheckInInfo expected_checkin_info = GCMClient::CheckinInfo expected_checkin_info =
GCMClientMock::GetCheckInInfoFromUsername(kTestingUsername); GCMClientMock::GetCheckinInfoFromUsername(kTestingUsername);
EXPECT_EQ(expected_checkin_info.android_id, checkin_info_.android_id); EXPECT_EQ(expected_checkin_info.android_id, checkin_info_.android_id);
EXPECT_EQ(expected_checkin_info.secret, checkin_info_.secret); EXPECT_EQ(expected_checkin_info.secret, checkin_info_.secret);
} }
...@@ -309,7 +309,7 @@ TEST_F(GCMProfileServiceTest, CheckIn) { ...@@ -309,7 +309,7 @@ TEST_F(GCMProfileServiceTest, CheckIn) {
TEST_F(GCMProfileServiceTest, CheckInFromPrefsStore) { TEST_F(GCMProfileServiceTest, CheckInFromPrefsStore) {
// The first check-in should be successful. // The first check-in should be successful.
EXPECT_TRUE(checkin_info_.IsValid()); EXPECT_TRUE(checkin_info_.IsValid());
GCMClient::CheckInInfo saved_checkin_info = checkin_info_; GCMClient::CheckinInfo saved_checkin_info = checkin_info_;
checkin_info_.Reset(); checkin_info_.Reset();
// Check-in should not reach the server. Forcing GCMClient server error should // Check-in should not reach the server. Forcing GCMClient server error should
......
// 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/checkin_request.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "google_apis/gcm/protocol/checkin.pb.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
namespace gcm {
namespace {
const char kCheckinURL[] = "https://android.clients.google.com/checkin";
const char kRequestContentType[] = "application/x-protobuf";
const int kRequestVersionValue = 2;
} // namespace
CheckinRequest::CheckinRequest(
const CheckinRequestCallback& callback,
const checkin_proto::ChromeBuildProto& chrome_build_proto,
int64 user_serial_number,
uint64 android_id,
uint64 security_token,
net::URLRequestContextGetter* request_context_getter)
: request_context_getter_(request_context_getter),
callback_(callback),
chrome_build_proto_(chrome_build_proto),
android_id_(android_id),
security_token_(security_token),
user_serial_number_(user_serial_number) {}
CheckinRequest::~CheckinRequest() {}
void CheckinRequest::Start() {
DCHECK(!url_fetcher_.get());
checkin_proto::AndroidCheckinRequest request;
request.set_id(android_id_);
request.set_security_token(security_token_);
request.set_user_serial_number(user_serial_number_);
request.set_version(kRequestVersionValue);
checkin_proto::AndroidCheckinProto* checkin = request.mutable_checkin();
checkin->mutable_chrome_build()->CopyFrom(chrome_build_proto_);
#if defined(CHROME_OS)
checkin->set_type(checkin_proto::DEVICE_CHROME_OS);
#else
checkin->set_type(checkin_proto::DEVICE_CHROME_BROWSER);
#endif
std::string upload_data;
CHECK(request.SerializeToString(&upload_data));
url_fetcher_.reset(
net::URLFetcher::Create(GURL(kCheckinURL), net::URLFetcher::POST, this));
url_fetcher_->SetRequestContext(request_context_getter_);
url_fetcher_->SetUploadData(kRequestContentType, upload_data);
url_fetcher_->Start();
}
void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) {
std::string response_string;
checkin_proto::AndroidCheckinResponse response_proto;
if (!source->GetStatus().is_success() ||
source->GetResponseCode() != net::HTTP_OK ||
!source->GetResponseAsString(&response_string) ||
!response_proto.ParseFromString(response_string)) {
LOG(ERROR) << "Failed to get checkin response.";
// TODO(fgorski): Handle retry logic for certain responses.
callback_.Run(0, 0);
return;
}
if (!response_proto.has_android_id() ||
!response_proto.has_security_token() ||
response_proto.android_id() == 0 ||
response_proto.security_token() == 0) {
LOG(ERROR) << "Badly formatted checkin response.";
callback_.Run(0, 0);
return;
}
callback_.Run(response_proto.android_id(), response_proto.security_token());
}
} // 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 GOOGLE_APIS_GCM_ENGINE_CHECKIN_REQUEST_H_
#define GOOGLE_APIS_GCM_ENGINE_CHECKIN_REQUEST_H_
#include "base/basictypes.h"
#include "base/callback.h"
#include "google_apis/gcm/base/gcm_export.h"
#include "google_apis/gcm/protocol/android_checkin.pb.h"
#include "net/url_request/url_fetcher_delegate.h"
namespace net {
class URLRequestContextGetter;
}
namespace gcm {
// Enables making check-in requests with the GCM infrastructure. When called
// with android_id and security_token both set to 0 it is an initial check-in
// used to obtain credentials. These should be persisted and used for subsequent
// check-ins.
class GCM_EXPORT CheckinRequest : public net::URLFetcherDelegate {
public:
// A callback function for the checkin request, accepting |android_id| and
// |security_token|.
typedef base::Callback<void(uint64 android_id, uint64 security_token)>
CheckinRequestCallback;
CheckinRequest(const CheckinRequestCallback& callback,
const checkin_proto::ChromeBuildProto& chrome_build_proto,
int64 user_serial_number,
uint64 android_id,
uint64 secret_token,
net::URLRequestContextGetter* request_context_getter);
virtual ~CheckinRequest();
void Start();
// URLFetcherDelegate implementation.
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
private:
net::URLRequestContextGetter* request_context_getter_;
CheckinRequestCallback callback_;
scoped_ptr<net::URLFetcher> url_fetcher_;
checkin_proto::ChromeBuildProto chrome_build_proto_;
uint64 android_id_;
uint64 security_token_;
int64 user_serial_number_;
DISALLOW_COPY_AND_ASSIGN(CheckinRequest);
};
} // namespace gcm
#endif // GOOGLE_APIS_GCM_ENGINE_CHECKIN_REQUEST_H_
// 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 <string>
#include "google_apis/gcm/engine/checkin_request.h"
#include "google_apis/gcm/protocol/checkin.pb.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gcm {
const uint64 kAndroidId = 42UL;
const uint64 kBlankAndroidId = 999999UL;
const uint64 kBlankSecurityToken = 999999UL;
const char kChromeVersion[] = "Version String";
const uint64 kSecurityToken = 77;
const int64 kUserSerialNumber = 7;
class CheckinRequestTest : public testing::Test {
public:
enum ResponseScenario {
VALID_RESPONSE, // Both android_id and security_token set in response.
MISSING_ANDROID_ID, // android_id is missing.
MISSING_SECURITY_TOKEN, // security_token is missing.
ANDROID_ID_IS_ZER0, // android_id is 0.
SECURITY_TOKEN_IS_ZERO // security_token is 0.
};
CheckinRequestTest();
virtual ~CheckinRequestTest();
void FetcherCallback(uint64 android_id, uint64 security_token);
void CreateRequest(uint64 android_id, uint64 security_token);
void SetResponseStatusAndString(
net::HttpStatusCode status_code,
const std::string& response_data);
void CompleteFetch();
void SetResponse(ResponseScenario response_scenario);
protected:
uint64 android_id_;
uint64 security_token_;
int checkin_device_type_;
base::MessageLoop message_loop_;
net::TestURLFetcherFactory url_fetcher_factory_;
scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_;
checkin_proto::ChromeBuildProto chrome_build_proto_;
scoped_ptr<CheckinRequest> request_;
};
CheckinRequestTest::CheckinRequestTest()
: android_id_(kBlankAndroidId),
security_token_(kBlankSecurityToken),
checkin_device_type_(0),
url_request_context_getter_(new net::TestURLRequestContextGetter(
message_loop_.message_loop_proxy())) {}
CheckinRequestTest::~CheckinRequestTest() {}
void CheckinRequestTest::FetcherCallback(uint64 android_id,
uint64 security_token) {
android_id_ = android_id;
security_token_ = security_token;
}
void CheckinRequestTest::CreateRequest(uint64 android_id,
uint64 security_token) {
// First setup a chrome_build protobuf.
chrome_build_proto_.set_platform(
checkin_proto::ChromeBuildProto::PLATFORM_LINUX);
chrome_build_proto_.set_channel(
checkin_proto::ChromeBuildProto::CHANNEL_CANARY);
chrome_build_proto_.set_chrome_version(kChromeVersion);
// Then create a request with that protobuf and specified android_id,
// security_token.
request_.reset(new CheckinRequest(
base::Bind(&CheckinRequestTest::FetcherCallback,
base::Unretained(this)),
chrome_build_proto_,
kUserSerialNumber,
android_id,
security_token,
url_request_context_getter_.get()));
// Setting android_id_ and security_token_ to blank value, not used elsewhere
// in the tests.
android_id_ = kBlankAndroidId;
security_token_ = kBlankSecurityToken;
}
void CheckinRequestTest::SetResponseStatusAndString(
net::HttpStatusCode status_code,
const std::string& response_data) {
net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(status_code);
fetcher->SetResponseString(response_data);
}
void CheckinRequestTest::CompleteFetch() {
net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
void CheckinRequestTest::SetResponse(ResponseScenario response_scenario) {
checkin_proto::AndroidCheckinResponse response;
response.set_stats_ok(true);
uint64 android_id = response_scenario == ANDROID_ID_IS_ZER0 ? 0 : kAndroidId;
uint64 security_token =
response_scenario == SECURITY_TOKEN_IS_ZERO ? 0 : kSecurityToken;
if (response_scenario != MISSING_ANDROID_ID)
response.set_android_id(android_id);
if (response_scenario != MISSING_SECURITY_TOKEN)
response.set_security_token(security_token);
std::string response_string;
response.SerializeToString(&response_string);
SetResponseStatusAndString(net::HTTP_OK, response_string);
}
TEST_F(CheckinRequestTest, FetcherData) {
CreateRequest(kAndroidId, kSecurityToken);
request_->Start();
// Get data sent by request.
net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
checkin_proto::AndroidCheckinRequest request_proto;
request_proto.ParseFromString(fetcher->upload_data());
EXPECT_EQ(kAndroidId, static_cast<uint64>(request_proto.id()));
EXPECT_EQ(kSecurityToken, request_proto.security_token());
EXPECT_EQ(kUserSerialNumber, request_proto.user_serial_number());
EXPECT_EQ(chrome_build_proto_.platform(),
request_proto.checkin().chrome_build().platform());
EXPECT_EQ(chrome_build_proto_.chrome_version(),
request_proto.checkin().chrome_build().chrome_version());
EXPECT_EQ(chrome_build_proto_.channel(),
request_proto.checkin().chrome_build().channel());
#if defined(CHROME_OS)
EXPECT_EQ(checkin_proto::DEVICE_CHROME_OS, request_proto.checkin().type());
#else
EXPECT_EQ(checkin_proto::DEVICE_CHROME_BROWSER,
request_proto.checkin().type());
#endif
}
TEST_F(CheckinRequestTest, ResponseBodyEmpty) {
CreateRequest(0u, 0u);
request_->Start();
SetResponseStatusAndString(net::HTTP_OK, std::string());
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, ResponseBodyCorrupted) {
CreateRequest(0u, 0u);
request_->Start();
SetResponseStatusAndString(net::HTTP_OK, "Corrupted response body");
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, ResponseHttpStatusNotOK) {
CreateRequest(0u, 0u);
request_->Start();
SetResponseStatusAndString(net::HTTP_UNAUTHORIZED, std::string());
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, ResponseMissingAndroidId) {
CreateRequest(0u, 0u);
request_->Start();
SetResponse(MISSING_ANDROID_ID);
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, ResponseMissingSecurityToken) {
CreateRequest(0u, 0u);
request_->Start();
SetResponse(MISSING_SECURITY_TOKEN);
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, AndroidIdEqualsZeroInResponse) {
CreateRequest(0u, 0u);
request_->Start();
SetResponse(ANDROID_ID_IS_ZER0);
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, SecurityTokenEqualsZeroInResponse) {
CreateRequest(0u, 0u);
request_->Start();
SetResponse(SECURITY_TOKEN_IS_ZERO);
CompleteFetch();
EXPECT_EQ(0u, android_id_);
EXPECT_EQ(0u, security_token_);
}
TEST_F(CheckinRequestTest, SuccessfulFirstTimeCheckin) {
CreateRequest(0u, 0u);
request_->Start();
SetResponse(VALID_RESPONSE);
CompleteFetch();
EXPECT_EQ(kAndroidId, android_id_);
EXPECT_EQ(kSecurityToken, security_token_);
}
TEST_F(CheckinRequestTest, SuccessfulSubsequentCheckin) {
CreateRequest(kAndroidId, kSecurityToken);
request_->Start();
SetResponse(VALID_RESPONSE);
CompleteFetch();
EXPECT_EQ(kAndroidId, android_id_);
EXPECT_EQ(kSecurityToken, security_token_);
}
} // namespace gcm
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
'base/mcs_util.h', 'base/mcs_util.h',
'base/socket_stream.cc', 'base/socket_stream.cc',
'base/socket_stream.h', 'base/socket_stream.h',
'engine/checkin_request.cc',
'engine/checkin_request.h',
'engine/connection_factory.cc', 'engine/connection_factory.cc',
'engine/connection_factory.h', 'engine/connection_factory.h',
'engine/connection_factory_impl.cc', 'engine/connection_factory_impl.cc',
...@@ -64,6 +66,8 @@ ...@@ -64,6 +66,8 @@
'gcm_client.h', 'gcm_client.h',
'gcm_client_impl.cc', 'gcm_client_impl.cc',
'gcm_client_impl.h', 'gcm_client_impl.h',
'protocol/android_checkin.proto',
'protocol/checkin.proto',
'protocol/mcs.proto', 'protocol/mcs.proto',
], ],
'includes': [ 'includes': [
...@@ -116,6 +120,7 @@ ...@@ -116,6 +120,7 @@
'base/mcs_message_unittest.cc', 'base/mcs_message_unittest.cc',
'base/mcs_util_unittest.cc', 'base/mcs_util_unittest.cc',
'base/socket_stream_unittest.cc', 'base/socket_stream_unittest.cc',
'engine/checkin_request_unittest.cc',
'engine/connection_factory_impl_unittest.cc', 'engine/connection_factory_impl_unittest.cc',
'engine/connection_handler_impl_unittest.cc', 'engine/connection_handler_impl_unittest.cc',
'engine/fake_connection_factory.cc', 'engine/fake_connection_factory.cc',
......
...@@ -64,8 +64,8 @@ class GCM_EXPORT GCMClient { ...@@ -64,8 +64,8 @@ class GCM_EXPORT GCMClient {
}; };
// The check-in info for the user. Returned by the server. // The check-in info for the user. Returned by the server.
struct GCM_EXPORT CheckInInfo { struct GCM_EXPORT CheckinInfo {
CheckInInfo() : android_id(0), secret(0) {} CheckinInfo() : android_id(0), secret(0) {}
bool IsValid() const { return android_id != 0 && secret != 0; } bool IsValid() const { return android_id != 0 && secret != 0; }
void Reset() { void Reset() {
android_id = 0; android_id = 0;
...@@ -81,9 +81,9 @@ class GCM_EXPORT GCMClient { ...@@ -81,9 +81,9 @@ class GCM_EXPORT GCMClient {
class Delegate { class Delegate {
public: public:
// Called when the user has been checked in successfully or an error occurs. // Called when the user has been checked in successfully or an error occurs.
// |checkin_info|: valid if the checkin completed successfully. // |checkin_info|: valid if the CheckIn(..) completed successfully.
// |result|: the type of the error if an error occured, success otherwise. // |result|: the type of the error if an error occured, success otherwise.
virtual void OnCheckInFinished(const CheckInInfo& checkin_info, virtual void OnCheckInFinished(const CheckinInfo& checkin_info,
Result result) = 0; Result result) = 0;
// Called when the registration completed successfully or an error occurs. // Called when the registration completed successfully or an error occurs.
...@@ -124,7 +124,7 @@ class GCM_EXPORT GCMClient { ...@@ -124,7 +124,7 @@ class GCM_EXPORT GCMClient {
// Returns the checkin info associated with this user. The delegate class // Returns the checkin info associated with this user. The delegate class
// is expected to persist the checkin info that is provided by // is expected to persist the checkin info that is provided by
// OnCheckInFinished. // OnCheckInFinished.
virtual CheckInInfo GetCheckInInfo() const = 0; virtual CheckinInfo GetCheckinInfo() const = 0;
// Called when the loading from the persistent store is done. The loading // Called when the loading from the persistent store is done. The loading
// is triggered asynchronously when GCMClient is created. // is triggered asynchronously when GCMClient is created.
...@@ -157,7 +157,7 @@ class GCM_EXPORT GCMClient { ...@@ -157,7 +157,7 @@ class GCM_EXPORT GCMClient {
// Registers the application for GCM. Delegate::OnRegisterFinished will be // Registers the application for GCM. Delegate::OnRegisterFinished will be
// called asynchronously upon completion. // called asynchronously upon completion.
// |username|: the username (email address) passed in CheckIn. // |username|: the username (email address) passed in CheckIn(..).
// |app_id|: application ID. // |app_id|: application ID.
// |cert|: SHA-1 of public key of the application, in base16 format. // |cert|: SHA-1 of public key of the application, in base16 format.
// |sender_ids|: list of IDs of the servers that are allowed to send the // |sender_ids|: list of IDs of the servers that are allowed to send the
...@@ -171,14 +171,14 @@ class GCM_EXPORT GCMClient { ...@@ -171,14 +171,14 @@ class GCM_EXPORT GCMClient {
// Unregisters the application from GCM when it is uninstalled. // Unregisters the application from GCM when it is uninstalled.
// Delegate::OnUnregisterFinished will be called asynchronously upon // Delegate::OnUnregisterFinished will be called asynchronously upon
// completion. // completion.
// |username|: the username (email address) passed in CheckIn. // |username|: the username (email address) passed in CheckIn(..).
// |app_id|: application ID. // |app_id|: application ID.
virtual void Unregister(const std::string& username, virtual void Unregister(const std::string& username,
const std::string& app_id) = 0; const std::string& app_id) = 0;
// Sends a message to a given receiver. Delegate::OnSendFinished will be // Sends a message to a given receiver. Delegate::OnSendFinished will be
// called asynchronously upon completion. // called asynchronously upon completion.
// |username|: the username (email address) passed in CheckIn. // |username|: the username (email address) passed in CheckIn(..).
// |app_id|: application ID. // |app_id|: application ID.
// |receiver_id|: registration ID of the receiver party. // |receiver_id|: registration ID of the receiver party.
// |message|: message to be sent. // |message|: message to be sent.
......
// 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.
//
// Logging information for Android "checkin" events (automatic, periodic
// requests made by Android devices to the server).
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
option retain_unknown_fields = true;
package checkin_proto;
// Build characteristics unique to the Chrome browser, and Chrome OS
message ChromeBuildProto {
enum Platform {
PLATFORM_WIN = 1;
PLATFORM_MAC = 2;
PLATFORM_LINUX = 3;
PLATFORM_CROS = 4;
PLATFORM_IOS = 5;
// Just a placeholder. Likely don't need it due to the presence of the
// Android GCM on phone/tablet devices.
PLATFORM_ANDROID = 6;
}
enum Channel {
CHANNEL_STABLE = 1;
CHANNEL_BETA = 2;
CHANNEL_DEV = 3;
CHANNEL_CANARY = 4;
CHANNEL_UNKNOWN = 5; // for tip of tree or custom builds
}
// The platform of the device.
optional Platform platform = 1;
// The Chrome instance's version.
optional string chrome_version = 2;
// The Channel (build type) of Chrome.
optional Channel channel = 3;
}
// Information sent by the device in a "checkin" request.
message AndroidCheckinProto {
// Miliseconds since the Unix epoch of the device's last successful checkin.
optional int64 last_checkin_msec = 2;
// The current MCC+MNC of the mobile device's current cell.
optional string cell_operator = 6;
// The MCC+MNC of the SIM card (different from operator if the
// device is roaming, for instance).
optional string sim_operator = 7;
// The device's current roaming state (reported starting in eclair builds).
// Currently one of "{,not}mobile-{,not}roaming", if it is present at all.
optional string roaming = 8;
// For devices supporting multiple user profiles (which may be
// supported starting in jellybean), the ordinal number of the
// profile that is checking in. This is 0 for the primary profile
// (which can't be changed without wiping the device), and 1,2,3,...
// for additional profiles (which can be added and deleted freely).
optional int32 user_number = 9;
// Class of device. Indicates the type of build proto
// (IosBuildProto/ChromeBuildProto/AndroidBuildProto)
// That is included in this proto
optional DeviceType type = 12 [default = DEVICE_ANDROID_OS];
// For devices running MCS on Chrome, build-specific characteristics
// of the browser. There are no hardware aspects (except for ChromeOS).
// This will only be populated for Chrome builds/ChromeOS devices
optional checkin_proto.ChromeBuildProto chrome_build = 13;
// Note: Some of the Android specific optional fields were skipped to limit
// the protobuf definition.
// Next 14
}
// enum values correspond to the type of device.
// Used in the AndroidCheckinProto and Device proto.
enum DeviceType {
// Android Device
DEVICE_ANDROID_OS = 1;
// Apple IOS device
DEVICE_IOS_OS = 2;
// Chrome browser - Not Chrome OS. No hardware records.
DEVICE_CHROME_BROWSER = 3;
// Chrome OS
DEVICE_CHROME_OS = 4;
}
// 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.
//
// Request and reply to the "checkin server" devices poll every few hours.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
option retain_unknown_fields = true;
package checkin_proto;
import "android_checkin.proto";
// A concrete name/value pair sent to the device's Gservices database.
message GservicesSetting {
required bytes name = 1;
required bytes value = 2;
}
// Devices send this every few hours to tell us how they're doing.
message AndroidCheckinRequest {
// IMEI (used by GSM phones) is sent and stored as 15 decimal
// digits; the 15th is a check digit.
optional string imei = 1; // IMEI, reported but not logged.
// MEID (used by CDMA phones) is sent and stored as 14 hexadecimal
// digits (no check digit).
optional string meid = 10; // MEID, reported but not logged.
// MAC address (used by non-phone devices). 12 hexadecimal digits;
// no separators (eg "0016E6513AC2", not "00:16:E6:51:3A:C2").
repeated string mac_addr = 9; // MAC address, reported but not logged.
// An array parallel to mac_addr, describing the type of interface.
// Currently accepted values: "wifi", "ethernet", "bluetooth". If
// not present, "wifi" is assumed.
repeated string mac_addr_type = 19;
// Serial number (a manufacturer-defined unique hardware
// identifier). Alphanumeric, case-insensitive.
optional string serial_number = 16;
// Older CDMA networks use an ESN (8 hex digits) instead of an MEID.
optional string esn = 17; // ESN, reported but not logged
optional int64 id = 2; // Android device ID, not logged
optional int64 logging_id = 7; // Pseudonymous logging ID for Sawmill
optional string digest = 3; // Digest of device provisioning, not logged.
optional string locale = 6; // Current locale in standard (xx_XX) format
required AndroidCheckinProto checkin = 4;
// DEPRECATED, see AndroidCheckinProto.requested_group
optional string desired_build = 5;
// Blob of data from the Market app to be passed to Market API server
optional string market_checkin = 8;
// SID cookies of any google accounts stored on the phone. Not logged.
repeated string account_cookie = 11;
// Time zone. Not currently logged.
optional string time_zone = 12;
// Security token used to validate the checkin request.
// Required for android IDs issued to Froyo+ devices, not for legacy IDs.
optional fixed64 security_token = 13;
// Version of checkin protocol.
//
// There are currently two versions:
//
// - version field missing: android IDs are assigned based on
// hardware identifiers. unsecured in the sense that you can
// "unregister" someone's phone by sending a registration request
// with their IMEI/MEID/MAC.
//
// - version=2: android IDs are assigned randomly. The device is
// sent a security token that must be included in all future
// checkins for that android id.
//
// - version=3: same as version 2, but the 'fragment' field is
// provided, and the device understands incremental updates to the
// gservices table (ie, only returning the keys whose values have
// changed.)
//
// (version=1 was skipped to avoid confusion with the "missing"
// version field that is effectively version 1.)
optional int32 version = 14;
// OTA certs accepted by device (base-64 SHA-1 of cert files). Not
// logged.
repeated string ota_cert = 15;
// Honeycomb and newer devices send configuration data with their checkin.
// optional DeviceConfigurationProto device_configuration = 18;
// A single CheckinTask on the device may lead to multiple checkin
// requests if there is too much log data to upload in a single
// request. For version 3 and up, this field will be filled in with
// the number of the request, starting with 0.
optional int32 fragment = 20;
// For devices supporting multiple users, the name of the current
// profile (they all check in independently, just as if they were
// multiple physical devices). This may not be set, even if the
// device is using multiuser. (checkin.user_number should be set to
// the ordinal of the user.)
optional string user_name = 21;
// For devices supporting multiple user profiles, the serial number
// for the user checking in. Not logged. May not be set, even if
// the device supportes multiuser. checkin.user_number is the
// ordinal of the user (0, 1, 2, ...), which may be reused if users
// are deleted and re-created. user_serial_number is never reused
// (unless the device is wiped).
optional int32 user_serial_number = 22;
// NEXT TAG: 23
}
// The response to the device.
message AndroidCheckinResponse {
required bool stats_ok = 1; // Whether statistics were recorded properly.
optional int64 time_msec = 3; // Time of day from server (Java epoch).
// repeated AndroidIntentProto intent = 2;
// Provisioning is sent if the request included an obsolete digest.
//
// For version <= 2, 'digest' contains the digest that should be
// sent back to the server on the next checkin, and 'setting'
// contains the entire gservices table (which replaces the entire
// current table on the device).
//
// for version >= 3, 'digest' will be absent. If 'settings_diff'
// is false, then 'setting' contains the entire table, as in version
// 2. If 'settings_diff' is true, then 'delete_setting' contains
// the keys to delete, and 'setting' contains only keys to be added
// or for which the value has changed. All other keys in the
// current table should be left untouched. If 'settings_diff' is
// absent, don't touch the existing gservices table.
//
optional string digest = 4;
optional bool settings_diff = 9;
repeated string delete_setting = 10;
repeated GservicesSetting setting = 5;
optional bool market_ok = 6; // If Market got the market_checkin data OK.
optional fixed64 android_id = 7; // From the request, or newly assigned
optional fixed64 security_token = 8; // The associated security token
optional string version_info = 11;
// NEXT TAG: 12
}
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