Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: sync/engine/apply_control_data_updates_unittest.cc

Issue 10832286: sync: Introduce control data types (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Respond to Tim's comments Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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/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/read_transaction.h"
17 #include "sync/syncable/syncable_util.h"
18 #include "sync/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_encryptor.h"
23 #include "sync/test/fake_sync_encryption_handler.h"
24 #include "sync/util/cryptographer.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace syncer {
28
29 using syncable::MutableEntry;
30 using syncable::UNITTEST;
31 using syncable::Id;
32
33 class ApplyControlDataUpdatesTest : public SyncerCommandTest {
34 public:
35 protected:
36 ApplyControlDataUpdatesTest() {}
37 virtual ~ApplyControlDataUpdatesTest() {}
38
39 virtual void SetUp() {
40 workers()->clear();
41 mutable_routing_info()->clear();
42 workers()->push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
43 workers()->push_back(
44 make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD)));
45 (*mutable_routing_info())[BOOKMARKS] = GROUP_UI;
46 (*mutable_routing_info())[PASSWORDS] = GROUP_PASSWORD;
47 (*mutable_routing_info())[NIGORI] = GROUP_CONTROL;
48 SyncerCommandTest::SetUp();
49 entry_factory_.reset(new TestEntryFactory(directory()));
50
51 syncable::ReadTransaction trans(FROM_HERE, directory());
52 directory()->GetCryptographer(&trans)->SetNigoriHandler(
53 &fake_encryption_handler_);
54 fake_encryption_handler_.set_cryptographer(
55 directory()->GetCryptographer(&trans));
56 }
57
58 FakeEncryptor encryptor_;
59 TestIdFactory id_factory_;
60 scoped_ptr<TestEntryFactory> entry_factory_;
61 FakeSyncEncryptionHandler fake_encryption_handler_;
62 private:
63 DISALLOW_COPY_AND_ASSIGN(ApplyControlDataUpdatesTest);
64 };
65
66 TEST_F(ApplyControlDataUpdatesTest, NigoriUpdate) {
67 // Storing the cryptographer separately is bad, but for this test we
68 // know it's safe.
69 Cryptographer* cryptographer;
70 ModelTypeSet encrypted_types;
71 encrypted_types.Put(PASSWORDS);
72 encrypted_types.Put(NIGORI);
73
74 // We start with initial_sync_ended == false. This makes it easier to verify
75 // that ApplyControlDataUpdates sets initial_sync_ended correctly.
76 EXPECT_FALSE(directory()->initial_sync_ended_types().Has(NIGORI));
77
78 {
79 syncable::ReadTransaction trans(FROM_HERE, directory());
80 cryptographer = directory()->GetCryptographer(&trans);
81 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
82 }
83
84 // Nigori node updates should update the Cryptographer.
85 Cryptographer other_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_encrypted());
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 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(ModelTypeSet::All()));
102 EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
103 }
104
105 TEST_F(ApplyControlDataUpdatesTest, NigoriUpdateForDisabledTypes) {
106 // Storing the cryptographer separately is bad, but for this test we
107 // know it's safe.
108 Cryptographer* cryptographer;
109 ModelTypeSet encrypted_types;
110 encrypted_types.Put(PASSWORDS);
111 encrypted_types.Put(NIGORI);
112
113 // We start with initial_sync_ended == false. This makes it easier to verify
114 // that ApplyControlDataUpdates sets initial_sync_ended correctly.
115 EXPECT_FALSE(directory()->initial_sync_ended_types().Has(NIGORI));
116
117 {
118 syncable::ReadTransaction trans(FROM_HERE, directory());
119 cryptographer = directory()->GetCryptographer(&trans);
120 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
121 }
122
123 // Nigori node updates should update the Cryptographer.
124 Cryptographer other_cryptographer(&encryptor_);
125 KeyParams params = {"localhost", "dummy", "foobar"};
126 other_cryptographer.AddKey(params);
127
128 sync_pb::EntitySpecifics specifics;
129 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
130 other_cryptographer.GetKeys(nigori->mutable_encrypted());
131 nigori->set_encrypt_everything(true);
132 entry_factory_->CreateUnappliedNewItem(
133 ModelTypeToRootTag(NIGORI), specifics, true);
134 EXPECT_FALSE(cryptographer->has_pending_keys());
135
136 ApplyControlDataUpdates(directory());
137
138 EXPECT_FALSE(cryptographer->is_ready());
139 EXPECT_TRUE(cryptographer->has_pending_keys());
140 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(ModelTypeSet::All()));
141 EXPECT_TRUE(directory()->initial_sync_ended_types().Has(NIGORI));
142 }
143
144 // Create some local unsynced and unencrypted data. Apply a nigori update that
145 // turns on encryption for the unsynced data. Ensure we properly encrypt the
146 // data as part of the nigori update. Apply another nigori update with no
147 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
148 // breaks.
149 TEST_F(ApplyControlDataUpdatesTest, EncryptUnsyncedChanges) {
150 // Storing the cryptographer separately is bad, but for this test we
151 // know it's safe.
152 Cryptographer* cryptographer;
153 ModelTypeSet encrypted_types;
154 encrypted_types.Put(PASSWORDS);
155 encrypted_types.Put(NIGORI);
156 {
157 syncable::ReadTransaction trans(FROM_HERE, directory());
158 cryptographer = directory()->GetCryptographer(&trans);
159 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
160
161 // With default encrypted_types, this should be true.
162 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
163
164 Syncer::UnsyncedMetaHandles handles;
165 GetUnsyncedEntries(&trans, &handles);
166 EXPECT_TRUE(handles.empty());
167 }
168
169 // Create unsynced bookmarks without encryption.
170 // First item is a folder
171 Id folder_id = id_factory_.NewLocalId();
172 entry_factory_->CreateUnsyncedItem(folder_id, id_factory_.root(), "folder",
173 true, BOOKMARKS, NULL);
174 // Next five items are children of the folder
175 size_t i;
176 size_t batch_s = 5;
177 for (i = 0; i < batch_s; ++i) {
178 entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
179 base::StringPrintf("Item %"PRIuS"", i),
180 false, BOOKMARKS, NULL);
181 }
182 // Next five items are children of the root.
183 for (; i < 2*batch_s; ++i) {
184 entry_factory_->CreateUnsyncedItem(
185 id_factory_.NewLocalId(), id_factory_.root(),
186 base::StringPrintf("Item %"PRIuS"", i), false,
187 BOOKMARKS, NULL);
188 }
189
190 KeyParams params = {"localhost", "dummy", "foobar"};
191 cryptographer->AddKey(params);
192 sync_pb::EntitySpecifics specifics;
193 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
194 cryptographer->GetKeys(nigori->mutable_encrypted());
195 nigori->set_encrypt_everything(true);
196 encrypted_types.Put(BOOKMARKS);
197 entry_factory_->CreateUnappliedNewItem(
198 ModelTypeToRootTag(NIGORI), specifics, true);
199 EXPECT_FALSE(cryptographer->has_pending_keys());
200 EXPECT_TRUE(cryptographer->is_ready());
201
202 {
203 // Ensure we have unsynced nodes that aren't properly encrypted.
204 syncable::ReadTransaction trans(FROM_HERE, directory());
205 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
206
207 Syncer::UnsyncedMetaHandles handles;
208 GetUnsyncedEntries(&trans, &handles);
209 EXPECT_EQ(2*batch_s+1, handles.size());
210 }
211
212 ApplyControlDataUpdates(directory());
213
214 EXPECT_FALSE(cryptographer->has_pending_keys());
215 EXPECT_TRUE(cryptographer->is_ready());
216 {
217 syncable::ReadTransaction trans(FROM_HERE, directory());
218
219 // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
220 // should be encrypted now.
221 EXPECT_TRUE(ModelTypeSet::All().Equals(cryptographer->GetEncryptedTypes()));
222 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
223
224 Syncer::UnsyncedMetaHandles handles;
225 GetUnsyncedEntries(&trans, &handles);
226 EXPECT_EQ(2*batch_s+1, handles.size());
227 }
228
229 // Simulate another nigori update that doesn't change anything.
230 {
231 syncable::WriteTransaction trans(FROM_HERE, UNITTEST, directory());
232 MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG,
233 ModelTypeToRootTag(NIGORI));
234 ASSERT_TRUE(entry.good());
235 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision());
236 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
237 }
238
239 ApplyControlDataUpdates(directory());
240
241 EXPECT_FALSE(cryptographer->has_pending_keys());
242 EXPECT_TRUE(cryptographer->is_ready());
243 {
244 syncable::ReadTransaction trans(FROM_HERE, directory());
245
246 // All our changes should still be encrypted.
247 EXPECT_TRUE(ModelTypeSet::All().Equals(cryptographer->GetEncryptedTypes()));
248 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
249
250 Syncer::UnsyncedMetaHandles handles;
251 GetUnsyncedEntries(&trans, &handles);
252 EXPECT_EQ(2*batch_s+1, handles.size());
253 }
254 }
255
256 TEST_F(ApplyControlDataUpdatesTest, CannotEncryptUnsyncedChanges) {
257 // Storing the cryptographer separately is bad, but for this test we
258 // know it's safe.
259 Cryptographer* cryptographer;
260 ModelTypeSet encrypted_types;
261 encrypted_types.Put(PASSWORDS);
262 encrypted_types.Put(NIGORI);
263 {
264 syncable::ReadTransaction trans(FROM_HERE, directory());
265 cryptographer = directory()->GetCryptographer(&trans);
266 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
267
268 // With default encrypted_types, this should be true.
269 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
270
271 Syncer::UnsyncedMetaHandles handles;
272 GetUnsyncedEntries(&trans, &handles);
273 EXPECT_TRUE(handles.empty());
274 }
275
276 // Create unsynced bookmarks without encryption.
277 // First item is a folder
278 Id folder_id = id_factory_.NewLocalId();
279 entry_factory_->CreateUnsyncedItem(
280 folder_id, id_factory_.root(), "folder", true,
281 BOOKMARKS, NULL);
282 // Next five items are children of the folder
283 size_t i;
284 size_t batch_s = 5;
285 for (i = 0; i < batch_s; ++i) {
286 entry_factory_->CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
287 base::StringPrintf("Item %"PRIuS"", i),
288 false, BOOKMARKS, NULL);
289 }
290 // Next five items are children of the root.
291 for (; i < 2*batch_s; ++i) {
292 entry_factory_->CreateUnsyncedItem(
293 id_factory_.NewLocalId(), id_factory_.root(),
294 base::StringPrintf("Item %"PRIuS"", i), false,
295 BOOKMARKS, NULL);
296 }
297
298 // We encrypt with new keys, triggering the local cryptographer to be unready
299 // and unable to decrypt data (once updated).
300 Cryptographer other_cryptographer(&encryptor_);
301 KeyParams params = {"localhost", "dummy", "foobar"};
302 other_cryptographer.AddKey(params);
303 sync_pb::EntitySpecifics specifics;
304 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
305 other_cryptographer.GetKeys(nigori->mutable_encrypted());
306 nigori->set_encrypt_everything(true);
307 encrypted_types.Put(BOOKMARKS);
308 entry_factory_->CreateUnappliedNewItem(
309 ModelTypeToRootTag(NIGORI), specifics, true);
310 EXPECT_FALSE(cryptographer->has_pending_keys());
311
312 {
313 // Ensure we have unsynced nodes that aren't properly encrypted.
314 syncable::ReadTransaction trans(FROM_HERE, directory());
315 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
316 Syncer::UnsyncedMetaHandles handles;
317 GetUnsyncedEntries(&trans, &handles);
318 EXPECT_EQ(2*batch_s+1, handles.size());
319 }
320
321 ApplyControlDataUpdates(directory());
322
323 EXPECT_FALSE(cryptographer->is_ready());
324 EXPECT_TRUE(cryptographer->has_pending_keys());
325 {
326 syncable::ReadTransaction trans(FROM_HERE, directory());
327
328 // Since we have pending keys, we would have failed to encrypt, but the
329 // cryptographer should be updated.
330 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
331 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(
332 ModelTypeSet().All()));
333 EXPECT_FALSE(cryptographer->is_ready());
334 EXPECT_TRUE(cryptographer->has_pending_keys());
335
336 Syncer::UnsyncedMetaHandles handles;
337 GetUnsyncedEntries(&trans, &handles);
338 EXPECT_EQ(2*batch_s+1, handles.size());
339 }
340 }
341
342 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698