- add sources.
[platform/framework/web/crosswalk.git] / src / sync / engine / apply_control_data_updates_unittest.cc
1 // Copyright 2012 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 "base/format_macros.h"
6 #include "base/location.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/stringprintf.h"
9 #include "sync/engine/apply_control_data_updates.h"
10 #include "sync/engine/syncer.h"
11 #include "sync/engine/syncer_util.h"
12 #include "sync/internal_api/public/test/test_entry_factory.h"
13 #include "sync/protocol/nigori_specifics.pb.h"
14 #include "sync/syncable/mutable_entry.h"
15 #include "sync/syncable/nigori_util.h"
16 #include "sync/syncable/syncable_read_transaction.h"
17 #include "sync/syncable/syncable_util.h"
18 #include "sync/syncable/syncable_write_transaction.h"
19 #include "sync/test/engine/fake_model_worker.h"
20 #include "sync/test/engine/syncer_command_test.h"
21 #include "sync/test/engine/test_id_factory.h"
22 #include "sync/test/fake_sync_encryption_handler.h"
23 #include "sync/util/cryptographer.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace syncer {
27
28 using syncable::MutableEntry;
29 using syncable::UNITTEST;
30 using syncable::Id;
31
32 class ApplyControlDataUpdatesTest : public SyncerCommandTest {
33  public:
34  protected:
35   ApplyControlDataUpdatesTest() {}
36   virtual ~ApplyControlDataUpdatesTest() {}
37
38   virtual void SetUp() {
39     workers()->clear();
40     mutable_routing_info()->clear();
41     workers()->push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
42     workers()->push_back(
43         make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD)));
44     (*mutable_routing_info())[NIGORI] = GROUP_PASSIVE;
45     (*mutable_routing_info())[EXPERIMENTS] = GROUP_PASSIVE;
46     SyncerCommandTest::SetUp();
47     entry_factory_.reset(new TestEntryFactory(directory()));
48
49     session()->mutable_status_controller()->set_updates_request_types(
50         ControlTypes());
51
52     syncable::ReadTransaction trans(FROM_HERE, directory());
53   }
54
55   TestIdFactory id_factory_;
56   scoped_ptr<TestEntryFactory> entry_factory_;
57  private:
58   DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest);
59 };
60
61 // Verify that applying a nigori node sets initial sync ended properly,
62 // updates the set of encrypted types, and updates the cryptographer.
63 TEST_F(ApplyControlDataUpdatesTest, NigoriUpdate) {
64   // Storing the cryptographer separately is bad, but for this test we
65   // know it's safe.
66   Cryptographer* cryptographer;
67   ModelTypeSet encrypted_types;
68   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
69
70   {
71     syncable::ReadTransaction trans(FROM_HERE, directory());
72     cryptographer = directory()->GetCryptographer(&trans);
73     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
74         .Equals(encrypted_types));
75   }
76
77   // Nigori node updates should update the Cryptographer.
78   Cryptographer other_cryptographer(cryptographer->encryptor());
79   KeyParams params = {"localhost", "dummy", "foobar"};
80   other_cryptographer.AddKey(params);
81
82   sync_pb::EntitySpecifics specifics;
83   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
84   other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
85   nigori->set_encrypt_everything(true);
86   entry_factory_->CreateUnappliedNewItem(
87       ModelTypeToRootTag(NIGORI), specifics, true);
88   EXPECT_FALSE(cryptographer->has_pending_keys());
89
90   ApplyControlDataUpdates(session());
91
92   EXPECT_FALSE(cryptographer->is_ready());
93   EXPECT_TRUE(cryptographer->has_pending_keys());
94   {
95     syncable::ReadTransaction trans(FROM_HERE, directory());
96     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
97         .Equals(ModelTypeSet::All()));
98   }
99 }
100
101 // Create some local unsynced and unencrypted data. Apply a nigori update that
102 // turns on encryption for the unsynced data. Ensure we properly encrypt the
103 // data as part of the nigori update. Apply another nigori update with no
104 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
105 // breaks.
106 TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
107   // Storing the cryptographer separately is bad, but for this test we
108   // know it's safe.
109   Cryptographer* cryptographer;
110   ModelTypeSet encrypted_types;
111   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
112   {
113     syncable::ReadTransaction trans(FROM_HERE, directory());
114     cryptographer = directory()->GetCryptographer(&trans);
115     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
116         .Equals(encrypted_types));
117
118     // With default encrypted_types, this should be true.
119     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
120
121     Syncer::UnsyncedMetaHandles handles;
122     GetUnsyncedEntries(&trans, &handles);
123     EXPECT_TRUE(handles.empty());
124   }
125
126   // Create unsynced bookmarks without encryption.
127   // First item is a folder
128   Id folder_id = id_factory_.NewLocalId();
129   entry_factory_->CreateUnsyncedItem(folder_id, id_factory_.root(), "folder",
130                                      true, BOOKMARKS, NULL);
131   // Next five items are children of the folder
132   size_t i;
133   size_t batch_s = 5;
134   for (i = 0; i < batch_s; ++i) {
135     entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
136                                        base::StringPrintf("Item %" PRIuS "", i),
137                                        false, BOOKMARKS, NULL);
138   }
139   // Next five items are children of the root.
140   for (; i < 2*batch_s; ++i) {
141     entry_factory_->CreateUnsyncedItem(
142         id_factory_.NewLocalId(), id_factory_.root(),
143         base::StringPrintf("Item %" PRIuS "", i), false,
144         BOOKMARKS, NULL);
145   }
146
147   KeyParams params = {"localhost", "dummy", "foobar"};
148   cryptographer->AddKey(params);
149   sync_pb::EntitySpecifics specifics;
150   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
151   cryptographer->GetKeys(nigori->mutable_encryption_keybag());
152   nigori->set_encrypt_everything(true);
153   encrypted_types.Put(BOOKMARKS);
154   entry_factory_->CreateUnappliedNewItem(
155       ModelTypeToRootTag(NIGORI), specifics, true);
156   EXPECT_FALSE(cryptographer->has_pending_keys());
157   EXPECT_TRUE(cryptographer->is_ready());
158
159   {
160     // Ensure we have unsynced nodes that aren't properly encrypted.
161     syncable::ReadTransaction trans(FROM_HERE, directory());
162     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
163
164     Syncer::UnsyncedMetaHandles handles;
165     GetUnsyncedEntries(&trans, &handles);
166     EXPECT_EQ(2*batch_s+1, handles.size());
167   }
168
169   ApplyControlDataUpdates(session());
170
171   EXPECT_FALSE(cryptographer->has_pending_keys());
172   EXPECT_TRUE(cryptographer->is_ready());
173   {
174     syncable::ReadTransaction trans(FROM_HERE, directory());
175
176     // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
177     // should be encrypted now.
178     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
179         .Equals(ModelTypeSet::All()));
180     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
181
182     Syncer::UnsyncedMetaHandles handles;
183     GetUnsyncedEntries(&trans, &handles);
184     EXPECT_EQ(2*batch_s+1, handles.size());
185   }
186
187   // Simulate another nigori update that doesn't change anything.
188   {
189     syncable::WriteTransaction trans(FROM_HERE, UNITTEST, directory());
190     MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG,
191                        ModelTypeToRootTag(NIGORI));
192     ASSERT_TRUE(entry.good());
193     entry.PutServerVersion(entry_factory_->GetNextRevision());
194     entry.PutIsUnappliedUpdate(true);
195   }
196
197   ApplyControlDataUpdates(session());
198
199   EXPECT_FALSE(cryptographer->has_pending_keys());
200   EXPECT_TRUE(cryptographer->is_ready());
201   {
202     syncable::ReadTransaction trans(FROM_HERE, directory());
203
204     // All our changes should still be encrypted.
205     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
206         .Equals(ModelTypeSet::All()));
207     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
208
209     Syncer::UnsyncedMetaHandles handles;
210     GetUnsyncedEntries(&trans, &handles);
211     EXPECT_EQ(2*batch_s+1, handles.size());
212   }
213 }
214
215 // Create some local unsynced and unencrypted changes. Receive a new nigori
216 // node enabling their encryption but also introducing pending keys. Ensure
217 // we apply the update properly without encrypting the unsynced changes or
218 // breaking.
219 TEST_F(ApplyControlDataUpdatesTest, CannotEncryptUnsyncedChanges) {
220   // Storing the cryptographer separately is bad, but for this test we
221   // know it's safe.
222   Cryptographer* cryptographer;
223   ModelTypeSet encrypted_types;
224   encrypted_types.PutAll(SyncEncryptionHandler::SensitiveTypes());
225   {
226     syncable::ReadTransaction trans(FROM_HERE, directory());
227     cryptographer = directory()->GetCryptographer(&trans);
228     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
229         .Equals(encrypted_types));
230
231     // With default encrypted_types, this should be true.
232     EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
233
234     Syncer::UnsyncedMetaHandles handles;
235     GetUnsyncedEntries(&trans, &handles);
236     EXPECT_TRUE(handles.empty());
237   }
238
239   // Create unsynced bookmarks without encryption.
240   // First item is a folder
241   Id folder_id = id_factory_.NewLocalId();
242   entry_factory_->CreateUnsyncedItem(
243       folder_id, id_factory_.root(), "folder", true,
244       BOOKMARKS, NULL);
245   // Next five items are children of the folder
246   size_t i;
247   size_t batch_s = 5;
248   for (i = 0; i < batch_s; ++i) {
249     entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
250                                        base::StringPrintf("Item %" PRIuS "", i),
251                                        false, BOOKMARKS, NULL);
252   }
253   // Next five items are children of the root.
254   for (; i < 2*batch_s; ++i) {
255     entry_factory_->CreateUnsyncedItem(
256         id_factory_.NewLocalId(), id_factory_.root(),
257         base::StringPrintf("Item %" PRIuS "", i), false,
258         BOOKMARKS, NULL);
259   }
260
261   // We encrypt with new keys, triggering the local cryptographer to be unready
262   // and unable to decrypt data (once updated).
263   Cryptographer other_cryptographer(cryptographer->encryptor());
264   KeyParams params = {"localhost", "dummy", "foobar"};
265   other_cryptographer.AddKey(params);
266   sync_pb::EntitySpecifics specifics;
267   sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
268   other_cryptographer.GetKeys(nigori->mutable_encryption_keybag());
269   nigori->set_encrypt_everything(true);
270   encrypted_types.Put(BOOKMARKS);
271   entry_factory_->CreateUnappliedNewItem(
272       ModelTypeToRootTag(NIGORI), specifics, true);
273   EXPECT_FALSE(cryptographer->has_pending_keys());
274
275   {
276     // Ensure we have unsynced nodes that aren't properly encrypted.
277     syncable::ReadTransaction trans(FROM_HERE, directory());
278     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
279     Syncer::UnsyncedMetaHandles handles;
280     GetUnsyncedEntries(&trans, &handles);
281     EXPECT_EQ(2*batch_s+1, handles.size());
282   }
283
284   ApplyControlDataUpdates(session());
285
286   EXPECT_FALSE(cryptographer->is_ready());
287   EXPECT_TRUE(cryptographer->has_pending_keys());
288   {
289     syncable::ReadTransaction trans(FROM_HERE, directory());
290
291     // Since we have pending keys, we would have failed to encrypt, but the
292     // cryptographer should be updated.
293     EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
294     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
295         .Equals(ModelTypeSet::All()));
296     EXPECT_FALSE(cryptographer->is_ready());
297     EXPECT_TRUE(cryptographer->has_pending_keys());
298
299     Syncer::UnsyncedMetaHandles handles;
300     GetUnsyncedEntries(&trans, &handles);
301     EXPECT_EQ(2*batch_s+1, handles.size());
302   }
303 }
304
305 // Verify we handle a nigori node conflict by merging encryption keys and
306 // types, but preserve the custom passphrase state of the server.
307 // Initial sync ended should be set.
308 TEST_F(ApplyControlDataUpdatesTest,
309        NigoriConflictPendingKeysServerEncryptEverythingCustom) {
310   Cryptographer* cryptographer;
311   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
312   KeyParams other_params = {"localhost", "dummy", "foobar"};
313   KeyParams local_params = {"localhost", "dummy", "local"};
314   {
315     syncable::ReadTransaction trans(FROM_HERE, directory());
316     cryptographer = directory()->GetCryptographer(&trans);
317     EXPECT_TRUE(encrypted_types.Equals(
318             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
319   }
320
321   // Set up a temporary cryptographer to generate new keys with.
322   Cryptographer other_cryptographer(cryptographer->encryptor());
323   other_cryptographer.AddKey(other_params);
324
325   // Create server specifics with pending keys, new encrypted types,
326   // and a custom passphrase (unmigrated).
327   sync_pb::EntitySpecifics server_specifics;
328   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
329   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
330   server_nigori->set_encrypt_everything(true);
331   server_nigori->set_keybag_is_frozen(true);
332   int64 nigori_handle =
333       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
334                                              server_specifics,
335                                              true);
336
337   // Initialize the local cryptographer with the local keys.
338   cryptographer->AddKey(local_params);
339   EXPECT_TRUE(cryptographer->is_ready());
340
341   // Set up a local nigori with the local encryption keys and default encrypted
342   // types.
343   sync_pb::EntitySpecifics local_specifics;
344   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
345   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
346   local_nigori->set_encrypt_everything(false);
347   local_nigori->set_keybag_is_frozen(true);
348   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
349           nigori_handle, local_specifics));
350   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
351   // to use.
352   {
353     syncable::ReadTransaction trans(FROM_HERE, directory());
354     cryptographer = directory()->GetCryptographer(&trans);
355     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
356         *local_nigori,
357         &trans);
358   }
359
360   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
361   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
362   ApplyControlDataUpdates(session());
363   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
364   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
365
366   EXPECT_FALSE(cryptographer->is_ready());
367   EXPECT_TRUE(cryptographer->is_initialized());
368   EXPECT_TRUE(cryptographer->has_pending_keys());
369   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
370           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
371               nigori().encryption_keybag()));
372   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
373       nigori().keybag_is_frozen());
374   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
375       nigori().encrypt_everything());
376   {
377     syncable::ReadTransaction trans(FROM_HERE, directory());
378     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
379         .Equals(ModelTypeSet::All()));
380   }
381 }
382
383 // Verify we handle a nigori node conflict by merging encryption keys and
384 // types, but preserve the custom passphrase state of the server.
385 // Initial sync ended should be set.
386 TEST_F(ApplyControlDataUpdatesTest,
387        NigoriConflictPendingKeysLocalEncryptEverythingCustom) {
388   Cryptographer* cryptographer;
389   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
390   KeyParams other_params = {"localhost", "dummy", "foobar"};
391   KeyParams local_params = {"localhost", "dummy", "local"};
392   {
393     syncable::ReadTransaction trans(FROM_HERE, directory());
394     cryptographer = directory()->GetCryptographer(&trans);
395     EXPECT_TRUE(encrypted_types.Equals(
396             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
397   }
398
399   // Set up a temporary cryptographer to generate new keys with.
400   Cryptographer other_cryptographer(cryptographer->encryptor());
401   other_cryptographer.AddKey(other_params);
402
403   // Create server specifics with pending keys, new encrypted types,
404   // and a custom passphrase (unmigrated).
405   sync_pb::EntitySpecifics server_specifics;
406   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
407   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
408   server_nigori->set_encrypt_everything(false);
409   server_nigori->set_keybag_is_frozen(false);
410   int64 nigori_handle =
411       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
412                                              server_specifics,
413                                              true);
414
415   // Initialize the local cryptographer with the local keys.
416   cryptographer->AddKey(local_params);
417   EXPECT_TRUE(cryptographer->is_ready());
418
419   // Set up a local nigori with the local encryption keys and default encrypted
420   // types.
421   sync_pb::EntitySpecifics local_specifics;
422   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
423   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
424   local_nigori->set_encrypt_everything(true);
425   local_nigori->set_keybag_is_frozen(true);
426   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
427           nigori_handle, local_specifics));
428   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
429   // to use.
430   {
431     syncable::ReadTransaction trans(FROM_HERE, directory());
432     cryptographer = directory()->GetCryptographer(&trans);
433     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
434         *local_nigori,
435         &trans);
436   }
437
438   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
439   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
440   ApplyControlDataUpdates(session());
441   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
442   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
443
444   EXPECT_FALSE(cryptographer->is_ready());
445   EXPECT_TRUE(cryptographer->is_initialized());
446   EXPECT_TRUE(cryptographer->has_pending_keys());
447   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
448           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
449               nigori().encryption_keybag()));
450   EXPECT_FALSE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
451       nigori().keybag_is_frozen());
452   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
453       nigori().encrypt_everything());
454   {
455     syncable::ReadTransaction trans(FROM_HERE, directory());
456     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
457         .Equals(ModelTypeSet::All()));
458   }
459 }
460
461 // If the conflicting nigori has a subset of the local keys, the conflict
462 // resolution should preserve the full local keys. Initial sync ended should be
463 // set.
464 TEST_F(ApplyControlDataUpdatesTest,
465        NigoriConflictOldKeys) {
466   Cryptographer* cryptographer;
467   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
468   KeyParams old_params = {"localhost", "dummy", "old"};
469   KeyParams new_params = {"localhost", "dummy", "new"};
470   {
471     syncable::ReadTransaction trans(FROM_HERE, directory());
472     cryptographer = directory()->GetCryptographer(&trans);
473     EXPECT_TRUE(encrypted_types.Equals(
474             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
475   }
476
477   // Set up the cryptographer with old keys
478   cryptographer->AddKey(old_params);
479
480   // Create server specifics with old keys and new encrypted types.
481   sync_pb::EntitySpecifics server_specifics;
482   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
483   cryptographer->GetKeys(server_nigori->mutable_encryption_keybag());
484   server_nigori->set_encrypt_everything(true);
485   int64 nigori_handle =
486       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
487                                              server_specifics,
488                                              true);
489
490   // Add the new keys to the cryptogrpaher
491   cryptographer->AddKey(new_params);
492   EXPECT_TRUE(cryptographer->is_ready());
493
494   // Set up a local nigori with the superset of keys.
495   sync_pb::EntitySpecifics local_specifics;
496   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
497   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
498   local_nigori->set_encrypt_everything(false);
499   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
500           nigori_handle, local_specifics));
501   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
502   // to use.
503   {
504     syncable::ReadTransaction trans(FROM_HERE, directory());
505     cryptographer = directory()->GetCryptographer(&trans);
506     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
507         *local_nigori,
508         &trans);
509   }
510
511   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
512   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
513   ApplyControlDataUpdates(session());
514   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
515   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
516
517   EXPECT_TRUE(cryptographer->is_ready());
518   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
519           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
520               nigori().encryption_keybag()));
521   EXPECT_FALSE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
522       nigori().keybag_is_frozen());
523   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
524       nigori().encrypt_everything());
525   {
526     syncable::ReadTransaction trans(FROM_HERE, directory());
527     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
528         .Equals(ModelTypeSet::All()));
529   }
530 }
531
532 // If both nigoris are migrated, but we also set a custom passphrase locally,
533 // the local nigori should be preserved.
534 TEST_F(ApplyControlDataUpdatesTest,
535        NigoriConflictBothMigratedLocalCustom) {
536   Cryptographer* cryptographer;
537   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
538   KeyParams old_params = {"localhost", "dummy", "old"};
539   KeyParams new_params = {"localhost", "dummy", "new"};
540   {
541     syncable::ReadTransaction trans(FROM_HERE, directory());
542     cryptographer = directory()->GetCryptographer(&trans);
543     EXPECT_TRUE(encrypted_types.Equals(
544             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
545   }
546
547   // Set up the cryptographer with new keys
548   Cryptographer other_cryptographer(cryptographer->encryptor());
549   other_cryptographer.AddKey(old_params);
550
551   // Create server specifics with a migrated keystore passphrase type.
552   sync_pb::EntitySpecifics server_specifics;
553   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
554   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
555   server_nigori->set_encrypt_everything(false);
556   server_nigori->set_keybag_is_frozen(true);
557   server_nigori->set_passphrase_type(
558       sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
559   server_nigori->mutable_keystore_decryptor_token();
560   int64 nigori_handle =
561       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
562                                              server_specifics,
563                                              true);
564
565   // Add the new keys to the cryptographer.
566   cryptographer->AddKey(old_params);
567   cryptographer->AddKey(new_params);
568   EXPECT_TRUE(cryptographer->is_ready());
569
570   // Set up a local nigori with a migrated custom passphrase type
571   sync_pb::EntitySpecifics local_specifics;
572   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
573   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
574   local_nigori->set_encrypt_everything(true);
575   local_nigori->set_keybag_is_frozen(true);
576   local_nigori->set_passphrase_type(
577       sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
578   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
579           nigori_handle, local_specifics));
580   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
581   // to use.
582   {
583     syncable::ReadTransaction trans(FROM_HERE, directory());
584     cryptographer = directory()->GetCryptographer(&trans);
585     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
586         *local_nigori,
587         &trans);
588   }
589
590   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
591   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
592   ApplyControlDataUpdates(session());
593   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
594   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
595
596   EXPECT_TRUE(cryptographer->is_ready());
597   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
598           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
599               nigori().encryption_keybag()));
600   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
601       nigori().keybag_is_frozen());
602   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
603       nigori().encrypt_everything());
604   EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
605             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
606                 nigori().passphrase_type());
607   {
608     syncable::ReadTransaction trans(FROM_HERE, directory());
609     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
610         .Equals(ModelTypeSet::All()));
611   }
612 }
613
614 // If both nigoris are migrated, but a custom passphrase with a new key was
615 // set remotely, the remote nigori should be preserved.
616 TEST_F(ApplyControlDataUpdatesTest,
617        NigoriConflictBothMigratedServerCustom) {
618   Cryptographer* cryptographer;
619   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
620   KeyParams old_params = {"localhost", "dummy", "old"};
621   KeyParams new_params = {"localhost", "dummy", "new"};
622   {
623     syncable::ReadTransaction trans(FROM_HERE, directory());
624     cryptographer = directory()->GetCryptographer(&trans);
625     EXPECT_TRUE(encrypted_types.Equals(
626             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
627   }
628
629   // Set up the cryptographer with both new keys and old keys.
630   Cryptographer other_cryptographer(cryptographer->encryptor());
631   other_cryptographer.AddKey(old_params);
632   other_cryptographer.AddKey(new_params);
633
634   // Create server specifics with a migrated custom passphrase type.
635   sync_pb::EntitySpecifics server_specifics;
636   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
637   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
638   server_nigori->set_encrypt_everything(true);
639   server_nigori->set_keybag_is_frozen(true);
640   server_nigori->set_passphrase_type(
641       sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
642   int64 nigori_handle =
643       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
644                                              server_specifics,
645                                              true);
646
647   // Add the old keys to the cryptographer.
648   cryptographer->AddKey(old_params);
649   EXPECT_TRUE(cryptographer->is_ready());
650
651   // Set up a local nigori with a migrated keystore passphrase type
652   sync_pb::EntitySpecifics local_specifics;
653   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
654   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
655   local_nigori->set_encrypt_everything(false);
656   local_nigori->set_keybag_is_frozen(true);
657   local_nigori->set_passphrase_type(
658       sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
659   server_nigori->mutable_keystore_decryptor_token();
660   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
661           nigori_handle, local_specifics));
662   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
663   // to use.
664   {
665     syncable::ReadTransaction trans(FROM_HERE, directory());
666     cryptographer = directory()->GetCryptographer(&trans);
667     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
668         *local_nigori,
669         &trans);
670   }
671
672   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
673   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
674   ApplyControlDataUpdates(session());
675   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
676   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
677
678   EXPECT_TRUE(cryptographer->is_initialized());
679   EXPECT_TRUE(cryptographer->has_pending_keys());
680   EXPECT_TRUE(other_cryptographer.CanDecryptUsingDefaultKey(
681           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
682               nigori().encryption_keybag()));
683   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
684       nigori().keybag_is_frozen());
685   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
686       nigori().encrypt_everything());
687   EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
688             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
689                 nigori().passphrase_type());
690   {
691     syncable::ReadTransaction trans(FROM_HERE, directory());
692     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
693         .Equals(ModelTypeSet::All()));
694   }
695 }
696
697 // If the local nigori is migrated but the server is not, preserve the local
698 // nigori.
699 TEST_F(ApplyControlDataUpdatesTest,
700        NigoriConflictLocalMigrated) {
701   Cryptographer* cryptographer;
702   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
703   KeyParams old_params = {"localhost", "dummy", "old"};
704   KeyParams new_params = {"localhost", "dummy", "new"};
705   {
706     syncable::ReadTransaction trans(FROM_HERE, directory());
707     cryptographer = directory()->GetCryptographer(&trans);
708     EXPECT_TRUE(encrypted_types.Equals(
709             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
710   }
711
712   // Set up the cryptographer with both new keys and old keys.
713   Cryptographer other_cryptographer(cryptographer->encryptor());
714   other_cryptographer.AddKey(old_params);
715
716   // Create server specifics with an unmigrated implicit passphrase type.
717   sync_pb::EntitySpecifics server_specifics;
718   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
719   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
720   server_nigori->set_encrypt_everything(true);
721   server_nigori->set_keybag_is_frozen(false);
722   int64 nigori_handle =
723       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
724                                              server_specifics,
725                                              true);
726
727   // Add the old keys to the cryptographer.
728   cryptographer->AddKey(old_params);
729   cryptographer->AddKey(new_params);
730   EXPECT_TRUE(cryptographer->is_ready());
731
732   // Set up a local nigori with a migrated custom passphrase type
733   sync_pb::EntitySpecifics local_specifics;
734   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
735   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
736   local_nigori->set_encrypt_everything(true);
737   local_nigori->set_keybag_is_frozen(true);
738   local_nigori->set_passphrase_type(
739       sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
740   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
741           nigori_handle, local_specifics));
742   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
743   // to use.
744   {
745     syncable::ReadTransaction trans(FROM_HERE, directory());
746     cryptographer = directory()->GetCryptographer(&trans);
747     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
748         *local_nigori,
749         &trans);
750   }
751
752   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
753   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
754   ApplyControlDataUpdates(session());
755   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
756   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
757
758   EXPECT_TRUE(cryptographer->is_ready());
759   EXPECT_TRUE(cryptographer->CanDecryptUsingDefaultKey(
760           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
761               nigori().encryption_keybag()));
762   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
763       nigori().keybag_is_frozen());
764   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
765       nigori().encrypt_everything());
766   EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
767             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
768                 nigori().passphrase_type());
769   {
770     syncable::ReadTransaction trans(FROM_HERE, directory());
771     EXPECT_TRUE(directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)
772         .Equals(ModelTypeSet::All()));
773   }
774 }
775
776 // If the server nigori is migrated but the local is not, preserve the server
777 // nigori.
778 TEST_F(ApplyControlDataUpdatesTest,
779        NigoriConflictServerMigrated) {
780   Cryptographer* cryptographer;
781   ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes());
782   KeyParams old_params = {"localhost", "dummy", "old"};
783   KeyParams new_params = {"localhost", "dummy", "new"};
784   {
785     syncable::ReadTransaction trans(FROM_HERE, directory());
786     cryptographer = directory()->GetCryptographer(&trans);
787     EXPECT_TRUE(encrypted_types.Equals(
788             directory()->GetNigoriHandler()->GetEncryptedTypes(&trans)));
789   }
790
791   // Set up the cryptographer with both new keys and old keys.
792   Cryptographer other_cryptographer(cryptographer->encryptor());
793   other_cryptographer.AddKey(old_params);
794
795   // Create server specifics with an migrated keystore passphrase type.
796   sync_pb::EntitySpecifics server_specifics;
797   sync_pb::NigoriSpecifics* server_nigori = server_specifics.mutable_nigori();
798   other_cryptographer.GetKeys(server_nigori->mutable_encryption_keybag());
799   server_nigori->set_encrypt_everything(false);
800   server_nigori->set_keybag_is_frozen(true);
801   server_nigori->set_passphrase_type(
802       sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
803   server_nigori->mutable_keystore_decryptor_token();
804   int64 nigori_handle =
805       entry_factory_->CreateUnappliedNewItem(kNigoriTag,
806                                              server_specifics,
807                                              true);
808
809   // Add the old keys to the cryptographer.
810   cryptographer->AddKey(old_params);
811   cryptographer->AddKey(new_params);
812   EXPECT_TRUE(cryptographer->is_ready());
813
814   // Set up a local nigori with a migrated custom passphrase type
815   sync_pb::EntitySpecifics local_specifics;
816   sync_pb::NigoriSpecifics* local_nigori = local_specifics.mutable_nigori();
817   cryptographer->GetKeys(local_nigori->mutable_encryption_keybag());
818   local_nigori->set_encrypt_everything(false);
819   local_nigori->set_keybag_is_frozen(false);
820   ASSERT_TRUE(entry_factory_->SetLocalSpecificsForItem(
821           nigori_handle, local_specifics));
822   // Apply the update locally so that UpdateFromEncryptedTypes knows what state
823   // to use.
824   {
825     syncable::ReadTransaction trans(FROM_HERE, directory());
826     cryptographer = directory()->GetCryptographer(&trans);
827     directory()->GetNigoriHandler()->ApplyNigoriUpdate(
828         *local_nigori,
829         &trans);
830   }
831
832   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
833   EXPECT_TRUE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
834   ApplyControlDataUpdates(session());
835   EXPECT_TRUE(entry_factory_->GetIsUnsyncedForItem(nigori_handle));
836   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(nigori_handle));
837
838   EXPECT_TRUE(cryptographer->is_ready());
839   // Note: we didn't overwrite the encryption keybag with the local keys. The
840   // sync encryption handler will do that when it detects that the new
841   // keybag is out of date (and update the keystore bootstrap if necessary).
842   EXPECT_FALSE(cryptographer->CanDecryptUsingDefaultKey(
843           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
844               nigori().encryption_keybag()));
845   EXPECT_TRUE(cryptographer->CanDecrypt(
846           entry_factory_->GetLocalSpecificsForItem(nigori_handle).
847               nigori().encryption_keybag()));
848   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
849       nigori().keybag_is_frozen());
850   EXPECT_TRUE(entry_factory_->GetLocalSpecificsForItem(nigori_handle).
851       nigori().has_keystore_decryptor_token());
852   EXPECT_EQ(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE,
853             entry_factory_->GetLocalSpecificsForItem(nigori_handle).
854                 nigori().passphrase_type());
855   {
856     syncable::ReadTransaction trans(FROM_HERE, directory());
857   }
858 }
859
860 // Check that we can apply a simple control datatype node successfully.
861 TEST_F(ApplyControlDataUpdatesTest, ControlApply) {
862   std::string experiment_id = "experiment";
863   sync_pb::EntitySpecifics specifics;
864   specifics.mutable_experiments()->mutable_keystore_encryption()->
865       set_enabled(true);
866   int64 experiment_handle = entry_factory_->CreateUnappliedNewItem(
867       experiment_id, specifics, false);
868   ApplyControlDataUpdates(session());
869
870   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(experiment_handle));
871   EXPECT_TRUE(
872       entry_factory_->GetLocalSpecificsForItem(experiment_handle).
873           experiments().keystore_encryption().enabled());
874 }
875
876 // Verify that we apply top level folders before their children.
877 TEST_F(ApplyControlDataUpdatesTest, ControlApplyParentBeforeChild) {
878   std::string parent_id = "parent";
879   std::string experiment_id = "experiment";
880   sync_pb::EntitySpecifics specifics;
881   specifics.mutable_experiments()->mutable_keystore_encryption()->
882       set_enabled(true);
883   int64 experiment_handle = entry_factory_->CreateUnappliedNewItemWithParent(
884       experiment_id, specifics, parent_id);
885   int64 parent_handle = entry_factory_->CreateUnappliedNewItem(
886       parent_id, specifics, true);
887   ApplyControlDataUpdates(session());
888
889   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(parent_handle));
890   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(experiment_handle));
891   EXPECT_TRUE(
892       entry_factory_->GetLocalSpecificsForItem(experiment_handle).
893           experiments().keystore_encryption().enabled());
894 }
895
896 // Verify that we handle control datatype conflicts by preserving the server
897 // data.
898 TEST_F(ApplyControlDataUpdatesTest, ControlConflict) {
899   std::string experiment_id = "experiment";
900   sync_pb::EntitySpecifics local_specifics, server_specifics;
901   server_specifics.mutable_experiments()->mutable_keystore_encryption()->
902       set_enabled(true);
903   local_specifics.mutable_experiments()->mutable_keystore_encryption()->
904       set_enabled(false);
905   int64 experiment_handle = entry_factory_->CreateSyncedItem(
906       experiment_id, EXPERIMENTS, false);
907   entry_factory_->SetServerSpecificsForItem(experiment_handle,
908                                             server_specifics);
909   entry_factory_->SetLocalSpecificsForItem(experiment_handle,
910                                            local_specifics);
911   ApplyControlDataUpdates(session());
912
913   EXPECT_FALSE(entry_factory_->GetIsUnappliedForItem(experiment_handle));
914   EXPECT_TRUE(
915       entry_factory_->GetLocalSpecificsForItem(experiment_handle).
916           experiments().keystore_encryption().enabled());
917 }
918
919 }  // namespace syncer