1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/gcm_driver/gcm_account_mapper.h"
6
7#include "base/test/simple_test_clock.h"
8#include "base/time/time.h"
9#include "components/gcm_driver/fake_gcm_driver.h"
10#include "google_apis/gcm/engine/account_mapping.h"
11#include "google_apis/gcm/engine/gcm_store.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace gcm {
15
16namespace {
17
18const char kGCMAccountMapperSenderId[] = "745476177629";
19const char kGCMAccountMapperAppId[] = "com.google.android.gms";
20const char kRegistrationId[] = "reg_id";
21
22AccountMapping MakeAccountMapping(const std::string& account_id,
23                                  AccountMapping::MappingStatus status,
24                                  const base::Time& status_change_timestamp,
25                                  const std::string& last_message_id) {
26  AccountMapping account_mapping;
27  account_mapping.account_id = account_id;
28  account_mapping.email = account_id + "@gmail.com";
29  // account_mapping.access_token intentionally left empty.
30  account_mapping.status = status;
31  account_mapping.status_change_timestamp = status_change_timestamp;
32  account_mapping.last_message_id = last_message_id;
33  return account_mapping;
34}
35
36GCMClient::AccountTokenInfo MakeAccountTokenInfo(
37    const std::string& account_id) {
38  GCMClient::AccountTokenInfo account_token;
39  account_token.account_id = account_id;
40  account_token.email = account_id + "@gmail.com";
41  account_token.access_token = account_id + "_token";
42  return account_token;
43}
44
45void VerifyMappings(const GCMAccountMapper::AccountMappings& expected_mappings,
46                    const GCMAccountMapper::AccountMappings& actual_mappings,
47                    const std::string& verification_info) {
48  EXPECT_EQ(expected_mappings.size(), actual_mappings.size())
49      << "Verification Info: " << verification_info;
50  GCMAccountMapper::AccountMappings::const_iterator expected_iter =
51      expected_mappings.begin();
52  GCMAccountMapper::AccountMappings::const_iterator actual_iter =
53      actual_mappings.begin();
54  for (; expected_iter != expected_mappings.end() &&
55             actual_iter != actual_mappings.end();
56       ++expected_iter, ++actual_iter) {
57    EXPECT_EQ(expected_iter->email, actual_iter->email)
58        << "Verification Info: " << verification_info
59        << "; Account ID of expected: " << expected_iter->account_id;
60    EXPECT_EQ(expected_iter->account_id, actual_iter->account_id)
61        << "Verification Info: " << verification_info;
62    EXPECT_EQ(expected_iter->status, actual_iter->status)
63        << "Verification Info: " << verification_info
64        << "; Account ID of expected: " << expected_iter->account_id;
65    EXPECT_EQ(expected_iter->status_change_timestamp,
66              actual_iter->status_change_timestamp)
67        << "Verification Info: " << verification_info
68        << "; Account ID of expected: " << expected_iter->account_id;
69  }
70}
71
72class CustomFakeGCMDriver : public FakeGCMDriver {
73 public:
74  enum LastMessageAction {
75    NONE,
76    SEND_STARTED,
77    SEND_FINISHED,
78    SEND_ACKNOWLEDGED
79  };
80
81  CustomFakeGCMDriver();
82  virtual ~CustomFakeGCMDriver();
83
84  virtual void UpdateAccountMapping(
85      const AccountMapping& account_mapping) OVERRIDE;
86  virtual void RemoveAccountMapping(const std::string& account_id) OVERRIDE;
87  virtual void AddAppHandler(const std::string& app_id,
88                             GCMAppHandler* handler) OVERRIDE;
89  virtual void RemoveAppHandler(const std::string& app_id) OVERRIDE;
90  virtual void RegisterImpl(
91      const std::string& app_id,
92      const std::vector<std::string>& sender_ids) OVERRIDE;
93
94  void CompleteRegister(const std::string& registration_id,
95                        GCMClient::Result result);
96  void CompleteSend(const std::string& message_id, GCMClient::Result result);
97  void AcknowledgeSend(const std::string& message_id);
98  void MessageSendError(const std::string& message_id);
99
100  void CompleteSendAllMessages();
101  void AcknowledgeSendAllMessages();
102
103  void SetLastMessageAction(const std::string& message_id,
104                            LastMessageAction action);
105  void Clear();
106
107  const AccountMapping& last_account_mapping() const {
108    return account_mapping_;
109  }
110  const std::string& last_message_id() const { return last_message_id_; }
111  const std::string& last_removed_account_id() const {
112    return last_removed_account_id_;
113  }
114  LastMessageAction last_action() const { return last_action_; }
115  bool registration_id_requested() const { return registration_id_requested_; }
116
117 protected:
118  virtual void SendImpl(const std::string& app_id,
119                        const std::string& receiver_id,
120                        const GCMClient::OutgoingMessage& message) OVERRIDE;
121
122 private:
123  AccountMapping account_mapping_;
124  std::string last_message_id_;
125  std::string last_removed_account_id_;
126  LastMessageAction last_action_;
127  std::map<std::string, LastMessageAction> all_messages_;
128  bool registration_id_requested_;
129};
130
131CustomFakeGCMDriver::CustomFakeGCMDriver()
132    : last_action_(NONE), registration_id_requested_(false) {
133}
134
135CustomFakeGCMDriver::~CustomFakeGCMDriver() {
136}
137
138void CustomFakeGCMDriver::UpdateAccountMapping(
139    const AccountMapping& account_mapping) {
140  account_mapping_.email = account_mapping.email;
141  account_mapping_.account_id = account_mapping.account_id;
142  account_mapping_.access_token = account_mapping.access_token;
143  account_mapping_.status = account_mapping.status;
144  account_mapping_.status_change_timestamp =
145      account_mapping.status_change_timestamp;
146  account_mapping_.last_message_id = account_mapping.last_message_id;
147}
148
149void CustomFakeGCMDriver::RemoveAccountMapping(const std::string& account_id) {
150  last_removed_account_id_ = account_id;
151}
152
153void CustomFakeGCMDriver::AddAppHandler(const std::string& app_id,
154                                        GCMAppHandler* handler) {
155  GCMDriver::AddAppHandler(app_id, handler);
156}
157
158void CustomFakeGCMDriver::RemoveAppHandler(const std::string& app_id) {
159  GCMDriver::RemoveAppHandler(app_id);
160}
161
162void CustomFakeGCMDriver::RegisterImpl(
163    const std::string& app_id,
164    const std::vector<std::string>& sender_ids) {
165  DCHECK_EQ(kGCMAccountMapperAppId, app_id);
166  DCHECK_EQ(1u, sender_ids.size());
167  DCHECK_EQ(kGCMAccountMapperSenderId, sender_ids[0]);
168  registration_id_requested_ = true;
169}
170
171void CustomFakeGCMDriver::CompleteRegister(const std::string& registration_id,
172                                           GCMClient::Result result) {
173  RegisterFinished(kGCMAccountMapperAppId, registration_id, result);
174}
175
176void CustomFakeGCMDriver::CompleteSend(const std::string& message_id,
177                                       GCMClient::Result result) {
178  SendFinished(kGCMAccountMapperAppId, message_id, result);
179  SetLastMessageAction(message_id, SEND_FINISHED);
180}
181
182void CustomFakeGCMDriver::AcknowledgeSend(const std::string& message_id) {
183  GetAppHandler(kGCMAccountMapperAppId)
184      ->OnSendAcknowledged(kGCMAccountMapperAppId, message_id);
185  SetLastMessageAction(message_id, SEND_ACKNOWLEDGED);
186}
187
188void CustomFakeGCMDriver::MessageSendError(const std::string& message_id) {
189  GCMClient::SendErrorDetails send_error;
190  send_error.message_id = message_id;
191  send_error.result = GCMClient::TTL_EXCEEDED;
192  GetAppHandler(kGCMAccountMapperAppId)
193      ->OnSendError(kGCMAccountMapperAppId, send_error);
194}
195
196void CustomFakeGCMDriver::SendImpl(const std::string& app_id,
197                                   const std::string& receiver_id,
198                                   const GCMClient::OutgoingMessage& message) {
199  DCHECK_EQ(kGCMAccountMapperAppId, app_id);
200  DCHECK_EQ(kGCMAccountMapperSenderId, receiver_id);
201
202  SetLastMessageAction(message.id, SEND_STARTED);
203}
204
205void CustomFakeGCMDriver::CompleteSendAllMessages() {
206  for (std::map<std::string, LastMessageAction>::const_iterator iter =
207           all_messages_.begin();
208       iter != all_messages_.end();
209       ++iter) {
210    if (iter->second == SEND_STARTED)
211      CompleteSend(iter->first, GCMClient::SUCCESS);
212  }
213}
214
215void CustomFakeGCMDriver::AcknowledgeSendAllMessages() {
216  for (std::map<std::string, LastMessageAction>::const_iterator iter =
217           all_messages_.begin();
218       iter != all_messages_.end();
219       ++iter) {
220    if (iter->second == SEND_FINISHED)
221      AcknowledgeSend(iter->first);
222  }
223}
224
225void CustomFakeGCMDriver::Clear() {
226  account_mapping_ = AccountMapping();
227  last_message_id_.clear();
228  last_removed_account_id_.clear();
229  last_action_ = NONE;
230  registration_id_requested_ = false;
231}
232
233void CustomFakeGCMDriver::SetLastMessageAction(const std::string& message_id,
234                                               LastMessageAction action) {
235  last_action_ = action;
236  last_message_id_ = message_id;
237  all_messages_[message_id] = action;
238}
239
240}  // namespace
241
242class GCMAccountMapperTest : public testing::Test {
243 public:
244  GCMAccountMapperTest();
245  virtual ~GCMAccountMapperTest();
246
247  void Restart();
248
249  const GCMAccountMapper::AccountMappings& GetAccounts() const {
250    return account_mapper_->accounts_;
251  }
252
253  GCMAccountMapper* mapper() { return account_mapper_.get(); }
254
255  CustomFakeGCMDriver& gcm_driver() { return gcm_driver_; }
256
257  base::SimpleTestClock* clock() { return clock_; }
258
259 private:
260  CustomFakeGCMDriver gcm_driver_;
261  scoped_ptr<GCMAccountMapper> account_mapper_;
262  base::SimpleTestClock* clock_;
263};
264
265GCMAccountMapperTest::GCMAccountMapperTest() {
266  Restart();
267}
268
269GCMAccountMapperTest::~GCMAccountMapperTest() {
270}
271
272void GCMAccountMapperTest::Restart() {
273  if (account_mapper_)
274    account_mapper_->ShutdownHandler();
275  account_mapper_.reset(new GCMAccountMapper(&gcm_driver_));
276  scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock);
277  clock_ = clock.get();
278  account_mapper_->SetClockForTesting(clock.PassAs<base::Clock>());
279}
280
281// Tests the initialization of account mappings (from the store) when empty.
282// It also checks that initialization triggers registration ID request.
283TEST_F(GCMAccountMapperTest, InitializeAccountMappingsEmpty) {
284  EXPECT_FALSE(gcm_driver().registration_id_requested());
285  mapper()->Initialize(GCMAccountMapper::AccountMappings());
286  EXPECT_TRUE(GetAccounts().empty());
287  EXPECT_TRUE(gcm_driver().registration_id_requested());
288}
289
290// Tests that registration is retried, when new tokens are delivered and in no
291// other circumstances.
292TEST_F(GCMAccountMapperTest, RegistrationRetryUponFailure) {
293  mapper()->Initialize(GCMAccountMapper::AccountMappings());
294  EXPECT_TRUE(gcm_driver().registration_id_requested());
295  gcm_driver().Clear();
296
297  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::UNKNOWN_ERROR);
298  EXPECT_FALSE(gcm_driver().registration_id_requested());
299  gcm_driver().Clear();
300
301  std::vector<GCMClient::AccountTokenInfo> account_tokens;
302  account_tokens.push_back(MakeAccountTokenInfo("acc_id2"));
303  mapper()->SetAccountTokens(account_tokens);
304  EXPECT_TRUE(gcm_driver().registration_id_requested());
305  gcm_driver().Clear();
306
307  gcm_driver().CompleteRegister(kRegistrationId,
308                                GCMClient::ASYNC_OPERATION_PENDING);
309  EXPECT_FALSE(gcm_driver().registration_id_requested());
310}
311
312// Tests the initialization of account mappings (from the store).
313TEST_F(GCMAccountMapperTest, InitializeAccountMappings) {
314  GCMAccountMapper::AccountMappings account_mappings;
315  AccountMapping account_mapping1 = MakeAccountMapping("acc_id1",
316                                                       AccountMapping::MAPPED,
317                                                       base::Time::Now(),
318                                                       std::string());
319  AccountMapping account_mapping2 = MakeAccountMapping("acc_id2",
320                                                       AccountMapping::ADDING,
321                                                       base::Time::Now(),
322                                                       "add_message_1");
323  account_mappings.push_back(account_mapping1);
324  account_mappings.push_back(account_mapping2);
325
326  mapper()->Initialize(account_mappings);
327
328  GCMAccountMapper::AccountMappings mappings = GetAccounts();
329  EXPECT_EQ(2UL, mappings.size());
330  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
331
332  EXPECT_EQ(account_mapping1.account_id, iter->account_id);
333  EXPECT_EQ(account_mapping1.email, iter->email);
334  EXPECT_TRUE(account_mapping1.access_token.empty());
335  EXPECT_EQ(account_mapping1.status, iter->status);
336  EXPECT_EQ(account_mapping1.status_change_timestamp,
337            iter->status_change_timestamp);
338  EXPECT_TRUE(account_mapping1.last_message_id.empty());
339
340  ++iter;
341  EXPECT_EQ(account_mapping2.account_id, iter->account_id);
342  EXPECT_EQ(account_mapping2.email, iter->email);
343  EXPECT_TRUE(account_mapping2.access_token.empty());
344  EXPECT_EQ(account_mapping2.status, iter->status);
345  EXPECT_EQ(account_mapping2.status_change_timestamp,
346            iter->status_change_timestamp);
347  EXPECT_EQ(account_mapping2.last_message_id, iter->last_message_id);
348}
349
350// Tests that account tokens are not processed until registration ID is
351// available.
352TEST_F(GCMAccountMapperTest, SetAccountTokensOnlyWorksWithRegisterationId) {
353  // Start with empty list.
354  mapper()->Initialize(GCMAccountMapper::AccountMappings());
355
356  std::vector<GCMClient::AccountTokenInfo> account_tokens;
357  account_tokens.push_back(MakeAccountTokenInfo("acc_id"));
358  mapper()->SetAccountTokens(account_tokens);
359
360  EXPECT_TRUE(GetAccounts().empty());
361
362  account_tokens.clear();
363  account_tokens.push_back(MakeAccountTokenInfo("acc_id1"));
364  account_tokens.push_back(MakeAccountTokenInfo("acc_id2"));
365  mapper()->SetAccountTokens(account_tokens);
366
367  EXPECT_TRUE(GetAccounts().empty());
368
369  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
370
371  GCMAccountMapper::AccountMappings mappings = GetAccounts();
372  EXPECT_EQ(2UL, mappings.size());
373  EXPECT_EQ("acc_id1", mappings[0].account_id);
374  EXPECT_EQ("acc_id2", mappings[1].account_id);
375}
376
377// Tests the part where a new account is added with a token, to the point when
378// GCM message is sent.
379TEST_F(GCMAccountMapperTest, AddMappingToMessageSent) {
380  mapper()->Initialize(GCMAccountMapper::AccountMappings());
381  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
382
383  std::vector<GCMClient::AccountTokenInfo> account_tokens;
384  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
385  account_tokens.push_back(account_token);
386  mapper()->SetAccountTokens(account_tokens);
387
388  GCMAccountMapper::AccountMappings mappings = GetAccounts();
389  EXPECT_EQ(1UL, mappings.size());
390  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
391  EXPECT_EQ("acc_id", iter->account_id);
392  EXPECT_EQ("acc_id@gmail.com", iter->email);
393  EXPECT_EQ("acc_id_token", iter->access_token);
394  EXPECT_EQ(AccountMapping::NEW, iter->status);
395  EXPECT_EQ(base::Time(), iter->status_change_timestamp);
396
397  EXPECT_TRUE(!gcm_driver().last_message_id().empty());
398}
399
400// Tests the part where GCM message is successfully queued.
401TEST_F(GCMAccountMapperTest, AddMappingMessageQueued) {
402  mapper()->Initialize(GCMAccountMapper::AccountMappings());
403  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
404
405  std::vector<GCMClient::AccountTokenInfo> account_tokens;
406  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
407  account_tokens.push_back(account_token);
408  mapper()->SetAccountTokens(account_tokens);
409
410  clock()->SetNow(base::Time::Now());
411  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
412
413  EXPECT_EQ(account_token.email, gcm_driver().last_account_mapping().email);
414  EXPECT_EQ(account_token.account_id,
415            gcm_driver().last_account_mapping().account_id);
416  EXPECT_EQ(account_token.access_token,
417            gcm_driver().last_account_mapping().access_token);
418  EXPECT_EQ(AccountMapping::ADDING, gcm_driver().last_account_mapping().status);
419  EXPECT_EQ(clock()->Now(),
420            gcm_driver().last_account_mapping().status_change_timestamp);
421  EXPECT_EQ(gcm_driver().last_message_id(),
422            gcm_driver().last_account_mapping().last_message_id);
423
424  GCMAccountMapper::AccountMappings mappings = GetAccounts();
425  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
426  EXPECT_EQ(account_token.email, iter->email);
427  EXPECT_EQ(account_token.account_id, iter->account_id);
428  EXPECT_EQ(account_token.access_token, iter->access_token);
429  EXPECT_EQ(AccountMapping::ADDING, iter->status);
430  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
431  EXPECT_EQ(gcm_driver().last_message_id(), iter->last_message_id);
432}
433
434// Tests status change from ADDING to MAPPED (Message is acknowledged).
435TEST_F(GCMAccountMapperTest, AddMappingMessageAcknowledged) {
436  mapper()->Initialize(GCMAccountMapper::AccountMappings());
437  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
438
439  std::vector<GCMClient::AccountTokenInfo> account_tokens;
440  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
441  account_tokens.push_back(account_token);
442  mapper()->SetAccountTokens(account_tokens);
443
444  clock()->SetNow(base::Time::Now());
445  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
446  clock()->SetNow(base::Time::Now());
447  gcm_driver().AcknowledgeSend(gcm_driver().last_message_id());
448
449  EXPECT_EQ(account_token.email, gcm_driver().last_account_mapping().email);
450  EXPECT_EQ(account_token.account_id,
451            gcm_driver().last_account_mapping().account_id);
452  EXPECT_EQ(account_token.access_token,
453            gcm_driver().last_account_mapping().access_token);
454  EXPECT_EQ(AccountMapping::MAPPED, gcm_driver().last_account_mapping().status);
455  EXPECT_EQ(clock()->Now(),
456            gcm_driver().last_account_mapping().status_change_timestamp);
457  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
458
459  GCMAccountMapper::AccountMappings mappings = GetAccounts();
460  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
461  EXPECT_EQ(account_token.email, iter->email);
462  EXPECT_EQ(account_token.account_id, iter->account_id);
463  EXPECT_EQ(account_token.access_token, iter->access_token);
464  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
465  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
466  EXPECT_TRUE(iter->last_message_id.empty());
467}
468
469// Tests status change form ADDING to MAPPED (When message was acknowledged,
470// after Chrome was restarted).
471TEST_F(GCMAccountMapperTest, AddMappingMessageAckedAfterRestart) {
472  mapper()->Initialize(GCMAccountMapper::AccountMappings());
473  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
474
475  std::vector<GCMClient::AccountTokenInfo> account_tokens;
476  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
477  account_tokens.push_back(account_token);
478  mapper()->SetAccountTokens(account_tokens);
479
480  clock()->SetNow(base::Time::Now());
481  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
482
483  Restart();
484  GCMAccountMapper::AccountMappings stored_mappings;
485  stored_mappings.push_back(gcm_driver().last_account_mapping());
486  mapper()->Initialize(stored_mappings);
487
488  clock()->SetNow(base::Time::Now());
489  gcm_driver().AcknowledgeSend(gcm_driver().last_message_id());
490
491  EXPECT_EQ(account_token.email, gcm_driver().last_account_mapping().email);
492  EXPECT_EQ(account_token.account_id,
493            gcm_driver().last_account_mapping().account_id);
494  EXPECT_EQ(account_token.access_token,
495            gcm_driver().last_account_mapping().access_token);
496  EXPECT_EQ(AccountMapping::MAPPED, gcm_driver().last_account_mapping().status);
497  EXPECT_EQ(clock()->Now(),
498            gcm_driver().last_account_mapping().status_change_timestamp);
499  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
500
501  GCMAccountMapper::AccountMappings mappings = GetAccounts();
502  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
503  EXPECT_EQ(account_token.email, iter->email);
504  EXPECT_EQ(account_token.account_id, iter->account_id);
505  EXPECT_EQ(account_token.access_token, iter->access_token);
506  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
507  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
508  EXPECT_TRUE(iter->last_message_id.empty());
509}
510
511// Tests a case when ADD message times out for a new account.
512TEST_F(GCMAccountMapperTest, AddMappingMessageSendErrorForNewAccount) {
513  mapper()->Initialize(GCMAccountMapper::AccountMappings());
514  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
515
516  std::vector<GCMClient::AccountTokenInfo> account_tokens;
517  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
518  account_tokens.push_back(account_token);
519  mapper()->SetAccountTokens(account_tokens);
520
521  clock()->SetNow(base::Time::Now());
522  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
523
524  clock()->SetNow(base::Time::Now());
525  std::string old_message_id = gcm_driver().last_message_id();
526  gcm_driver().MessageSendError(old_message_id);
527
528  // No new message is sent because of the send error, as the token is stale.
529  // Because the account was new, the entry should be deleted.
530  EXPECT_EQ(old_message_id, gcm_driver().last_message_id());
531  EXPECT_EQ(account_token.account_id, gcm_driver().last_removed_account_id());
532  EXPECT_TRUE(GetAccounts().empty());
533}
534
535/// Tests a case when ADD message times out for a MAPPED account.
536TEST_F(GCMAccountMapperTest, AddMappingMessageSendErrorForMappedAccount) {
537  // Start with one account that is mapped.
538  base::Time status_change_timestamp = base::Time::Now();
539  AccountMapping mapping = MakeAccountMapping("acc_id",
540                                              AccountMapping::MAPPED,
541                                              status_change_timestamp,
542                                              "add_message_id");
543
544  GCMAccountMapper::AccountMappings stored_mappings;
545  stored_mappings.push_back(mapping);
546  mapper()->Initialize(stored_mappings);
547  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
548
549  clock()->SetNow(base::Time::Now());
550  gcm_driver().MessageSendError("add_message_id");
551
552  // No new message is sent because of the send error, as the token is stale.
553  // Because the account was new, the entry should be deleted.
554  EXPECT_TRUE(gcm_driver().last_message_id().empty());
555
556  GCMAccountMapper::AccountMappings mappings = GetAccounts();
557  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
558  EXPECT_EQ(mapping.email, iter->email);
559  EXPECT_EQ(mapping.account_id, iter->account_id);
560  EXPECT_EQ(mapping.access_token, iter->access_token);
561  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
562  EXPECT_EQ(status_change_timestamp, iter->status_change_timestamp);
563  EXPECT_TRUE(iter->last_message_id.empty());
564}
565
566// Tests that a missing token for an account will trigger removing of that
567// account. This test goes only until the message is passed to GCM.
568TEST_F(GCMAccountMapperTest, RemoveMappingToMessageSent) {
569  // Start with one account that is mapped.
570  AccountMapping mapping = MakeAccountMapping("acc_id",
571                                              AccountMapping::MAPPED,
572                                              base::Time::Now(),
573                                              std::string());
574
575  GCMAccountMapper::AccountMappings stored_mappings;
576  stored_mappings.push_back(mapping);
577  mapper()->Initialize(stored_mappings);
578  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
579  clock()->SetNow(base::Time::Now());
580
581  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
582
583  EXPECT_EQ(mapping.account_id, gcm_driver().last_account_mapping().account_id);
584  EXPECT_EQ(mapping.email, gcm_driver().last_account_mapping().email);
585  EXPECT_EQ(AccountMapping::REMOVING,
586            gcm_driver().last_account_mapping().status);
587  EXPECT_EQ(clock()->Now(),
588            gcm_driver().last_account_mapping().status_change_timestamp);
589  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
590
591  GCMAccountMapper::AccountMappings mappings = GetAccounts();
592  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
593  EXPECT_EQ(mapping.email, iter->email);
594  EXPECT_EQ(mapping.account_id, iter->account_id);
595  EXPECT_EQ(mapping.access_token, iter->access_token);
596  EXPECT_EQ(AccountMapping::REMOVING, iter->status);
597  EXPECT_EQ(clock()->Now(), iter->status_change_timestamp);
598  EXPECT_TRUE(iter->last_message_id.empty());
599}
600
601// Tests that a missing token for an account will trigger removing of that
602// account. This test goes until the message is queued by GCM.
603TEST_F(GCMAccountMapperTest, RemoveMappingMessageQueued) {
604  // Start with one account that is mapped.
605  AccountMapping mapping = MakeAccountMapping("acc_id",
606                                              AccountMapping::MAPPED,
607                                              base::Time::Now(),
608                                              std::string());
609
610  GCMAccountMapper::AccountMappings stored_mappings;
611  stored_mappings.push_back(mapping);
612  mapper()->Initialize(stored_mappings);
613  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
614  clock()->SetNow(base::Time::Now());
615  base::Time status_change_timestamp = clock()->Now();
616
617  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
618  clock()->SetNow(base::Time::Now());
619  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
620
621  EXPECT_EQ(mapping.account_id, gcm_driver().last_account_mapping().account_id);
622  EXPECT_EQ(mapping.email, gcm_driver().last_account_mapping().email);
623  EXPECT_EQ(AccountMapping::REMOVING,
624            gcm_driver().last_account_mapping().status);
625  EXPECT_EQ(status_change_timestamp,
626            gcm_driver().last_account_mapping().status_change_timestamp);
627  EXPECT_TRUE(!gcm_driver().last_account_mapping().last_message_id.empty());
628
629  GCMAccountMapper::AccountMappings mappings = GetAccounts();
630  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
631  EXPECT_EQ(mapping.email, iter->email);
632  EXPECT_EQ(mapping.account_id, iter->account_id);
633  EXPECT_EQ(mapping.access_token, iter->access_token);
634  EXPECT_EQ(AccountMapping::REMOVING, iter->status);
635  EXPECT_EQ(status_change_timestamp, iter->status_change_timestamp);
636  EXPECT_EQ(gcm_driver().last_account_mapping().last_message_id,
637            iter->last_message_id);
638}
639
640// Tests that a missing token for an account will trigger removing of that
641// account. This test goes until the message is acknowledged by GCM.
642// This is a complete success scenario for account removal, and it end with
643// account mapping being completely gone.
644TEST_F(GCMAccountMapperTest, RemoveMappingMessageAcknowledged) {
645  // Start with one account that is mapped.
646  AccountMapping mapping = MakeAccountMapping("acc_id",
647                                              AccountMapping::MAPPED,
648                                              base::Time::Now(),
649                                              std::string());
650
651  GCMAccountMapper::AccountMappings stored_mappings;
652  stored_mappings.push_back(mapping);
653  mapper()->Initialize(stored_mappings);
654  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
655  clock()->SetNow(base::Time::Now());
656
657  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
658  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
659  gcm_driver().AcknowledgeSend(gcm_driver().last_message_id());
660
661  EXPECT_EQ(mapping.account_id, gcm_driver().last_removed_account_id());
662
663  GCMAccountMapper::AccountMappings mappings = GetAccounts();
664  EXPECT_TRUE(mappings.empty());
665}
666
667// Tests that account removing proceeds, when a removing message is acked after
668// Chrome was restarted.
669TEST_F(GCMAccountMapperTest, RemoveMappingMessageAckedAfterRestart) {
670  // Start with one account that is mapped.
671  AccountMapping mapping = MakeAccountMapping("acc_id",
672                                              AccountMapping::REMOVING,
673                                              base::Time::Now(),
674                                              "remove_message_id");
675
676  GCMAccountMapper::AccountMappings stored_mappings;
677  stored_mappings.push_back(mapping);
678  mapper()->Initialize(stored_mappings);
679
680  gcm_driver().AcknowledgeSend("remove_message_id");
681
682  EXPECT_EQ(mapping.account_id, gcm_driver().last_removed_account_id());
683
684  GCMAccountMapper::AccountMappings mappings = GetAccounts();
685  EXPECT_TRUE(mappings.empty());
686}
687
688// Tests that account removing proceeds, when a removing message is acked after
689// Chrome was restarted.
690TEST_F(GCMAccountMapperTest, RemoveMappingMessageSendError) {
691  // Start with one account that is mapped.
692  base::Time status_change_timestamp = base::Time::Now();
693  AccountMapping mapping = MakeAccountMapping("acc_id",
694                                              AccountMapping::REMOVING,
695                                              status_change_timestamp,
696                                              "remove_message_id");
697
698  GCMAccountMapper::AccountMappings stored_mappings;
699  stored_mappings.push_back(mapping);
700  mapper()->Initialize(stored_mappings);
701
702  clock()->SetNow(base::Time::Now());
703  gcm_driver().MessageSendError("remove_message_id");
704
705  EXPECT_TRUE(gcm_driver().last_removed_account_id().empty());
706
707  EXPECT_EQ(mapping.account_id, gcm_driver().last_account_mapping().account_id);
708  EXPECT_EQ(mapping.email, gcm_driver().last_account_mapping().email);
709  EXPECT_EQ(AccountMapping::REMOVING,
710            gcm_driver().last_account_mapping().status);
711  EXPECT_EQ(status_change_timestamp,
712            gcm_driver().last_account_mapping().status_change_timestamp);
713  // Message is not persisted, until send is completed.
714  EXPECT_TRUE(gcm_driver().last_account_mapping().last_message_id.empty());
715
716  GCMAccountMapper::AccountMappings mappings = GetAccounts();
717  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
718  EXPECT_EQ(mapping.email, iter->email);
719  EXPECT_EQ(mapping.account_id, iter->account_id);
720  EXPECT_TRUE(iter->access_token.empty());
721  EXPECT_EQ(AccountMapping::REMOVING, iter->status);
722  EXPECT_EQ(status_change_timestamp, iter->status_change_timestamp);
723  EXPECT_TRUE(iter->last_message_id.empty());
724}
725
726// Tests that, if a new token arrives when the adding message is in progress
727// no new message is sent and account mapper still waits for the first one to
728// complete.
729TEST_F(GCMAccountMapperTest, TokenIsRefreshedWhenAdding) {
730  mapper()->Initialize(GCMAccountMapper::AccountMappings());
731  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
732
733  clock()->SetNow(base::Time::Now());
734  std::vector<GCMClient::AccountTokenInfo> account_tokens;
735  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
736  account_tokens.push_back(account_token);
737  mapper()->SetAccountTokens(account_tokens);
738  DCHECK_EQ(CustomFakeGCMDriver::SEND_STARTED, gcm_driver().last_action());
739
740  clock()->SetNow(base::Time::Now());
741  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
742  DCHECK_EQ(CustomFakeGCMDriver::SEND_FINISHED, gcm_driver().last_action());
743
744  // Providing another token and clearing status.
745  gcm_driver().Clear();
746  mapper()->SetAccountTokens(account_tokens);
747  DCHECK_EQ(CustomFakeGCMDriver::NONE, gcm_driver().last_action());
748}
749
750// Tests that, if a new token arrives when a removing message is in progress
751// a new adding message is sent and while account mapping status is changed to
752// mapped. If the original Removing message arrives it is discarded.
753TEST_F(GCMAccountMapperTest, TokenIsRefreshedWhenRemoving) {
754  // Start with one account that is mapped.
755  AccountMapping mapping = MakeAccountMapping(
756      "acc_id", AccountMapping::MAPPED, base::Time::Now(), std::string());
757
758  GCMAccountMapper::AccountMappings stored_mappings;
759  stored_mappings.push_back(mapping);
760  mapper()->Initialize(stored_mappings);
761  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
762  clock()->SetNow(base::Time::Now());
763
764  // Remove the token to trigger a remove message to be sent
765  mapper()->SetAccountTokens(std::vector<GCMClient::AccountTokenInfo>());
766  EXPECT_EQ(CustomFakeGCMDriver::SEND_STARTED, gcm_driver().last_action());
767  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
768  EXPECT_EQ(CustomFakeGCMDriver::SEND_FINISHED, gcm_driver().last_action());
769
770  std::string remove_message_id = gcm_driver().last_message_id();
771  gcm_driver().Clear();
772
773  // The account mapping for acc_id is now in status REMOVING.
774  // Adding the token for that account.
775  clock()->SetNow(base::Time::Now());
776  std::vector<GCMClient::AccountTokenInfo> account_tokens;
777  GCMClient::AccountTokenInfo account_token = MakeAccountTokenInfo("acc_id");
778  account_tokens.push_back(account_token);
779  mapper()->SetAccountTokens(account_tokens);
780  DCHECK_EQ(CustomFakeGCMDriver::SEND_STARTED, gcm_driver().last_action());
781  gcm_driver().CompleteSend(gcm_driver().last_message_id(), GCMClient::SUCCESS);
782  EXPECT_EQ(CustomFakeGCMDriver::SEND_FINISHED, gcm_driver().last_action());
783
784  std::string add_message_id = gcm_driver().last_message_id();
785
786  // A remove message confirmation arrives now, but should be ignored.
787  gcm_driver().AcknowledgeSend(remove_message_id);
788
789  GCMAccountMapper::AccountMappings mappings = GetAccounts();
790  GCMAccountMapper::AccountMappings::const_iterator iter = mappings.begin();
791  EXPECT_EQ(mapping.email, iter->email);
792  EXPECT_EQ(mapping.account_id, iter->account_id);
793  EXPECT_FALSE(iter->access_token.empty());
794  EXPECT_EQ(AccountMapping::MAPPED, iter->status);
795  // Status change timestamp is set to very long time ago, to make sure the next
796  // round of mapping picks it up.
797  EXPECT_EQ(base::Time(), iter->status_change_timestamp);
798  EXPECT_EQ(add_message_id, iter->last_message_id);
799}
800
801// Tests adding/removing works for multiple accounts, after a restart and when
802// tokens are periodically delierverd.
803TEST_F(GCMAccountMapperTest, MultipleAccountMappings) {
804  clock()->SetNow(base::Time::Now());
805  base::Time half_hour_ago = clock()->Now() - base::TimeDelta::FromMinutes(30);
806  GCMAccountMapper::AccountMappings stored_mappings;
807  stored_mappings.push_back(MakeAccountMapping(
808      "acc_id_0", AccountMapping::ADDING, half_hour_ago, "acc_id_0_msg"));
809  stored_mappings.push_back(MakeAccountMapping(
810      "acc_id_1", AccountMapping::MAPPED, half_hour_ago, "acc_id_1_msg"));
811  stored_mappings.push_back(MakeAccountMapping(
812      "acc_id_2", AccountMapping::REMOVING, half_hour_ago, "acc_id_2_msg"));
813
814  mapper()->Initialize(stored_mappings);
815  gcm_driver().CompleteRegister(kRegistrationId, GCMClient::SUCCESS);
816
817  GCMAccountMapper::AccountMappings expected_mappings(stored_mappings);
818
819  // Finish messages after a restart.
820  clock()->SetNow(base::Time::Now());
821  gcm_driver().AcknowledgeSend(expected_mappings[0].last_message_id);
822  expected_mappings[0].status_change_timestamp = clock()->Now();
823  expected_mappings[0].status = AccountMapping::MAPPED;
824  expected_mappings[0].last_message_id.clear();
825
826  clock()->SetNow(base::Time::Now());
827  gcm_driver().AcknowledgeSend(expected_mappings[1].last_message_id);
828  expected_mappings[1].status_change_timestamp = clock()->Now();
829  expected_mappings[1].status = AccountMapping::MAPPED;
830  expected_mappings[1].last_message_id.clear();
831
832  // Upon success last element is removed.
833  clock()->SetNow(base::Time::Now());
834  gcm_driver().AcknowledgeSend(expected_mappings[2].last_message_id);
835  expected_mappings.pop_back();
836
837  VerifyMappings(expected_mappings, GetAccounts(), "Step 1, After restart");
838
839  // One of accounts gets removed.
840  std::vector<GCMClient::AccountTokenInfo> account_tokens;
841  account_tokens.push_back(MakeAccountTokenInfo("acc_id_0"));
842
843  // Advance a day to make sure existing mappings will be reported.
844  clock()->SetNow(clock()->Now() + base::TimeDelta::FromDays(1));
845  mapper()->SetAccountTokens(account_tokens);
846
847  expected_mappings[0].status = AccountMapping::MAPPED;
848  expected_mappings[1].status = AccountMapping::REMOVING;
849  expected_mappings[1].status_change_timestamp = clock()->Now();
850
851  gcm_driver().CompleteSendAllMessages();
852
853  VerifyMappings(
854      expected_mappings, GetAccounts(), "Step 2, One account is being removed");
855
856  clock()->SetNow(clock()->Now() + base::TimeDelta::FromSeconds(5));
857  gcm_driver().AcknowledgeSendAllMessages();
858
859  expected_mappings[0].status_change_timestamp = clock()->Now();
860  expected_mappings.pop_back();
861
862  VerifyMappings(
863      expected_mappings, GetAccounts(), "Step 3, Removing completed");
864
865  account_tokens.clear();
866  account_tokens.push_back(MakeAccountTokenInfo("acc_id_0"));
867  account_tokens.push_back(MakeAccountTokenInfo("acc_id_3"));
868  account_tokens.push_back(MakeAccountTokenInfo("acc_id_4"));
869
870  // Advance a day to make sure existing mappings will be reported.
871  clock()->SetNow(clock()->Now() + base::TimeDelta::FromDays(1));
872  mapper()->SetAccountTokens(account_tokens);
873
874  // Mapping from acc_id_0 still in position 0
875  expected_mappings.push_back(MakeAccountMapping(
876      "acc_id_3", AccountMapping::NEW, base::Time(), std::string()));
877  expected_mappings.push_back(MakeAccountMapping(
878      "acc_id_4", AccountMapping::NEW, base::Time(), std::string()));
879
880  VerifyMappings(expected_mappings, GetAccounts(), "Step 4, Two new accounts");
881
882  clock()->SetNow(clock()->Now() + base::TimeDelta::FromSeconds(1));
883  gcm_driver().CompleteSendAllMessages();
884
885  expected_mappings[1].status = AccountMapping::ADDING;
886  expected_mappings[1].status_change_timestamp = clock()->Now();
887  expected_mappings[2].status = AccountMapping::ADDING;
888  expected_mappings[2].status_change_timestamp = clock()->Now();
889
890  VerifyMappings(
891      expected_mappings, GetAccounts(), "Step 5, Two accounts being added");
892
893  clock()->SetNow(clock()->Now() + base::TimeDelta::FromSeconds(5));
894  gcm_driver().AcknowledgeSendAllMessages();
895
896  expected_mappings[0].status_change_timestamp = clock()->Now();
897  expected_mappings[1].status_change_timestamp = clock()->Now();
898  expected_mappings[1].status = AccountMapping::MAPPED;
899  expected_mappings[2].status_change_timestamp = clock()->Now();
900  expected_mappings[2].status = AccountMapping::MAPPED;
901
902  VerifyMappings(
903      expected_mappings, GetAccounts(), "Step 6, Three mapped accounts");
904}
905
906}  // namespace gcm
907