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