Home | History | Annotate | Download | only in engine
      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 "sync/engine/model_type_sync_worker_impl.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "sync/engine/commit_contribution.h"
      9 #include "sync/engine/model_type_sync_proxy.h"
     10 #include "sync/internal_api/public/base/model_type.h"
     11 #include "sync/internal_api/public/non_blocking_sync_common.h"
     12 #include "sync/protocol/sync.pb.h"
     13 #include "sync/sessions/status_controller.h"
     14 #include "sync/syncable/syncable_util.h"
     15 #include "sync/test/engine/mock_model_type_sync_proxy.h"
     16 #include "sync/test/engine/mock_nudge_handler.h"
     17 #include "sync/test/engine/single_type_mock_server.h"
     18 #include "sync/test/fake_encryptor.h"
     19 
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 static const std::string kTypeParentId = "PrefsRootNodeID";
     23 static const syncer::ModelType kModelType = syncer::PREFERENCES;
     24 
     25 // Special constant value taken from cryptographer.cc.
     26 const char kNigoriKeyName[] = "nigori-key";
     27 
     28 namespace syncer {
     29 
     30 // Tests the ModelTypeSyncWorkerImpl.
     31 //
     32 // This class passes messages between the model thread and sync server.
     33 // As such, its code is subject to lots of different race conditions.  This
     34 // test harness lets us exhaustively test all possible races.  We try to
     35 // focus on just a few interesting cases.
     36 //
     37 // Inputs:
     38 // - Initial data type state from the model thread.
     39 // - Commit requests from the model thread.
     40 // - Update responses from the server.
     41 // - Commit responses from the server.
     42 // - The cryptographer, if encryption is enabled.
     43 //
     44 // Outputs:
     45 // - Commit requests to the server.
     46 // - Commit responses to the model thread.
     47 // - Update responses to the model thread.
     48 // - Nudges to the sync scheduler.
     49 //
     50 // We use the MockModelTypeSyncProxy to stub out all communication
     51 // with the model thread.  That interface is synchronous, which makes it
     52 // much easier to test races.
     53 //
     54 // The interface with the server is built around "pulling" data from this
     55 // class, so we don't have to mock out any of it.  We wrap it with some
     56 // convenience functions to we can emulate server behavior.
     57 class ModelTypeSyncWorkerImplTest : public ::testing::Test {
     58  public:
     59   ModelTypeSyncWorkerImplTest();
     60   virtual ~ModelTypeSyncWorkerImplTest();
     61 
     62   // One of these Initialize functions should be called at the beginning of
     63   // each test.
     64 
     65   // Initializes with no data type state.  We will be unable to perform any
     66   // significant server action until we receive an update response that
     67   // contains the type root node for this type.
     68   void FirstInitialize();
     69 
     70   // Initializes with some existing data type state.  Allows us to start
     71   // committing items right away.
     72   void NormalInitialize();
     73 
     74   // Initialize with some saved pending updates from the model thread.
     75   void InitializeWithPendingUpdates(
     76       const UpdateResponseDataList& initial_pending_updates);
     77 
     78   // Initialize with a custom initial DataTypeState and pending updates.
     79   void InitializeWithState(const DataTypeState& state,
     80                            const UpdateResponseDataList& pending_updates);
     81 
     82   // Introduce a new key that the local cryptographer can't decrypt.
     83   void NewForeignEncryptionKey();
     84 
     85   // Update the local cryptographer with all relevant keys.
     86   void UpdateLocalCryptographer();
     87 
     88   // Use the Nth nigori instance to encrypt incoming updates.
     89   // The default value, zero, indicates no encryption.
     90   void SetUpdateEncryptionFilter(int n);
     91 
     92   // Modifications on the model thread that get sent to the worker under test.
     93   void CommitRequest(const std::string& tag, const std::string& value);
     94   void DeleteRequest(const std::string& tag);
     95 
     96   // Pretends to receive update messages from the server.
     97   void TriggerTypeRootUpdateFromServer();
     98   void TriggerUpdateFromServer(int64 version_offset,
     99                                const std::string& tag,
    100                                const std::string& value);
    101   void TriggerTombstoneFromServer(int64 version_offset, const std::string& tag);
    102 
    103   // Delivers specified protos as updates.
    104   //
    105   // Does not update mock server state.  Should be used as a last resort when
    106   // writing test cases that require entities that don't fit the normal sync
    107   // protocol.  Try to use the other, higher level methods if possible.
    108   void DeliverRawUpdates(const SyncEntityList& update_list);
    109 
    110   // By default, this harness behaves as if all tasks posted to the model
    111   // thread are executed immediately.  However, this is not necessarily true.
    112   // The model's TaskRunner has a queue, and the tasks we post to it could
    113   // linger there for a while.  In the meantime, the model thread could
    114   // continue posting tasks to the worker based on its stale state.
    115   //
    116   // If you want to test those race cases, then these functions are for you.
    117   void SetModelThreadIsSynchronous(bool is_synchronous);
    118   void PumpModelThread();
    119 
    120   // Returns true if the |worker_| is ready to commit something.
    121   bool WillCommit();
    122 
    123   // Pretend to successfully commit all outstanding unsynced items.
    124   // It is safe to call this only if WillCommit() returns true.
    125   void DoSuccessfulCommit();
    126 
    127   // Read commit messages the worker_ sent to the emulated server.
    128   size_t GetNumCommitMessagesOnServer() const;
    129   sync_pb::ClientToServerMessage GetNthCommitMessageOnServer(size_t n) const;
    130 
    131   // Read the latest version of sync entities committed to the emulated server.
    132   bool HasCommitEntityOnServer(const std::string& tag) const;
    133   sync_pb::SyncEntity GetLatestCommitEntityOnServer(
    134       const std::string& tag) const;
    135 
    136   // Read the latest update messages received on the model thread.
    137   // Note that if the model thread is in non-blocking mode, this data will not
    138   // be updated until the response is actually processed by the model thread.
    139   size_t GetNumModelThreadUpdateResponses() const;
    140   UpdateResponseDataList GetNthModelThreadUpdateResponse(size_t n) const;
    141   UpdateResponseDataList GetNthModelThreadPendingUpdates(size_t n) const;
    142   DataTypeState GetNthModelThreadUpdateState(size_t n) const;
    143 
    144   // Reads the latest update response datas on the model thread.
    145   // Note that if the model thread is in non-blocking mode, this data will not
    146   // be updated until the response is actually processed by the model thread.
    147   bool HasUpdateResponseOnModelThread(const std::string& tag) const;
    148   UpdateResponseData GetUpdateResponseOnModelThread(
    149       const std::string& tag) const;
    150 
    151   // Read the latest commit messages received on the model thread.
    152   // Note that if the model thread is in non-blocking mode, this data will not
    153   // be updated until the response is actually processed by the model thread.
    154   size_t GetNumModelThreadCommitResponses() const;
    155   CommitResponseDataList GetNthModelThreadCommitResponse(size_t n) const;
    156   DataTypeState GetNthModelThreadCommitState(size_t n) const;
    157 
    158   // Reads the latest commit response datas on the model thread.
    159   // Note that if the model thread is in non-blocking mode, this data will not
    160   // be updated until the response is actually processed by the model thread.
    161   bool HasCommitResponseOnModelThread(const std::string& tag) const;
    162   CommitResponseData GetCommitResponseOnModelThread(
    163       const std::string& tag) const;
    164 
    165   // Returns the number of commit nudges sent to the mock nudge handler.
    166   int GetNumCommitNudges() const;
    167 
    168   // Returns the number of initial sync nudges sent to the mock nudge handler.
    169   int GetNumInitialDownloadNudges() const;
    170 
    171   // Returns the name of the encryption key in the cryptographer last passed to
    172   // the ModelTypeSyncWorker.  Returns an empty string if no crypgorapher is
    173   // in use.  See also: UpdateLocalCryptographer().
    174   std::string GetLocalCryptographerKeyName() const;
    175 
    176   // Helpers for building various messages and structures.
    177   static std::string GenerateTagHash(const std::string& tag);
    178   static sync_pb::EntitySpecifics GenerateSpecifics(const std::string& tag,
    179                                                     const std::string& value);
    180 
    181   // Returns a set of KeyParams for the cryptographer.  Each input 'n' value
    182   // results in a different set of parameters.
    183   static KeyParams GetNthKeyParams(int n);
    184 
    185   // Returns the name for the given Nigori.
    186   //
    187   // Uses some 'white-box' knowledge to mimic the names that a real sync client
    188   // would generate.  It's probably not necessary to do so, but it can't hurt.
    189   static std::string GetNigoriName(const Nigori& nigori);
    190 
    191   // Modifies the input/output parameter |specifics| by encrypting it with
    192   // a Nigori intialized with the specified KeyParams.
    193   static void EncryptUpdate(const KeyParams& params,
    194                             sync_pb::EntitySpecifics* specifics);
    195 
    196  private:
    197   // An encryptor for our cryptographer.
    198   FakeEncryptor fake_encryptor_;
    199 
    200   // The cryptographer itself.  NULL if we're not encrypting the type.
    201   scoped_ptr<Cryptographer> cryptographer_;
    202 
    203   // The number of the most recent foreign encryption key known to our
    204   // cryptographer.  Note that not all of these will be decryptable.
    205   int foreign_encryption_key_index_;
    206 
    207   // The number of the encryption key used to encrypt incoming updates.  A zero
    208   // value implies no encryption.
    209   int update_encryption_filter_index_;
    210 
    211   // The ModelTypeSyncWorkerImpl being tested.
    212   scoped_ptr<ModelTypeSyncWorkerImpl> worker_;
    213 
    214   // Non-owned, possibly NULL pointer.  This object belongs to the
    215   // ModelTypeSyncWorkerImpl under test.
    216   MockModelTypeSyncProxy* mock_type_sync_proxy_;
    217 
    218   // A mock that emulates enough of the sync server that it can be used
    219   // a single UpdateHandler and CommitContributor pair.  In this test
    220   // harness, the |worker_| is both of them.
    221   SingleTypeMockServer mock_server_;
    222 
    223   // A mock to track the number of times the ModelTypeSyncWorker requests to
    224   // sync.
    225   MockNudgeHandler mock_nudge_handler_;
    226 };
    227 
    228 ModelTypeSyncWorkerImplTest::ModelTypeSyncWorkerImplTest()
    229     : foreign_encryption_key_index_(0),
    230       update_encryption_filter_index_(0),
    231       mock_type_sync_proxy_(NULL),
    232       mock_server_(kModelType) {
    233 }
    234 
    235 ModelTypeSyncWorkerImplTest::~ModelTypeSyncWorkerImplTest() {
    236 }
    237 
    238 void ModelTypeSyncWorkerImplTest::FirstInitialize() {
    239   DataTypeState initial_state;
    240   initial_state.progress_marker.set_data_type_id(
    241       GetSpecificsFieldNumberFromModelType(kModelType));
    242   initial_state.next_client_id = 0;
    243 
    244   InitializeWithState(initial_state, UpdateResponseDataList());
    245 }
    246 
    247 void ModelTypeSyncWorkerImplTest::NormalInitialize() {
    248   InitializeWithPendingUpdates(UpdateResponseDataList());
    249 }
    250 
    251 void ModelTypeSyncWorkerImplTest::InitializeWithPendingUpdates(
    252     const UpdateResponseDataList& initial_pending_updates) {
    253   DataTypeState initial_state;
    254   initial_state.progress_marker.set_data_type_id(
    255       GetSpecificsFieldNumberFromModelType(kModelType));
    256   initial_state.progress_marker.set_token("some_saved_progress_token");
    257 
    258   initial_state.next_client_id = 10;
    259   initial_state.type_root_id = kTypeParentId;
    260   initial_state.initial_sync_done = true;
    261 
    262   InitializeWithState(initial_state, initial_pending_updates);
    263 
    264   mock_nudge_handler_.ClearCounters();
    265 }
    266 
    267 void ModelTypeSyncWorkerImplTest::InitializeWithState(
    268     const DataTypeState& state,
    269     const UpdateResponseDataList& initial_pending_updates) {
    270   DCHECK(!worker_);
    271 
    272   // We don't get to own this object.  The |worker_| keeps a scoped_ptr to it.
    273   mock_type_sync_proxy_ = new MockModelTypeSyncProxy();
    274   scoped_ptr<ModelTypeSyncProxy> proxy(mock_type_sync_proxy_);
    275 
    276   scoped_ptr<Cryptographer> cryptographer_copy;
    277   if (cryptographer_) {
    278     cryptographer_copy.reset(new Cryptographer(*cryptographer_));
    279   }
    280 
    281   worker_.reset(new ModelTypeSyncWorkerImpl(kModelType,
    282                                             state,
    283                                             initial_pending_updates,
    284                                             cryptographer_copy.Pass(),
    285                                             &mock_nudge_handler_,
    286                                             proxy.Pass()));
    287 }
    288 
    289 void ModelTypeSyncWorkerImplTest::NewForeignEncryptionKey() {
    290   if (!cryptographer_) {
    291     cryptographer_.reset(new Cryptographer(&fake_encryptor_));
    292   }
    293 
    294   foreign_encryption_key_index_++;
    295 
    296   sync_pb::NigoriKeyBag bag;
    297 
    298   for (int i = 0; i <= foreign_encryption_key_index_; ++i) {
    299     Nigori nigori;
    300     KeyParams params = GetNthKeyParams(i);
    301     nigori.InitByDerivation(params.hostname, params.username, params.password);
    302 
    303     sync_pb::NigoriKey* key = bag.add_key();
    304 
    305     key->set_name(GetNigoriName(nigori));
    306     nigori.ExportKeys(key->mutable_user_key(),
    307                       key->mutable_encryption_key(),
    308                       key->mutable_mac_key());
    309   }
    310 
    311   // Re-create the last nigori from that loop.
    312   Nigori last_nigori;
    313   KeyParams params = GetNthKeyParams(foreign_encryption_key_index_);
    314   last_nigori.InitByDerivation(
    315       params.hostname, params.username, params.password);
    316 
    317   // Serialize and encrypt the bag with the last nigori.
    318   std::string serialized_bag;
    319   bag.SerializeToString(&serialized_bag);
    320 
    321   sync_pb::EncryptedData encrypted;
    322   encrypted.set_key_name(GetNigoriName(last_nigori));
    323   last_nigori.Encrypt(serialized_bag, encrypted.mutable_blob());
    324 
    325   // Update the cryptographer with new pending keys.
    326   cryptographer_->SetPendingKeys(encrypted);
    327 
    328   // Update the worker with the latest cryptographer.
    329   if (worker_) {
    330     worker_->UpdateCryptographer(
    331         make_scoped_ptr<Cryptographer>(new Cryptographer(*cryptographer_)));
    332   }
    333 }
    334 
    335 void ModelTypeSyncWorkerImplTest::UpdateLocalCryptographer() {
    336   if (!cryptographer_) {
    337     cryptographer_.reset(new Cryptographer(&fake_encryptor_));
    338   }
    339 
    340   KeyParams params = GetNthKeyParams(foreign_encryption_key_index_);
    341   bool success = cryptographer_->DecryptPendingKeys(params);
    342   DCHECK(success);
    343 
    344   // Update the worker with the latest cryptographer.
    345   if (worker_) {
    346     worker_->UpdateCryptographer(
    347         make_scoped_ptr<Cryptographer>(new Cryptographer(*cryptographer_)));
    348   }
    349 }
    350 
    351 void ModelTypeSyncWorkerImplTest::SetUpdateEncryptionFilter(int n) {
    352   update_encryption_filter_index_ = n;
    353 }
    354 
    355 void ModelTypeSyncWorkerImplTest::CommitRequest(const std::string& name,
    356                                                 const std::string& value) {
    357   const std::string tag_hash = GenerateTagHash(name);
    358   CommitRequestData data = mock_type_sync_proxy_->CommitRequest(
    359       tag_hash, GenerateSpecifics(name, value));
    360   CommitRequestDataList list;
    361   list.push_back(data);
    362   worker_->EnqueueForCommit(list);
    363 }
    364 
    365 void ModelTypeSyncWorkerImplTest::DeleteRequest(const std::string& tag) {
    366   const std::string tag_hash = GenerateTagHash(tag);
    367   CommitRequestData data = mock_type_sync_proxy_->DeleteRequest(tag_hash);
    368   CommitRequestDataList list;
    369   list.push_back(data);
    370   worker_->EnqueueForCommit(list);
    371 }
    372 
    373 void ModelTypeSyncWorkerImplTest::TriggerTypeRootUpdateFromServer() {
    374   sync_pb::SyncEntity entity = mock_server_.TypeRootUpdate();
    375   SyncEntityList entity_list;
    376   entity_list.push_back(&entity);
    377 
    378   sessions::StatusController dummy_status;
    379 
    380   worker_->ProcessGetUpdatesResponse(mock_server_.GetProgress(),
    381                                      mock_server_.GetContext(),
    382                                      entity_list,
    383                                      &dummy_status);
    384   worker_->ApplyUpdates(&dummy_status);
    385 }
    386 
    387 void ModelTypeSyncWorkerImplTest::TriggerUpdateFromServer(
    388     int64 version_offset,
    389     const std::string& tag,
    390     const std::string& value) {
    391   sync_pb::SyncEntity entity = mock_server_.UpdateFromServer(
    392       version_offset, GenerateTagHash(tag), GenerateSpecifics(tag, value));
    393 
    394   if (update_encryption_filter_index_ != 0) {
    395     EncryptUpdate(GetNthKeyParams(update_encryption_filter_index_),
    396                   entity.mutable_specifics());
    397   }
    398 
    399   SyncEntityList entity_list;
    400   entity_list.push_back(&entity);
    401 
    402   sessions::StatusController dummy_status;
    403 
    404   worker_->ProcessGetUpdatesResponse(mock_server_.GetProgress(),
    405                                      mock_server_.GetContext(),
    406                                      entity_list,
    407                                      &dummy_status);
    408   worker_->ApplyUpdates(&dummy_status);
    409 }
    410 
    411 void ModelTypeSyncWorkerImplTest::DeliverRawUpdates(
    412     const SyncEntityList& list) {
    413   sessions::StatusController dummy_status;
    414   worker_->ProcessGetUpdatesResponse(mock_server_.GetProgress(),
    415                                      mock_server_.GetContext(),
    416                                      list,
    417                                      &dummy_status);
    418   worker_->ApplyUpdates(&dummy_status);
    419 }
    420 
    421 void ModelTypeSyncWorkerImplTest::TriggerTombstoneFromServer(
    422     int64 version_offset,
    423     const std::string& tag) {
    424   sync_pb::SyncEntity entity =
    425       mock_server_.TombstoneFromServer(version_offset, GenerateTagHash(tag));
    426 
    427   if (update_encryption_filter_index_ != 0) {
    428     EncryptUpdate(GetNthKeyParams(update_encryption_filter_index_),
    429                   entity.mutable_specifics());
    430   }
    431 
    432   SyncEntityList entity_list;
    433   entity_list.push_back(&entity);
    434 
    435   sessions::StatusController dummy_status;
    436 
    437   worker_->ProcessGetUpdatesResponse(mock_server_.GetProgress(),
    438                                      mock_server_.GetContext(),
    439                                      entity_list,
    440                                      &dummy_status);
    441   worker_->ApplyUpdates(&dummy_status);
    442 }
    443 
    444 void ModelTypeSyncWorkerImplTest::SetModelThreadIsSynchronous(
    445     bool is_synchronous) {
    446   mock_type_sync_proxy_->SetSynchronousExecution(is_synchronous);
    447 }
    448 
    449 void ModelTypeSyncWorkerImplTest::PumpModelThread() {
    450   mock_type_sync_proxy_->RunQueuedTasks();
    451 }
    452 
    453 bool ModelTypeSyncWorkerImplTest::WillCommit() {
    454   scoped_ptr<CommitContribution> contribution(
    455       worker_->GetContribution(INT_MAX));
    456 
    457   if (contribution) {
    458     contribution->CleanUp();  // Gracefully abort the commit.
    459     return true;
    460   } else {
    461     return false;
    462   }
    463 }
    464 
    465 // Conveniently, this is all one big synchronous operation.  The sync thread
    466 // remains blocked while the commit is in progress, so we don't need to worry
    467 // about other tasks being run between the time when the commit request is
    468 // issued and the time when the commit response is received.
    469 void ModelTypeSyncWorkerImplTest::DoSuccessfulCommit() {
    470   DCHECK(WillCommit());
    471   scoped_ptr<CommitContribution> contribution(
    472       worker_->GetContribution(INT_MAX));
    473 
    474   sync_pb::ClientToServerMessage message;
    475   contribution->AddToCommitMessage(&message);
    476 
    477   sync_pb::ClientToServerResponse response =
    478       mock_server_.DoSuccessfulCommit(message);
    479 
    480   sessions::StatusController dummy_status;
    481   contribution->ProcessCommitResponse(response, &dummy_status);
    482   contribution->CleanUp();
    483 }
    484 
    485 size_t ModelTypeSyncWorkerImplTest::GetNumCommitMessagesOnServer() const {
    486   return mock_server_.GetNumCommitMessages();
    487 }
    488 
    489 sync_pb::ClientToServerMessage
    490 ModelTypeSyncWorkerImplTest::GetNthCommitMessageOnServer(size_t n) const {
    491   DCHECK_LT(n, GetNumCommitMessagesOnServer());
    492   return mock_server_.GetNthCommitMessage(n);
    493 }
    494 
    495 bool ModelTypeSyncWorkerImplTest::HasCommitEntityOnServer(
    496     const std::string& tag) const {
    497   const std::string tag_hash = GenerateTagHash(tag);
    498   return mock_server_.HasCommitEntity(tag_hash);
    499 }
    500 
    501 sync_pb::SyncEntity ModelTypeSyncWorkerImplTest::GetLatestCommitEntityOnServer(
    502     const std::string& tag) const {
    503   DCHECK(HasCommitEntityOnServer(tag));
    504   const std::string tag_hash = GenerateTagHash(tag);
    505   return mock_server_.GetLastCommittedEntity(tag_hash);
    506 }
    507 
    508 size_t ModelTypeSyncWorkerImplTest::GetNumModelThreadUpdateResponses() const {
    509   return mock_type_sync_proxy_->GetNumUpdateResponses();
    510 }
    511 
    512 UpdateResponseDataList
    513 ModelTypeSyncWorkerImplTest::GetNthModelThreadUpdateResponse(size_t n) const {
    514   DCHECK_LT(n, GetNumModelThreadUpdateResponses());
    515   return mock_type_sync_proxy_->GetNthUpdateResponse(n);
    516 }
    517 
    518 UpdateResponseDataList
    519 ModelTypeSyncWorkerImplTest::GetNthModelThreadPendingUpdates(size_t n) const {
    520   DCHECK_LT(n, GetNumModelThreadUpdateResponses());
    521   return mock_type_sync_proxy_->GetNthPendingUpdates(n);
    522 }
    523 
    524 DataTypeState ModelTypeSyncWorkerImplTest::GetNthModelThreadUpdateState(
    525     size_t n) const {
    526   DCHECK_LT(n, GetNumModelThreadUpdateResponses());
    527   return mock_type_sync_proxy_->GetNthTypeStateReceivedInUpdateResponse(n);
    528 }
    529 
    530 bool ModelTypeSyncWorkerImplTest::HasUpdateResponseOnModelThread(
    531     const std::string& tag) const {
    532   const std::string tag_hash = GenerateTagHash(tag);
    533   return mock_type_sync_proxy_->HasUpdateResponse(tag_hash);
    534 }
    535 
    536 UpdateResponseData ModelTypeSyncWorkerImplTest::GetUpdateResponseOnModelThread(
    537     const std::string& tag) const {
    538   const std::string tag_hash = GenerateTagHash(tag);
    539   return mock_type_sync_proxy_->GetUpdateResponse(tag_hash);
    540 }
    541 
    542 size_t ModelTypeSyncWorkerImplTest::GetNumModelThreadCommitResponses() const {
    543   return mock_type_sync_proxy_->GetNumCommitResponses();
    544 }
    545 
    546 CommitResponseDataList
    547 ModelTypeSyncWorkerImplTest::GetNthModelThreadCommitResponse(size_t n) const {
    548   DCHECK_LT(n, GetNumModelThreadCommitResponses());
    549   return mock_type_sync_proxy_->GetNthCommitResponse(n);
    550 }
    551 
    552 DataTypeState ModelTypeSyncWorkerImplTest::GetNthModelThreadCommitState(
    553     size_t n) const {
    554   DCHECK_LT(n, GetNumModelThreadCommitResponses());
    555   return mock_type_sync_proxy_->GetNthTypeStateReceivedInCommitResponse(n);
    556 }
    557 
    558 bool ModelTypeSyncWorkerImplTest::HasCommitResponseOnModelThread(
    559     const std::string& tag) const {
    560   const std::string tag_hash = GenerateTagHash(tag);
    561   return mock_type_sync_proxy_->HasCommitResponse(tag_hash);
    562 }
    563 
    564 CommitResponseData ModelTypeSyncWorkerImplTest::GetCommitResponseOnModelThread(
    565     const std::string& tag) const {
    566   DCHECK(HasCommitResponseOnModelThread(tag));
    567   const std::string tag_hash = GenerateTagHash(tag);
    568   return mock_type_sync_proxy_->GetCommitResponse(tag_hash);
    569 }
    570 
    571 int ModelTypeSyncWorkerImplTest::GetNumCommitNudges() const {
    572   return mock_nudge_handler_.GetNumCommitNudges();
    573 }
    574 
    575 int ModelTypeSyncWorkerImplTest::GetNumInitialDownloadNudges() const {
    576   return mock_nudge_handler_.GetNumInitialDownloadNudges();
    577 }
    578 
    579 std::string ModelTypeSyncWorkerImplTest::GetLocalCryptographerKeyName() const {
    580   if (!cryptographer_) {
    581     return std::string();
    582   }
    583 
    584   return cryptographer_->GetDefaultNigoriKeyName();
    585 }
    586 
    587 // static.
    588 std::string ModelTypeSyncWorkerImplTest::GenerateTagHash(
    589     const std::string& tag) {
    590   const std::string& client_tag_hash =
    591       syncable::GenerateSyncableHash(kModelType, tag);
    592   return client_tag_hash;
    593 }
    594 
    595 // static.
    596 sync_pb::EntitySpecifics ModelTypeSyncWorkerImplTest::GenerateSpecifics(
    597     const std::string& tag,
    598     const std::string& value) {
    599   sync_pb::EntitySpecifics specifics;
    600   specifics.mutable_preference()->set_name(tag);
    601   specifics.mutable_preference()->set_value(value);
    602   return specifics;
    603 }
    604 
    605 // static.
    606 std::string ModelTypeSyncWorkerImplTest::GetNigoriName(const Nigori& nigori) {
    607   std::string name;
    608   if (!nigori.Permute(Nigori::Password, kNigoriKeyName, &name)) {
    609     NOTREACHED();
    610     return std::string();
    611   }
    612 
    613   return name;
    614 }
    615 
    616 // static.
    617 KeyParams ModelTypeSyncWorkerImplTest::GetNthKeyParams(int n) {
    618   KeyParams params;
    619   params.hostname = std::string("localhost");
    620   params.username = std::string("userX");
    621   params.password = base::StringPrintf("pw%02d", n);
    622   return params;
    623 }
    624 
    625 // static.
    626 void ModelTypeSyncWorkerImplTest::EncryptUpdate(
    627     const KeyParams& params,
    628     sync_pb::EntitySpecifics* specifics) {
    629   Nigori nigori;
    630   nigori.InitByDerivation(params.hostname, params.username, params.password);
    631 
    632   sync_pb::EntitySpecifics original_specifics = *specifics;
    633   std::string plaintext;
    634   original_specifics.SerializeToString(&plaintext);
    635 
    636   std::string encrypted;
    637   nigori.Encrypt(plaintext, &encrypted);
    638 
    639   specifics->Clear();
    640   AddDefaultFieldValue(kModelType, specifics);
    641   specifics->mutable_encrypted()->set_key_name(GetNigoriName(nigori));
    642   specifics->mutable_encrypted()->set_blob(encrypted);
    643 }
    644 
    645 // Requests a commit and verifies the messages sent to the client and server as
    646 // a result.
    647 //
    648 // This test performs sanity checks on most of the fields in these messages.
    649 // For the most part this is checking that the test code behaves as expected
    650 // and the |worker_| doesn't mess up its simple task of moving around these
    651 // values.  It makes sense to have one or two tests that are this thorough, but
    652 // we shouldn't be this verbose in all tests.
    653 TEST_F(ModelTypeSyncWorkerImplTest, SimpleCommit) {
    654   NormalInitialize();
    655 
    656   EXPECT_FALSE(WillCommit());
    657   EXPECT_EQ(0U, GetNumCommitMessagesOnServer());
    658   EXPECT_EQ(0U, GetNumModelThreadCommitResponses());
    659 
    660   CommitRequest("tag1", "value1");
    661 
    662   EXPECT_EQ(1, GetNumCommitNudges());
    663 
    664   ASSERT_TRUE(WillCommit());
    665   DoSuccessfulCommit();
    666 
    667   const std::string& client_tag_hash = GenerateTagHash("tag1");
    668 
    669   // Exhaustively verify the SyncEntity sent in the commit message.
    670   ASSERT_EQ(1U, GetNumCommitMessagesOnServer());
    671   EXPECT_EQ(1, GetNthCommitMessageOnServer(0).commit().entries_size());
    672   ASSERT_TRUE(HasCommitEntityOnServer("tag1"));
    673   const sync_pb::SyncEntity& entity = GetLatestCommitEntityOnServer("tag1");
    674   EXPECT_FALSE(entity.id_string().empty());
    675   EXPECT_EQ(kTypeParentId, entity.parent_id_string());
    676   EXPECT_EQ(kUncommittedVersion, entity.version());
    677   EXPECT_NE(0, entity.mtime());
    678   EXPECT_NE(0, entity.ctime());
    679   EXPECT_FALSE(entity.name().empty());
    680   EXPECT_EQ(client_tag_hash, entity.client_defined_unique_tag());
    681   EXPECT_EQ("tag1", entity.specifics().preference().name());
    682   EXPECT_FALSE(entity.deleted());
    683   EXPECT_EQ("value1", entity.specifics().preference().value());
    684 
    685   // Exhaustively verify the commit response returned to the model thread.
    686   ASSERT_EQ(1U, GetNumModelThreadCommitResponses());
    687   EXPECT_EQ(1U, GetNthModelThreadCommitResponse(0).size());
    688   ASSERT_TRUE(HasCommitResponseOnModelThread("tag1"));
    689   const CommitResponseData& commit_response =
    690       GetCommitResponseOnModelThread("tag1");
    691 
    692   // The ID changes in a commit response to initial commit.
    693   EXPECT_FALSE(commit_response.id.empty());
    694   EXPECT_NE(entity.id_string(), commit_response.id);
    695 
    696   EXPECT_EQ(client_tag_hash, commit_response.client_tag_hash);
    697   EXPECT_LT(0, commit_response.response_version);
    698 }
    699 
    700 TEST_F(ModelTypeSyncWorkerImplTest, SimpleDelete) {
    701   NormalInitialize();
    702 
    703   // We can't delete an entity that was never committed.
    704   // Step 1 is to create and commit a new entity.
    705   CommitRequest("tag1", "value1");
    706   EXPECT_EQ(1, GetNumCommitNudges());
    707   ASSERT_TRUE(WillCommit());
    708   DoSuccessfulCommit();
    709 
    710   ASSERT_TRUE(HasCommitResponseOnModelThread("tag1"));
    711   const CommitResponseData& initial_commit_response =
    712       GetCommitResponseOnModelThread("tag1");
    713   int64 base_version = initial_commit_response.response_version;
    714 
    715   // Now that we have an entity, we can delete it.
    716   DeleteRequest("tag1");
    717   ASSERT_TRUE(WillCommit());
    718   DoSuccessfulCommit();
    719 
    720   // Verify the SyncEntity sent in the commit message.
    721   ASSERT_EQ(2U, GetNumCommitMessagesOnServer());
    722   EXPECT_EQ(1, GetNthCommitMessageOnServer(1).commit().entries_size());
    723   ASSERT_TRUE(HasCommitEntityOnServer("tag1"));
    724   const sync_pb::SyncEntity& entity = GetLatestCommitEntityOnServer("tag1");
    725   EXPECT_FALSE(entity.id_string().empty());
    726   EXPECT_EQ(GenerateTagHash("tag1"), entity.client_defined_unique_tag());
    727   EXPECT_EQ(base_version, entity.version());
    728   EXPECT_TRUE(entity.deleted());
    729 
    730   // Deletions should contain enough specifics to identify the type.
    731   EXPECT_TRUE(entity.has_specifics());
    732   EXPECT_EQ(kModelType, GetModelTypeFromSpecifics(entity.specifics()));
    733 
    734   // Verify the commit response returned to the model thread.
    735   ASSERT_EQ(2U, GetNumModelThreadCommitResponses());
    736   EXPECT_EQ(1U, GetNthModelThreadCommitResponse(1).size());
    737   ASSERT_TRUE(HasCommitResponseOnModelThread("tag1"));
    738   const CommitResponseData& commit_response =
    739       GetCommitResponseOnModelThread("tag1");
    740 
    741   EXPECT_EQ(entity.id_string(), commit_response.id);
    742   EXPECT_EQ(entity.client_defined_unique_tag(),
    743             commit_response.client_tag_hash);
    744   EXPECT_EQ(entity.version(), commit_response.response_version);
    745 }
    746 
    747 // The server doesn't like it when we try to delete an entity it's never heard
    748 // of before.  This test helps ensure we avoid that scenario.
    749 TEST_F(ModelTypeSyncWorkerImplTest, NoDeleteUncommitted) {
    750   NormalInitialize();
    751 
    752   // Request the commit of a new, never-before-seen item.
    753   CommitRequest("tag1", "value1");
    754   EXPECT_TRUE(WillCommit());
    755   EXPECT_EQ(1, GetNumCommitNudges());
    756 
    757   // Request a deletion of that item before we've had a chance to commit it.
    758   DeleteRequest("tag1");
    759   EXPECT_FALSE(WillCommit());
    760   EXPECT_EQ(2, GetNumCommitNudges());
    761 }
    762 
    763 // Verifies the sending of an "initial sync done" signal.
    764 TEST_F(ModelTypeSyncWorkerImplTest, SendInitialSyncDone) {
    765   FirstInitialize();  // Initialize with no saved sync state.
    766   EXPECT_EQ(0U, GetNumModelThreadUpdateResponses());
    767   EXPECT_EQ(1, GetNumInitialDownloadNudges());
    768 
    769   // Receive an update response that contains only the type root node.
    770   TriggerTypeRootUpdateFromServer();
    771 
    772   // Two updates:
    773   // - One triggered by process updates to forward the type root ID.
    774   // - One triggered by apply updates, which the worker interprets to mean
    775   //   "initial sync done".  This triggers a model thread update, too.
    776   EXPECT_EQ(2U, GetNumModelThreadUpdateResponses());
    777 
    778   // The type root and initial sync done updates both contain no entities.
    779   EXPECT_EQ(0U, GetNthModelThreadUpdateResponse(0).size());
    780   EXPECT_EQ(0U, GetNthModelThreadUpdateResponse(1).size());
    781 
    782   const DataTypeState& state = GetNthModelThreadUpdateState(1);
    783   EXPECT_FALSE(state.progress_marker.token().empty());
    784   EXPECT_FALSE(state.type_root_id.empty());
    785   EXPECT_TRUE(state.initial_sync_done);
    786 }
    787 
    788 // Commit two new entities in two separate commit messages.
    789 TEST_F(ModelTypeSyncWorkerImplTest, TwoNewItemsCommittedSeparately) {
    790   NormalInitialize();
    791 
    792   // Commit the first of two entities.
    793   CommitRequest("tag1", "value1");
    794   EXPECT_EQ(1, GetNumCommitNudges());
    795   ASSERT_TRUE(WillCommit());
    796   DoSuccessfulCommit();
    797   ASSERT_EQ(1U, GetNumCommitMessagesOnServer());
    798   EXPECT_EQ(1, GetNthCommitMessageOnServer(0).commit().entries_size());
    799   ASSERT_TRUE(HasCommitEntityOnServer("tag1"));
    800   const sync_pb::SyncEntity& tag1_entity =
    801       GetLatestCommitEntityOnServer("tag1");
    802 
    803   // Commit the second of two entities.
    804   CommitRequest("tag2", "value2");
    805   EXPECT_EQ(2, GetNumCommitNudges());
    806   ASSERT_TRUE(WillCommit());
    807   DoSuccessfulCommit();
    808   ASSERT_EQ(2U, GetNumCommitMessagesOnServer());
    809   EXPECT_EQ(1, GetNthCommitMessageOnServer(1).commit().entries_size());
    810   ASSERT_TRUE(HasCommitEntityOnServer("tag2"));
    811   const sync_pb::SyncEntity& tag2_entity =
    812       GetLatestCommitEntityOnServer("tag2");
    813 
    814   EXPECT_FALSE(WillCommit());
    815 
    816   // The IDs assigned by the |worker_| should be unique.
    817   EXPECT_NE(tag1_entity.id_string(), tag2_entity.id_string());
    818 
    819   // Check that the committed specifics values are sane.
    820   EXPECT_EQ(tag1_entity.specifics().preference().value(), "value1");
    821   EXPECT_EQ(tag2_entity.specifics().preference().value(), "value2");
    822 
    823   // There should have been two separate commit responses sent to the model
    824   // thread.  They should be uninteresting, so we don't bother inspecting them.
    825   EXPECT_EQ(2U, GetNumModelThreadCommitResponses());
    826 }
    827 
    828 // Test normal update receipt code path.
    829 TEST_F(ModelTypeSyncWorkerImplTest, ReceiveUpdates) {
    830   NormalInitialize();
    831 
    832   const std::string& tag_hash = GenerateTagHash("tag1");
    833 
    834   TriggerUpdateFromServer(10, "tag1", "value1");
    835 
    836   ASSERT_EQ(1U, GetNumModelThreadUpdateResponses());
    837   UpdateResponseDataList updates_list = GetNthModelThreadUpdateResponse(0);
    838   ASSERT_EQ(1U, updates_list.size());
    839 
    840   ASSERT_TRUE(HasUpdateResponseOnModelThread("tag1"));
    841   UpdateResponseData update = GetUpdateResponseOnModelThread("tag1");
    842 
    843   EXPECT_FALSE(update.id.empty());
    844   EXPECT_EQ(tag_hash, update.client_tag_hash);
    845   EXPECT_LT(0, update.response_version);
    846   EXPECT_FALSE(update.ctime.is_null());
    847   EXPECT_FALSE(update.mtime.is_null());
    848   EXPECT_FALSE(update.non_unique_name.empty());
    849   EXPECT_FALSE(update.deleted);
    850   EXPECT_EQ("tag1", update.specifics.preference().name());
    851   EXPECT_EQ("value1", update.specifics.preference().value());
    852 }
    853 
    854 // Test commit of encrypted updates.
    855 TEST_F(ModelTypeSyncWorkerImplTest, EncryptedCommit) {
    856   NormalInitialize();
    857 
    858   ASSERT_EQ(0U, GetNumModelThreadUpdateResponses());
    859 
    860   NewForeignEncryptionKey();
    861   UpdateLocalCryptographer();
    862 
    863   ASSERT_EQ(1U, GetNumModelThreadUpdateResponses());
    864   EXPECT_EQ(GetLocalCryptographerKeyName(),
    865             GetNthModelThreadUpdateState(0).encryption_key_name);
    866 
    867   // Normal commit request stuff.
    868   CommitRequest("tag1", "value1");
    869   DoSuccessfulCommit();
    870   ASSERT_EQ(1U, GetNumCommitMessagesOnServer());
    871   EXPECT_EQ(1, GetNthCommitMessageOnServer(0).commit().entries_size());
    872   ASSERT_TRUE(HasCommitEntityOnServer("tag1"));
    873   const sync_pb::SyncEntity& tag1_entity =
    874       GetLatestCommitEntityOnServer("tag1");
    875 
    876   EXPECT_TRUE(tag1_entity.specifics().has_encrypted());
    877 
    878   // The title should be overwritten.
    879   EXPECT_EQ(tag1_entity.name(), "encrypted");
    880 
    881   // The type should be set, but there should be no non-encrypted contents.
    882   EXPECT_TRUE(tag1_entity.specifics().has_preference());
    883   EXPECT_FALSE(tag1_entity.specifics().preference().has_name());
    884   EXPECT_FALSE(tag1_entity.specifics().preference().has_value());
    885 }
    886 
    887 // Test items are not committed when encryption is required but unavailable.
    888 TEST_F(ModelTypeSyncWorkerImplTest, EncryptionBlocksCommits) {
    889   NormalInitialize();
    890 
    891   CommitRequest("tag1", "value1");
    892   EXPECT_TRUE(WillCommit());
    893 
    894   // We know encryption is in use on this account, but don't have the necessary
    895   // encryption keys.  The worker should refuse to commit.
    896   NewForeignEncryptionKey();
    897   EXPECT_FALSE(WillCommit());
    898 
    899   // Once the cryptographer is returned to a normal state, we should be able to
    900   // commit again.
    901   EXPECT_EQ(1, GetNumCommitNudges());
    902   UpdateLocalCryptographer();
    903   EXPECT_EQ(2, GetNumCommitNudges());
    904   EXPECT_TRUE(WillCommit());
    905 
    906   // Verify the committed entity was properly encrypted.
    907   DoSuccessfulCommit();
    908   ASSERT_EQ(1U, GetNumCommitMessagesOnServer());
    909   EXPECT_EQ(1, GetNthCommitMessageOnServer(0).commit().entries_size());
    910   ASSERT_TRUE(HasCommitEntityOnServer("tag1"));
    911   const sync_pb::SyncEntity& tag1_entity =
    912       GetLatestCommitEntityOnServer("tag1");
    913   EXPECT_TRUE(tag1_entity.specifics().has_encrypted());
    914   EXPECT_EQ(tag1_entity.name(), "encrypted");
    915   EXPECT_TRUE(tag1_entity.specifics().has_preference());
    916   EXPECT_FALSE(tag1_entity.specifics().preference().has_name());
    917   EXPECT_FALSE(tag1_entity.specifics().preference().has_value());
    918 }
    919 
    920 // Test the receipt of decryptable entities.
    921 TEST_F(ModelTypeSyncWorkerImplTest, ReceiveDecryptableEntities) {
    922   NormalInitialize();
    923 
    924   // Create a new Nigori and allow the cryptographer to decrypt it.
    925   NewForeignEncryptionKey();
    926   UpdateLocalCryptographer();
    927 
    928   // First, receive an unencrypted entry.
    929   TriggerUpdateFromServer(10, "tag1", "value1");
    930 
    931   // Test some basic properties regarding the update.
    932   ASSERT_TRUE(HasUpdateResponseOnModelThread("tag1"));
    933   UpdateResponseData update1 = GetUpdateResponseOnModelThread("tag1");
    934   EXPECT_EQ("tag1", update1.specifics.preference().name());
    935   EXPECT_EQ("value1", update1.specifics.preference().value());
    936   EXPECT_TRUE(update1.encryption_key_name.empty());
    937 
    938   // Set received updates to be encrypted using the new nigori.
    939   SetUpdateEncryptionFilter(1);
    940 
    941   // This next update will be encrypted.
    942   TriggerUpdateFromServer(10, "tag2", "value2");
    943 
    944   // Test its basic features and the value of encryption_key_name.
    945   ASSERT_TRUE(HasUpdateResponseOnModelThread("tag2"));
    946   UpdateResponseData update2 = GetUpdateResponseOnModelThread("tag2");
    947   EXPECT_EQ("tag2", update2.specifics.preference().name());
    948   EXPECT_EQ("value2", update2.specifics.preference().value());
    949   EXPECT_FALSE(update2.encryption_key_name.empty());
    950 }
    951 
    952 // Test initializing a ModelTypeSyncWorker with a cryptographer at startup.
    953 TEST_F(ModelTypeSyncWorkerImplTest, InitializeWithCryptographer) {
    954   // Set up some encryption state.
    955   NewForeignEncryptionKey();
    956   UpdateLocalCryptographer();
    957 
    958   // Then initialize.
    959   NormalInitialize();
    960 
    961   // The worker should tell the model thread about encryption as soon as
    962   // possible, so that it will have the chance to re-encrypt local data if
    963   // necessary.
    964   ASSERT_EQ(1U, GetNumModelThreadUpdateResponses());
    965   EXPECT_EQ(GetLocalCryptographerKeyName(),
    966             GetNthModelThreadUpdateState(0).encryption_key_name);
    967 }
    968 
    969 // Receive updates that are initially undecryptable, then ensure they get
    970 // delivered to the model thread when decryption becomes possible.
    971 TEST_F(ModelTypeSyncWorkerImplTest, ReceiveUndecryptableEntries) {
    972   NormalInitialize();
    973 
    974   // Receive a new foreign encryption key that we can't decrypt.
    975   NewForeignEncryptionKey();
    976 
    977   // Receive an encrypted with that new key, which we can't access.
    978   SetUpdateEncryptionFilter(1);
    979   TriggerUpdateFromServer(10, "tag1", "value1");
    980 
    981   // At this point, the cryptographer does not have access to the key, so the
    982   // updates will be undecryptable.  They'll be transfered to the model thread
    983   // for safe-keeping as pending updates.
    984   ASSERT_EQ(1U, GetNumModelThreadUpdateResponses());
    985   UpdateResponseDataList updates_list = GetNthModelThreadUpdateResponse(0);
    986   EXPECT_EQ(0U, updates_list.size());
    987   UpdateResponseDataList pending_updates = GetNthModelThreadPendingUpdates(0);
    988   EXPECT_EQ(1U, pending_updates.size());
    989 
    990   // The update will be delivered as soon as decryption becomes possible.
    991   UpdateLocalCryptographer();
    992   ASSERT_TRUE(HasUpdateResponseOnModelThread("tag1"));
    993   UpdateResponseData update = GetUpdateResponseOnModelThread("tag1");
    994   EXPECT_EQ("tag1", update.specifics.preference().name());
    995   EXPECT_EQ("value1", update.specifics.preference().value());
    996   EXPECT_FALSE(update.encryption_key_name.empty());
    997 }
    998 
    999 // Ensure that even encrypted updates can cause conflicts.
   1000 TEST_F(ModelTypeSyncWorkerImplTest, EncryptedUpdateOverridesPendingCommit) {
   1001   NormalInitialize();
   1002 
   1003   // Prepeare to commit an item.
   1004   CommitRequest("tag1", "value1");
   1005   EXPECT_TRUE(WillCommit());
   1006 
   1007   // Receive an encrypted update for that item.
   1008   SetUpdateEncryptionFilter(1);
   1009   TriggerUpdateFromServer(10, "tag1", "value1");
   1010 
   1011   // The pending commit state should be cleared.
   1012   EXPECT_FALSE(WillCommit());
   1013 
   1014   // The encrypted update will be delivered to the model thread.
   1015   ASSERT_EQ(1U, GetNumModelThreadUpdateResponses());
   1016   UpdateResponseDataList updates_list = GetNthModelThreadUpdateResponse(0);
   1017   EXPECT_EQ(0U, updates_list.size());
   1018   UpdateResponseDataList pending_updates = GetNthModelThreadPendingUpdates(0);
   1019   EXPECT_EQ(1U, pending_updates.size());
   1020 }
   1021 
   1022 // Test decryption of pending updates saved across a restart.
   1023 TEST_F(ModelTypeSyncWorkerImplTest, RestorePendingEntries) {
   1024   // Create a fake pending update.
   1025   UpdateResponseData update;
   1026 
   1027   update.client_tag_hash = GenerateTagHash("tag1");
   1028   update.id = "SomeID";
   1029   update.response_version = 100;
   1030   update.ctime = base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(10);
   1031   update.mtime = base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(11);
   1032   update.non_unique_name = "encrypted";
   1033   update.deleted = false;
   1034 
   1035   update.specifics = GenerateSpecifics("tag1", "value1");
   1036   EncryptUpdate(GetNthKeyParams(1), &(update.specifics));
   1037 
   1038   // Inject the update during ModelTypeSyncWorker initialization.
   1039   UpdateResponseDataList saved_pending_updates;
   1040   saved_pending_updates.push_back(update);
   1041   InitializeWithPendingUpdates(saved_pending_updates);
   1042 
   1043   // Update will be undecryptable at first.
   1044   EXPECT_EQ(0U, GetNumModelThreadUpdateResponses());
   1045   ASSERT_FALSE(HasUpdateResponseOnModelThread("tag1"));
   1046 
   1047   // Update the cryptographer so it can decrypt that update.
   1048   NewForeignEncryptionKey();
   1049   UpdateLocalCryptographer();
   1050 
   1051   // Verify the item gets decrypted and sent back to the model thread.
   1052   ASSERT_TRUE(HasUpdateResponseOnModelThread("tag1"));
   1053 }
   1054 
   1055 // Test decryption of pending updates saved across a restart.  This test
   1056 // differs from the previous one in that the restored updates can be decrypted
   1057 // immediately after the ModelTypeSyncWorker is constructed.
   1058 TEST_F(ModelTypeSyncWorkerImplTest, RestoreApplicableEntries) {
   1059   // Update the cryptographer so it can decrypt that update.
   1060   NewForeignEncryptionKey();
   1061   UpdateLocalCryptographer();
   1062 
   1063   // Create a fake pending update.
   1064   UpdateResponseData update;
   1065   update.client_tag_hash = GenerateTagHash("tag1");
   1066   update.id = "SomeID";
   1067   update.response_version = 100;
   1068   update.ctime = base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(10);
   1069   update.mtime = base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(11);
   1070   update.non_unique_name = "encrypted";
   1071   update.deleted = false;
   1072 
   1073   update.specifics = GenerateSpecifics("tag1", "value1");
   1074   EncryptUpdate(GetNthKeyParams(1), &(update.specifics));
   1075 
   1076   // Inject the update during ModelTypeSyncWorker initialization.
   1077   UpdateResponseDataList saved_pending_updates;
   1078   saved_pending_updates.push_back(update);
   1079   InitializeWithPendingUpdates(saved_pending_updates);
   1080 
   1081   // Verify the item gets decrypted and sent back to the model thread.
   1082   ASSERT_TRUE(HasUpdateResponseOnModelThread("tag1"));
   1083 }
   1084 
   1085 // Test that undecryptable updates provide sufficient reason to not commit.
   1086 //
   1087 // This should be rare in practice.  Usually the cryptographer will be in an
   1088 // unusable state when we receive undecryptable updates, and that alone will be
   1089 // enough to prevent all commits.
   1090 TEST_F(ModelTypeSyncWorkerImplTest, CommitBlockedByPending) {
   1091   NormalInitialize();
   1092 
   1093   // Prepeare to commit an item.
   1094   CommitRequest("tag1", "value1");
   1095   EXPECT_TRUE(WillCommit());
   1096 
   1097   // Receive an encrypted update for that item.
   1098   SetUpdateEncryptionFilter(1);
   1099   TriggerUpdateFromServer(10, "tag1", "value1");
   1100 
   1101   // The pending commit state should be cleared.
   1102   EXPECT_FALSE(WillCommit());
   1103 
   1104   // The pending update will be delivered to the model thread.
   1105   HasUpdateResponseOnModelThread("tag1");
   1106 
   1107   // Pretend the update arrived too late to prevent another commit request.
   1108   CommitRequest("tag1", "value2");
   1109 
   1110   EXPECT_FALSE(WillCommit());
   1111 }
   1112 
   1113 // Verify that corrupted encrypted updates don't cause crashes.
   1114 TEST_F(ModelTypeSyncWorkerImplTest, ReceiveCorruptEncryption) {
   1115   // Initialize the worker with basic encryption state.
   1116   NormalInitialize();
   1117   NewForeignEncryptionKey();
   1118   UpdateLocalCryptographer();
   1119 
   1120   // Manually create an update.
   1121   sync_pb::SyncEntity entity;
   1122   entity.set_client_defined_unique_tag(GenerateTagHash("tag1"));
   1123   entity.set_id_string("SomeID");
   1124   entity.set_version(1);
   1125   entity.set_ctime(1000);
   1126   entity.set_mtime(1001);
   1127   entity.set_name("encrypted");
   1128   entity.set_deleted(false);
   1129 
   1130   // Encrypt it.
   1131   entity.mutable_specifics()->CopyFrom(GenerateSpecifics("tag1", "value1"));
   1132   EncryptUpdate(GetNthKeyParams(1), entity.mutable_specifics());
   1133 
   1134   // Replace a few bytes to corrupt it.
   1135   entity.mutable_specifics()->mutable_encrypted()->mutable_blob()->replace(
   1136       0, 4, "xyz!");
   1137 
   1138   SyncEntityList entity_list;
   1139   entity_list.push_back(&entity);
   1140 
   1141   // If a corrupt update could trigger a crash, this is where it would happen.
   1142   DeliverRawUpdates(entity_list);
   1143 
   1144   EXPECT_FALSE(HasUpdateResponseOnModelThread("tag1"));
   1145 
   1146   // Deliver a non-corrupt update to see if the everything still works.
   1147   SetUpdateEncryptionFilter(1);
   1148   TriggerUpdateFromServer(10, "tag1", "value1");
   1149   EXPECT_TRUE(HasUpdateResponseOnModelThread("tag1"));
   1150 }
   1151 
   1152 }  // namespace syncer
   1153