Commit c1047318 authored by fgorski's avatar fgorski Committed by Commit bot

[GCM] Adding GCMAccountMapper to link signed in profile to accounts.

* Addes GCMAccountMapper with tests for adding and removing accoounts.

BUG=374969

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

Cr-Commit-Position: refs/heads/master@{#293308}
parent 6017d60f
......@@ -119,6 +119,7 @@
'feedback/feedback_common_unittest.cc',
'feedback/feedback_data_unittest.cc',
'feedback/feedback_uploader_unittest.cc',
'gcm_driver/gcm_account_mapper_unittest.cc',
'gcm_driver/gcm_client_impl_unittest.cc',
'gcm_driver/gcm_driver_desktop_unittest.cc',
'gcm_driver/gcm_stats_recorder_impl_unittest.cc',
......@@ -439,7 +440,7 @@
'components.gyp:autofill_content_browser',
'components.gyp:autofill_content_renderer',
'components.gyp:autofill_content_test_support',
# Dependencies of component_updater
'components.gyp:component_updater',
'components.gyp:component_updater_test_support',
......@@ -577,6 +578,7 @@
}],
['OS == "android"', {
'sources!': [
'gcm_driver/gcm_account_mapper_unittest.cc',
'gcm_driver/gcm_client_impl_unittest.cc',
'gcm_driver/gcm_driver_desktop_unittest.cc',
'feedback/feedback_common_unittest.cc',
......
......@@ -23,6 +23,8 @@
'gcm_driver/android/component_jni_registrar.h',
'gcm_driver/default_gcm_app_handler.cc',
'gcm_driver/default_gcm_app_handler.h',
'gcm_driver/gcm_account_mapper.cc',
'gcm_driver/gcm_account_mapper.h',
'gcm_driver/gcm_activity.cc',
'gcm_driver/gcm_activity.h',
'gcm_driver/gcm_app_handler.cc',
......@@ -55,6 +57,8 @@
'../google_apis/gcm/gcm.gyp:gcm',
],
'sources!': [
'gcm_driver/gcm_account_mapper.cc',
'gcm_driver/gcm_account_mapper.h',
'gcm_driver/gcm_client_factory.cc',
'gcm_driver/gcm_client_factory.h',
'gcm_driver/gcm_client_impl.cc',
......
This diff is collapsed.
// 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_ACCOUNT_MAPPER_H_
#define COMPONENTS_GCM_DRIVER_GCM_ACCOUNT_MAPPER_H_
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/gcm_client.h"
#include "google_apis/gcm/engine/account_mapping.h"
namespace base {
class Clock;
}
namespace gcm {
class GCMDriver;
// Class for mapping signed-in GAIA accounts to the GCM Device ID.
class GCMAccountMapper : public GCMAppHandler {
public:
// List of account mappings.
typedef std::vector<AccountMapping> AccountMappings;
explicit GCMAccountMapper(GCMDriver* gcm_driver);
virtual ~GCMAccountMapper();
void Initialize(const AccountMappings& account_mappings,
const std::string& registration_id);
// Called by AccountTracker, when a new list of account tokens is available.
// This will cause a refresh of account mappings and sending updates to GCM.
void SetAccountTokens(
const std::vector<GCMClient::AccountTokenInfo> account_tokens);
// Implementation of GCMAppHandler:
virtual void ShutdownHandler() OVERRIDE;
virtual void OnMessage(const std::string& app_id,
const GCMClient::IncomingMessage& message) OVERRIDE;
virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
virtual void OnSendError(
const std::string& app_id,
const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
virtual void OnSendAcknowledged(const std::string& app_id,
const std::string& message_id) OVERRIDE;
virtual bool CanHandle(const std::string& app_id) const OVERRIDE;
private:
friend class GCMAccountMapperTest;
typedef std::map<std::string, GCMClient::OutgoingMessage> OutgoingMessages;
// Informs GCM of an added or refreshed account mapping.
void SendAddMappingMessage(AccountMapping& account_mapping);
// Informs GCM of a removed account mapping.
void SendRemoveMappingMessage(AccountMapping& account_mapping);
void CreateAndSendMessage(const AccountMapping& account_mapping);
// Callback for sending a message.
void OnSendFinished(const std::string& account_id,
const std::string& message_id,
GCMClient::Result result);
// Checks whether the update can be triggered now. If the current time is
// within reasonable time (6 hours) of when the update is due, we want to
// trigger the update immediately to take advantage of a fresh OAuth2 token.
bool CanTriggerUpdate(const base::Time& last_update_time) const;
// Checks whether last status change is older than a TTL of a message.
bool IsLastStatusChangeOlderThanTTL(
const AccountMapping& account_mapping) const;
// Finds an account mapping in |accounts_| by |account_id|.
AccountMapping* FindMappingByAccountId(const std::string& account_id);
// Finds an account mapping in |accounts_| by |message_id|.
// Returns iterator that can be used to delete the account.
AccountMappings::iterator FindMappingByMessageId(
const std::string& message_id);
// Sets the clock for testing.
void SetClockForTesting(scoped_ptr<base::Clock> clock);
// GCMDriver owns GCMAccountMapper.
GCMDriver* gcm_driver_;
// Clock for timestamping status changes.
scoped_ptr<base::Clock> clock_;
// Currnetly tracked account mappings.
AccountMappings accounts_;
// GCM Registration ID of the account mapper.
std::string registration_id_;
bool initialized_;
base::WeakPtrFactory<GCMAccountMapper> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GCMAccountMapper);
};
} // namespace gcm
#endif // COMPONENTS_GCM_DRIVER_GCM_ACCOUNT_MAPPER_H_
This diff is collapsed.
......@@ -141,6 +141,13 @@ class GCMClient {
RecordedActivities recorded_activities;
};
// Information about account.
struct AccountTokenInfo {
std::string account_id;
std::string email;
std::string access_token;
};
// A delegate interface that allows the GCMClient instance to interact with
// its caller, i.e. notifying asynchronous event.
class Delegate {
......
......@@ -12,39 +12,44 @@ namespace gcm {
namespace {
const char kSeparator[] = "&";
uint32 kEmailIndex = 0;
uint32 kMappingChangeTimestampIndex = 1;
uint32 kMessageTypeIndex = 2;
uint32 kMessageIdIndex = 3;
uint32 kSizeWithNoMessage = kMessageTypeIndex + 1;
uint32 kSizeWithMessage = kMessageIdIndex + 1;
const char kMessageTypeNoneString[] = "none";
const char kMessageTypeAddString[] = "add";
const char kMessageTypeRemoveString[] = "remove";
std::string MessageTypeToString(AccountMapping::MessageType type) {
switch (type) {
case AccountMapping::MSG_NONE:
return kMessageTypeNoneString;
case AccountMapping::MSG_ADD:
return kMessageTypeAddString;
case AccountMapping::MSG_REMOVE:
return kMessageTypeRemoveString;
const uint32 kEmailIndex = 0;
const uint32 kStatusIndex = 1;
const uint32 kStatusChangeTimestampIndex = 2;
const uint32 kSizeWithNoMessage = kStatusChangeTimestampIndex + 1;
const uint32 kMessageIdIndex = 3;
const uint32 kSizeWithMessage = kMessageIdIndex + 1;
const char kStatusNew[] = "new";
const char kStatusAdding[] = "adding";
const char kStatusMapped[] = "mapped";
const char kStatusRemoving[] = "removing";
std::string StatusToString(AccountMapping::MappingStatus status) {
switch (status) {
case AccountMapping::NEW:
return kStatusNew;
case AccountMapping::ADDING:
return kStatusAdding;
case AccountMapping::MAPPED:
return kStatusMapped;
case AccountMapping::REMOVING:
return kStatusRemoving;
default:
NOTREACHED();
}
return std::string();
}
bool StringToMessageType(const std::string& type_str,
AccountMapping::MessageType* type) {
if (type_str.compare(kMessageTypeAddString) == 0)
*type = AccountMapping::MSG_ADD;
else if (type_str.compare(kMessageTypeRemoveString) == 0)
*type = AccountMapping::MSG_REMOVE;
else if (type_str.compare(kMessageTypeNoneString) == 0)
*type = AccountMapping::MSG_NONE;
bool StringToStatus(const std::string& status_str,
AccountMapping::MappingStatus* status) {
if (status_str.compare(kStatusAdding) == 0)
*status = AccountMapping::ADDING;
else if (status_str.compare(kStatusMapped) == 0)
*status = AccountMapping::MAPPED;
else if (status_str.compare(kStatusRemoving) == 0)
*status = AccountMapping::REMOVING;
else if (status_str.compare(kStatusNew) == 0)
*status = AccountMapping::NEW;
else
return false;
......@@ -53,7 +58,7 @@ bool StringToMessageType(const std::string& type_str,
} // namespace
AccountMapping::AccountMapping() {
AccountMapping::AccountMapping() : status(NEW) {
}
AccountMapping::~AccountMapping() {
......@@ -63,10 +68,10 @@ std::string AccountMapping::SerializeAsString() const {
std::string value;
value.append(email);
value.append(kSeparator);
value.append(base::Int64ToString(status_change_timestamp.ToInternalValue()));
value.append(StatusToString(status));
value.append(kSeparator);
value.append(MessageTypeToString(last_message_type));
if (last_message_type != MSG_NONE) {
value.append(base::Int64ToString(status_change_timestamp.ToInternalValue()));
if (!last_message_id.empty()) {
value.append(kSeparator);
value.append(last_message_id);
}
......@@ -83,49 +88,40 @@ bool AccountMapping::ParseFromString(const std::string& value) {
}
if (values[kEmailIndex].empty() ||
values[kMappingChangeTimestampIndex].empty() ||
values[kMessageTypeIndex].empty()) {
values[kStatusChangeTimestampIndex].empty() ||
values[kStatusIndex].empty()) {
return false;
}
if (values.size() == kSizeWithMessage && values[kMessageIdIndex].empty()) {
if (values.size() == kSizeWithMessage && values[kMessageIdIndex].empty())
return false;
}
MessageType message_type;
if (!StringToMessageType(values[kMessageTypeIndex], &message_type))
MappingStatus temp_status;
if (!StringToStatus(values[kStatusIndex], &temp_status))
return false;
if ((message_type == MSG_NONE && values.size() == kSizeWithMessage) ||
(message_type != MSG_NONE && values.size() != kSizeWithMessage)) {
if (values.size() == kSizeWithNoMessage &&
(temp_status == REMOVING || temp_status == ADDING)) {
return false;
}
last_message_type = message_type;
int64 status_change_ts_internal = 0LL;
if (!base::StringToInt64(values[kMappingChangeTimestampIndex],
if (!base::StringToInt64(values[kStatusChangeTimestampIndex],
&status_change_ts_internal)) {
return false;
}
if (status_change_ts_internal == 0LL)
status = ADDING;
else if (last_message_type == MSG_REMOVE)
status = REMOVING;
else
status = MAPPED;
status_change_timestamp =
base::Time::FromInternalValue(status_change_ts_internal);
status = temp_status;
email = values[kEmailIndex];
access_token.clear();
if (values.size() == kSizeWithMessage)
last_message_id = values[kMessageIdIndex];
else
last_message_id.clear();
email = values[kEmailIndex];
status_change_timestamp =
base::Time::FromInternalValue(status_change_ts_internal);
access_token.clear();
return true;
}
......
......@@ -25,16 +25,6 @@ struct GCM_EXPORT AccountMapping {
// reached the GCM.
REMOVING, // Account is removed, but a message removing the mapping has not
// been confirmed yet.
REMOVED, // Account is removed, and at least one message has been
// confirmed to have reached the GCM.
};
// Indicates whether a message, if sent, was adding or removing account
// mapping.
enum MessageType {
MSG_NONE, // No message has been sent.
MSG_ADD, // Account was mapped to device by the message.
MSG_REMOVE, // Account mapping to device was removed by the message.
};
AccountMapping();
......@@ -57,8 +47,6 @@ struct GCM_EXPORT AccountMapping {
MappingStatus status;
// Time of the mapping status change.
base::Time status_change_timestamp;
// Type of the last mapping message sent to GCM.
MessageType last_message_type;
// ID of the last mapping message sent to GCM.
std::string last_message_id;
};
......
......@@ -17,66 +17,91 @@ TEST(AccountMappingTest, SerializeAccountMapping) {
account_mapping.account_id = "acc_id";
account_mapping.email = "test@example.com";
account_mapping.access_token = "access_token";
account_mapping.status = AccountMapping::ADDING;
account_mapping.status = AccountMapping::NEW;
account_mapping.status_change_timestamp = base::Time();
account_mapping.last_message_id.clear();
EXPECT_EQ("test@example.com&new&0", account_mapping.SerializeAsString());
account_mapping.status = AccountMapping::ADDING;
account_mapping.status_change_timestamp =
base::Time::FromInternalValue(1305797421259977LL);
account_mapping.last_message_id = "last_message_id_1";
account_mapping.last_message_type = AccountMapping::MSG_ADD;
EXPECT_EQ("test@example.com&0&add&last_message_id_1",
EXPECT_EQ("test@example.com&adding&1305797421259977&last_message_id_1",
account_mapping.SerializeAsString());
account_mapping.status = AccountMapping::MAPPED;
EXPECT_EQ("test@example.com&mapped&1305797421259977&last_message_id_1",
account_mapping.SerializeAsString());
account_mapping.last_message_id.clear();
EXPECT_EQ("test@example.com&mapped&1305797421259977",
account_mapping.SerializeAsString());
account_mapping.account_id = "acc_id2";
account_mapping.email = "test@gmail.com";
account_mapping.access_token = "access_token"; // should be ignored.
account_mapping.status = AccountMapping::MAPPED; // should be ignored.
account_mapping.status_change_timestamp =
base::Time::FromInternalValue(1305797421259977LL);
account_mapping.status = AccountMapping::REMOVING;
account_mapping.last_message_id = "last_message_id_2";
account_mapping.last_message_type = AccountMapping::MSG_REMOVE;
EXPECT_EQ("test@gmail.com&1305797421259977&remove&last_message_id_2",
account_mapping.SerializeAsString());
account_mapping.last_message_type = AccountMapping::MSG_NONE;
EXPECT_EQ("test@gmail.com&1305797421259977&none",
EXPECT_EQ("test@gmail.com&removing&1305797421259977&last_message_id_2",
account_mapping.SerializeAsString());
}
TEST(AccountMappingTest, DeserializeAccountMapping) {
AccountMapping account_mapping;
account_mapping.account_id = "acc_id";
EXPECT_TRUE(account_mapping.ParseFromString(
"test@example.com&0&add&last_message_id_1"));
EXPECT_TRUE(account_mapping.ParseFromString("test@example.com&new&0"));
EXPECT_EQ("acc_id", account_mapping.account_id);
EXPECT_EQ("test@example.com", account_mapping.email);
EXPECT_TRUE(account_mapping.access_token.empty());
EXPECT_EQ(AccountMapping::ADDING, account_mapping.status);
EXPECT_EQ(AccountMapping::NEW, account_mapping.status);
EXPECT_EQ(base::Time(), account_mapping.status_change_timestamp);
EXPECT_EQ(AccountMapping::MSG_ADD, account_mapping.last_message_type);
EXPECT_EQ("last_message_id_1", account_mapping.last_message_id);
EXPECT_TRUE(account_mapping.last_message_id.empty());
EXPECT_TRUE(account_mapping.ParseFromString(
"test@gmail.com&1305797421259977&remove&last_message_id_2"));
"test@gmail.com&adding&1305797421259977&last_message_id_1"));
EXPECT_EQ("acc_id", account_mapping.account_id);
EXPECT_EQ("test@gmail.com", account_mapping.email);
EXPECT_TRUE(account_mapping.access_token.empty());
EXPECT_EQ(AccountMapping::REMOVING, account_mapping.status);
EXPECT_EQ(AccountMapping::ADDING, account_mapping.status);
EXPECT_EQ(base::Time::FromInternalValue(1305797421259977LL),
account_mapping.status_change_timestamp);
EXPECT_EQ(AccountMapping::MSG_REMOVE, account_mapping.last_message_type);
EXPECT_EQ("last_message_id_2", account_mapping.last_message_id);
EXPECT_EQ("last_message_id_1", account_mapping.last_message_id);
EXPECT_TRUE(account_mapping.ParseFromString(
"test@gmail.com&1305797421259977&none"));
"test@example.com&mapped&1305797421259977"));
EXPECT_EQ("acc_id", account_mapping.account_id);
EXPECT_EQ("test@example.com", account_mapping.email);
EXPECT_TRUE(account_mapping.access_token.empty());
EXPECT_EQ(AccountMapping::MAPPED, account_mapping.status);
EXPECT_EQ(base::Time::FromInternalValue(1305797421259977LL),
account_mapping.status_change_timestamp);
EXPECT_TRUE(account_mapping.last_message_id.empty());
EXPECT_TRUE(account_mapping.ParseFromString(
"test@gmail.com&mapped&1305797421259977&last_message_id_1"));
EXPECT_EQ("acc_id", account_mapping.account_id);
EXPECT_EQ("test@gmail.com", account_mapping.email);
EXPECT_TRUE(account_mapping.access_token.empty());
EXPECT_EQ(AccountMapping::MAPPED, account_mapping.status);
EXPECT_EQ(base::Time::FromInternalValue(1305797421259977LL),
account_mapping.status_change_timestamp);
EXPECT_EQ(AccountMapping::MSG_NONE, account_mapping.last_message_type);
EXPECT_EQ("", account_mapping.last_message_id);
EXPECT_EQ("last_message_id_1", account_mapping.last_message_id);
EXPECT_TRUE(account_mapping.ParseFromString(
"test@gmail.com&removing&1305797421259977&last_message_id_2"));
EXPECT_EQ("acc_id", account_mapping.account_id);
EXPECT_EQ("test@gmail.com", account_mapping.email);
EXPECT_TRUE(account_mapping.access_token.empty());
EXPECT_EQ(AccountMapping::REMOVING, account_mapping.status);
EXPECT_EQ(base::Time::FromInternalValue(1305797421259977LL),
account_mapping.status_change_timestamp);
EXPECT_EQ("last_message_id_2", account_mapping.last_message_id);
}
TEST(AccountMappingTest, DeserializeAccountMappingInvalidInput) {
......@@ -84,38 +109,37 @@ TEST(AccountMappingTest, DeserializeAccountMappingInvalidInput) {
account_mapping.account_id = "acc_id";
// Too many agruments.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935"
"&add&last_message_id_1&stuff_here"));
"test@example.com&adding&1305797421259935&last_message_id_1&stuff_here"));
// Too few arguments.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935&remove"));
"test@example.com&removing&1305797421259935"));
// Too few arguments.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935"));
// Missing email.
"test@example.com&adding&1305797421259935"));
// Too few arguments.
EXPECT_FALSE(account_mapping.ParseFromString(
"&1305797421259935&remove&last_message_id_2"));
// Missing mapping status change timestamp.
"test@example.com&new"));
// Too few arguments.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@gmail.com&&remove&last_message_id_2"));
// Last mapping status change timestamp not parseable.
"test@example.com&mapped"));
// Missing email.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@gmail.com&remove&asdfjkl&last_message_id_2"));
// Missing message type.
"&remove&1305797421259935&last_message_id_2"));
// Missing mapping status.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935&&last_message_id_2"));
// Unkown message type.
"test@example.com&&1305797421259935&last_message_id_2"));
// Unkown mapping status.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935&random&last_message_id_2"));
// Message type is none when message details specified.
"test@example.com&random&1305797421259935&last_message_id_2"));
// Missing mapping status change timestamp.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935&none&last_message_id_2"));
// Message type is messed up.
"test@gmail.com&removing&&last_message_id_2"));
// Last mapping status change timestamp not parseable.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935&random"));
"test@gmail.com&removing&asdfjkl&last_message_id_2"));
// Missing last message ID.
EXPECT_FALSE(account_mapping.ParseFromString(
"test@example.com&1305797421259935&remove&"));
"test@example.com&removing&1305797421259935&"));
}
} // namespace
......
......@@ -532,7 +532,6 @@ TEST_F(GCMStoreImplTest, AccountMapping) {
account_mapping1.access_token = "account_token1";
account_mapping1.status = AccountMapping::ADDING;
account_mapping1.status_change_timestamp = base::Time();
account_mapping1.last_message_type = AccountMapping::MSG_ADD;
account_mapping1.last_message_id = "message_1";
AccountMapping account_mapping2;
......@@ -542,7 +541,6 @@ TEST_F(GCMStoreImplTest, AccountMapping) {
account_mapping2.status = AccountMapping::REMOVING;
account_mapping2.status_change_timestamp =
base::Time::FromInternalValue(1305734521259935LL);
account_mapping2.last_message_type = AccountMapping::MSG_REMOVE;
account_mapping2.last_message_id = "message_2";
gcm_store->AddAccountMapping(
......@@ -569,7 +567,6 @@ TEST_F(GCMStoreImplTest, AccountMapping) {
EXPECT_EQ(AccountMapping::ADDING, iter->second.status);
EXPECT_EQ(account_mapping1.status_change_timestamp,
iter->second.status_change_timestamp);
EXPECT_EQ(account_mapping1.last_message_type, iter->second.last_message_type);
EXPECT_EQ(account_mapping1.last_message_id, iter->second.last_message_id);
++iter;
EXPECT_EQ("account_id_2", iter->first);
......@@ -579,7 +576,6 @@ TEST_F(GCMStoreImplTest, AccountMapping) {
EXPECT_EQ(AccountMapping::REMOVING, iter->second.status);
EXPECT_EQ(account_mapping2.status_change_timestamp,
iter->second.status_change_timestamp);
EXPECT_EQ(account_mapping2.last_message_type, iter->second.last_message_type);
EXPECT_EQ(account_mapping2.last_message_id, iter->second.last_message_id);
gcm_store->RemoveAccountMapping(
......@@ -601,7 +597,6 @@ TEST_F(GCMStoreImplTest, AccountMapping) {
EXPECT_EQ(AccountMapping::REMOVING, iter->second.status);
EXPECT_EQ(account_mapping2.status_change_timestamp,
iter->second.status_change_timestamp);
EXPECT_EQ(account_mapping2.last_message_type, iter->second.last_message_type);
EXPECT_EQ(account_mapping2.last_message_id, iter->second.last_message_id);
}
......
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