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

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

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

Powered by Google App Engine
This is Rietveld 408576698