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

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

Issue 10559104: sync: Process 'control' data separately (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rename, cleanup, fix tests Created 8 years, 6 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
« no previous file with comments | « sync/engine/apply_updates_command.cc ('k') | sync/engine/conflict_resolver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <string> 5 #include <string>
6 6
7 #include "base/format_macros.h"
8 #include "base/location.h" 7 #include "base/location.h"
9 #include "base/stringprintf.h" 8 #include "base/memory/scoped_ptr.h"
10 #include "sync/engine/apply_updates_command.h" 9 #include "sync/engine/apply_updates_command.h"
11 #include "sync/engine/nigori_util.h"
12 #include "sync/engine/syncer.h" 10 #include "sync/engine/syncer.h"
13 #include "sync/engine/syncer_util.h" 11 #include "sync/engine/syncer_util.h"
14 #include "sync/protocol/bookmark_specifics.pb.h" 12 #include "sync/protocol/bookmark_specifics.pb.h"
15 #include "sync/protocol/password_specifics.pb.h" 13 #include "sync/protocol/password_specifics.pb.h"
16 #include "sync/sessions/sync_session.h"
17 #include "sync/syncable/mutable_entry.h" 14 #include "sync/syncable/mutable_entry.h"
18 #include "sync/syncable/read_transaction.h" 15 #include "sync/syncable/read_transaction.h"
19 #include "sync/syncable/syncable_id.h" 16 #include "sync/syncable/syncable_id.h"
20 #include "sync/syncable/write_transaction.h" 17 #include "sync/syncable/write_transaction.h"
21 #include "sync/test/engine/fake_model_worker.h" 18 #include "sync/test/engine/fake_model_worker.h"
22 #include "sync/test/engine/syncer_command_test.h" 19 #include "sync/test/engine/syncer_command_test.h"
23 #include "sync/test/engine/test_id_factory.h" 20 #include "sync/test/engine/test_id_factory.h"
24 #include "sync/test/fake_encryptor.h" 21 #include "sync/test/fake_encryptor.h"
22 #include "sync/test/test_entry_factory.h"
25 #include "sync/util/cryptographer.h" 23 #include "sync/util/cryptographer.h"
26 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/gtest/include/gtest/gtest.h"
27 25
28 namespace csync { 26 namespace csync {
29 27
30 using sessions::SyncSession;
31 using std::string; 28 using std::string;
32 using syncable::Id; 29 using syncable::Id;
33 using syncable::MutableEntry; 30 using syncable::MutableEntry;
34 using syncable::UNITTEST; 31 using syncable::UNITTEST;
35 using syncable::WriteTransaction; 32 using syncable::WriteTransaction;
36 33
37 namespace { 34 namespace {
38 sync_pb::EntitySpecifics DefaultBookmarkSpecifics() { 35 sync_pb::EntitySpecifics DefaultBookmarkSpecifics() {
39 sync_pb::EntitySpecifics result; 36 sync_pb::EntitySpecifics result;
40 AddDefaultFieldValue(syncable::BOOKMARKS, &result); 37 AddDefaultFieldValue(syncable::BOOKMARKS, &result);
41 return result; 38 return result;
42 } 39 }
43 } // namespace 40 } // namespace
44 41
45 // A test fixture for tests exercising ApplyUpdatesCommand. 42 // A test fixture for tests exercising ApplyUpdatesCommand.
46 class ApplyUpdatesCommandTest : public SyncerCommandTest { 43 class ApplyUpdatesCommandTest : public SyncerCommandTest {
47 public: 44 public:
48 protected: 45 protected:
49 ApplyUpdatesCommandTest() : next_revision_(1) {} 46 ApplyUpdatesCommandTest() {}
50 virtual ~ApplyUpdatesCommandTest() {} 47 virtual ~ApplyUpdatesCommandTest() {}
51 48
52 virtual void SetUp() { 49 virtual void SetUp() {
53 workers()->clear(); 50 workers()->clear();
54 mutable_routing_info()->clear(); 51 mutable_routing_info()->clear();
55 workers()->push_back( 52 workers()->push_back(
56 make_scoped_refptr(new FakeModelWorker(GROUP_UI))); 53 make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
57 workers()->push_back( 54 workers()->push_back(
58 make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD))); 55 make_scoped_refptr(new FakeModelWorker(GROUP_PASSWORD)));
59 (*mutable_routing_info())[syncable::BOOKMARKS] = GROUP_UI; 56 (*mutable_routing_info())[syncable::BOOKMARKS] = GROUP_UI;
60 (*mutable_routing_info())[syncable::PASSWORDS] = GROUP_PASSWORD; 57 (*mutable_routing_info())[syncable::PASSWORDS] = GROUP_PASSWORD;
61 (*mutable_routing_info())[syncable::NIGORI] = GROUP_PASSIVE; 58 (*mutable_routing_info())[syncable::NIGORI] = GROUP_CONTROL;
62 SyncerCommandTest::SetUp(); 59 SyncerCommandTest::SetUp();
60 entry_factory_.reset(new TestEntryFactory(directory()));
63 ExpectNoGroupsToChange(apply_updates_command_); 61 ExpectNoGroupsToChange(apply_updates_command_);
64 } 62 }
65 63
66 // Create a new unapplied folder node with a parent.
67 void CreateUnappliedNewItemWithParent(
68 const string& item_id,
69 const sync_pb::EntitySpecifics& specifics,
70 const string& parent_id) {
71 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
72 MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
73 Id::CreateFromServerId(item_id));
74 ASSERT_TRUE(entry.good());
75 entry.Put(syncable::SERVER_VERSION, next_revision_++);
76 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
77
78 entry.Put(syncable::SERVER_NON_UNIQUE_NAME, item_id);
79 entry.Put(syncable::SERVER_PARENT_ID, Id::CreateFromServerId(parent_id));
80 entry.Put(syncable::SERVER_IS_DIR, true);
81 entry.Put(syncable::SERVER_SPECIFICS, specifics);
82 }
83
84 // Create a new unapplied update without a parent.
85 void CreateUnappliedNewItem(const string& item_id,
86 const sync_pb::EntitySpecifics& specifics,
87 bool is_unique) {
88 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
89 MutableEntry entry(&trans, syncable::CREATE_NEW_UPDATE_ITEM,
90 Id::CreateFromServerId(item_id));
91 ASSERT_TRUE(entry.good());
92 entry.Put(syncable::SERVER_VERSION, next_revision_++);
93 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
94 entry.Put(syncable::SERVER_NON_UNIQUE_NAME, item_id);
95 entry.Put(syncable::SERVER_PARENT_ID, syncable::GetNullId());
96 entry.Put(syncable::SERVER_IS_DIR, false);
97 entry.Put(syncable::SERVER_SPECIFICS, specifics);
98 if (is_unique) // For top-level nodes.
99 entry.Put(syncable::UNIQUE_SERVER_TAG, item_id);
100 }
101
102 // Create an unsynced item in the database. If item_id is a local ID, it
103 // will be treated as a create-new. Otherwise, if it's a server ID, we'll
104 // fake the server data so that it looks like it exists on the server.
105 // Returns the methandle of the created item in |metahandle_out| if not NULL.
106 void CreateUnsyncedItem(const Id& item_id,
107 const Id& parent_id,
108 const string& name,
109 bool is_folder,
110 syncable::ModelType model_type,
111 int64* metahandle_out) {
112 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
113 Id predecessor_id;
114 ASSERT_TRUE(
115 directory()->GetLastChildIdForTest(&trans, parent_id, &predecessor_id));
116 MutableEntry entry(&trans, syncable::CREATE, parent_id, name);
117 ASSERT_TRUE(entry.good());
118 entry.Put(syncable::ID, item_id);
119 entry.Put(syncable::BASE_VERSION,
120 item_id.ServerKnows() ? next_revision_++ : 0);
121 entry.Put(syncable::IS_UNSYNCED, true);
122 entry.Put(syncable::IS_DIR, is_folder);
123 entry.Put(syncable::IS_DEL, false);
124 entry.Put(syncable::PARENT_ID, parent_id);
125 CHECK(entry.PutPredecessor(predecessor_id));
126 sync_pb::EntitySpecifics default_specifics;
127 syncable::AddDefaultFieldValue(model_type, &default_specifics);
128 entry.Put(syncable::SPECIFICS, default_specifics);
129 if (item_id.ServerKnows()) {
130 entry.Put(syncable::SERVER_SPECIFICS, default_specifics);
131 entry.Put(syncable::SERVER_IS_DIR, is_folder);
132 entry.Put(syncable::SERVER_PARENT_ID, parent_id);
133 entry.Put(syncable::SERVER_IS_DEL, false);
134 }
135 if (metahandle_out)
136 *metahandle_out = entry.Get(syncable::META_HANDLE);
137 }
138
139 // Creates an item that is both unsynced an an unapplied update. Returns the
140 // metahandle of the created item.
141 int64 CreateUnappliedAndUnsyncedItem(const string& name,
142 syncable::ModelType model_type) {
143 int64 metahandle = 0;
144 CreateUnsyncedItem(id_factory_.MakeServer(name), id_factory_.root(), name,
145 false, model_type, &metahandle);
146
147 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
148 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, metahandle);
149 if (!entry.good()) {
150 ADD_FAILURE();
151 return syncable::kInvalidMetaHandle;
152 }
153
154 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
155 entry.Put(syncable::SERVER_VERSION, GetNextRevision());
156
157 return metahandle;
158 }
159
160
161 // Creates an item that has neither IS_UNSYNED or IS_UNAPPLIED_UPDATE. The
162 // item is known to both the server and client. Returns the metahandle of
163 // the created item.
164 int64 CreateSyncedItem(const std::string& name, syncable::ModelType
165 model_type, bool is_folder) {
166 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
167
168 syncable::Id parent_id(id_factory_.root());
169 syncable::Id item_id(id_factory_.MakeServer(name));
170 int64 version = GetNextRevision();
171
172 sync_pb::EntitySpecifics default_specifics;
173 syncable::AddDefaultFieldValue(model_type, &default_specifics);
174
175 MutableEntry entry(&trans, syncable::CREATE, parent_id, name);
176 if (!entry.good()) {
177 ADD_FAILURE();
178 return syncable::kInvalidMetaHandle;
179 }
180
181 entry.Put(syncable::ID, item_id);
182 entry.Put(syncable::BASE_VERSION, version);
183 entry.Put(syncable::IS_UNSYNCED, false);
184 entry.Put(syncable::NON_UNIQUE_NAME, name);
185 entry.Put(syncable::IS_DIR, is_folder);
186 entry.Put(syncable::IS_DEL, false);
187 entry.Put(syncable::PARENT_ID, parent_id);
188
189 if (!entry.PutPredecessor(id_factory_.root())) {
190 ADD_FAILURE();
191 return syncable::kInvalidMetaHandle;
192 }
193 entry.Put(syncable::SPECIFICS, default_specifics);
194
195 entry.Put(syncable::SERVER_VERSION, GetNextRevision());
196 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
197 entry.Put(syncable::SERVER_NON_UNIQUE_NAME, "X");
198 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.MakeServer("Y"));
199 entry.Put(syncable::SERVER_IS_DIR, is_folder);
200 entry.Put(syncable::SERVER_IS_DEL, false);
201 entry.Put(syncable::SERVER_SPECIFICS, default_specifics);
202 entry.Put(syncable::SERVER_PARENT_ID, parent_id);
203
204 return entry.Get(syncable::META_HANDLE);
205 }
206
207 int64 GetNextRevision() {
208 return next_revision_++;
209 }
210
211 ApplyUpdatesCommand apply_updates_command_; 64 ApplyUpdatesCommand apply_updates_command_;
212 FakeEncryptor encryptor_; 65 FakeEncryptor encryptor_;
213 TestIdFactory id_factory_; 66 scoped_ptr<TestEntryFactory> entry_factory_;
214 private: 67 private:
215 int64 next_revision_;
216 DISALLOW_COPY_AND_ASSIGN(ApplyUpdatesCommandTest); 68 DISALLOW_COPY_AND_ASSIGN(ApplyUpdatesCommandTest);
217 }; 69 };
218 70
219 TEST_F(ApplyUpdatesCommandTest, Simple) { 71 TEST_F(ApplyUpdatesCommandTest, Simple) {
220 string root_server_id = syncable::GetNullId().GetServerId(); 72 string root_server_id = syncable::GetNullId().GetServerId();
221 CreateUnappliedNewItemWithParent("parent", 73 entry_factory_->CreateUnappliedNewItemWithParent("parent",
222 DefaultBookmarkSpecifics(), 74 DefaultBookmarkSpecifics(),
223 root_server_id); 75 root_server_id);
224 CreateUnappliedNewItemWithParent("child", 76 entry_factory_->CreateUnappliedNewItemWithParent("child",
225 DefaultBookmarkSpecifics(), 77 DefaultBookmarkSpecifics(),
226 "parent"); 78 "parent");
227 79
228 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 80 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
229 apply_updates_command_.ExecuteImpl(session()); 81 apply_updates_command_.ExecuteImpl(session());
230 82
231 sessions::StatusController* status = session()->mutable_status_controller(); 83 sessions::StatusController* status = session()->mutable_status_controller();
232 84
233 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 85 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
234 ASSERT_TRUE(status->update_progress()); 86 ASSERT_TRUE(status->update_progress());
235 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) 87 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize())
236 << "All updates should have been attempted"; 88 << "All updates should have been attempted";
237 ASSERT_TRUE(status->conflict_progress()); 89 ASSERT_TRUE(status->conflict_progress());
238 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 90 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
239 << "Simple update shouldn't result in conflicts"; 91 << "Simple update shouldn't result in conflicts";
240 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize()) 92 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize())
241 << "Simple update shouldn't result in conflicts"; 93 << "Simple update shouldn't result in conflicts";
242 EXPECT_EQ(0, status->conflict_progress()->HierarchyConflictingItemsSize()) 94 EXPECT_EQ(0, status->conflict_progress()->HierarchyConflictingItemsSize())
243 << "Simple update shouldn't result in conflicts"; 95 << "Simple update shouldn't result in conflicts";
244 EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount()) 96 EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount())
245 << "All items should have been successfully applied"; 97 << "All items should have been successfully applied";
246 } 98 }
247 99
248 TEST_F(ApplyUpdatesCommandTest, UpdateWithChildrenBeforeParents) { 100 TEST_F(ApplyUpdatesCommandTest, UpdateWithChildrenBeforeParents) {
249 // Set a bunch of updates which are difficult to apply in the order 101 // Set a bunch of updates which are difficult to apply in the order
250 // they're received due to dependencies on other unseen items. 102 // they're received due to dependencies on other unseen items.
251 string root_server_id = syncable::GetNullId().GetServerId(); 103 string root_server_id = syncable::GetNullId().GetServerId();
252 CreateUnappliedNewItemWithParent("a_child_created_first", 104 entry_factory_->CreateUnappliedNewItemWithParent(
253 DefaultBookmarkSpecifics(), 105 "a_child_created_first", DefaultBookmarkSpecifics(), "parent");
254 "parent"); 106 entry_factory_->CreateUnappliedNewItemWithParent(
255 CreateUnappliedNewItemWithParent("x_child_created_first", 107 "x_child_created_first", DefaultBookmarkSpecifics(), "parent");
256 DefaultBookmarkSpecifics(), 108 entry_factory_->CreateUnappliedNewItemWithParent(
257 "parent"); 109 "parent", DefaultBookmarkSpecifics(), root_server_id);
258 CreateUnappliedNewItemWithParent("parent", 110 entry_factory_->CreateUnappliedNewItemWithParent(
259 DefaultBookmarkSpecifics(), 111 "a_child_created_second", DefaultBookmarkSpecifics(), "parent");
260 root_server_id); 112 entry_factory_->CreateUnappliedNewItemWithParent(
261 CreateUnappliedNewItemWithParent("a_child_created_second", 113 "x_child_created_second", DefaultBookmarkSpecifics(), "parent");
262 DefaultBookmarkSpecifics(),
263 "parent");
264 CreateUnappliedNewItemWithParent("x_child_created_second",
265 DefaultBookmarkSpecifics(),
266 "parent");
267 114
268 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 115 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
269 apply_updates_command_.ExecuteImpl(session()); 116 apply_updates_command_.ExecuteImpl(session());
270 117
271 sessions::StatusController* status = session()->mutable_status_controller(); 118 sessions::StatusController* status = session()->mutable_status_controller();
272 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 119 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
273 ASSERT_TRUE(status->update_progress()); 120 ASSERT_TRUE(status->update_progress());
274 EXPECT_EQ(5, status->update_progress()->AppliedUpdatesSize()) 121 EXPECT_EQ(5, status->update_progress()->AppliedUpdatesSize())
275 << "All updates should have been attempted"; 122 << "All updates should have been attempted";
276 ASSERT_TRUE(status->conflict_progress()); 123 ASSERT_TRUE(status->conflict_progress());
277 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 124 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
278 << "Simple update shouldn't result in conflicts, even if out-of-order"; 125 << "Simple update shouldn't result in conflicts, even if out-of-order";
279 EXPECT_EQ(5, status->update_progress()->SuccessfullyAppliedUpdateCount()) 126 EXPECT_EQ(5, status->update_progress()->SuccessfullyAppliedUpdateCount())
280 << "All updates should have been successfully applied"; 127 << "All updates should have been successfully applied";
281 } 128 }
282 129
283 // Runs the ApplyUpdatesCommand on an item that has both local and remote 130 // Runs the ApplyUpdatesCommand on an item that has both local and remote
284 // modifications (IS_UNSYNCED and IS_UNAPPLIED_UPDATE). We expect the command 131 // modifications (IS_UNSYNCED and IS_UNAPPLIED_UPDATE). We expect the command
285 // to detect that this update can't be applied because it is in a CONFLICT 132 // to detect that this update can't be applied because it is in a CONFLICT
286 // state. 133 // state.
287 TEST_F(ApplyUpdatesCommandTest, SimpleConflict) { 134 TEST_F(ApplyUpdatesCommandTest, SimpleConflict) {
288 CreateUnappliedAndUnsyncedItem("item", syncable::BOOKMARKS); 135 entry_factory_->CreateUnappliedAndUnsyncedItem(
136 "item", syncable::BOOKMARKS);
289 137
290 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 138 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
291 apply_updates_command_.ExecuteImpl(session()); 139 apply_updates_command_.ExecuteImpl(session());
292 140
293 sessions::StatusController* status = session()->mutable_status_controller(); 141 sessions::StatusController* status = session()->mutable_status_controller();
294 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 142 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
295 ASSERT_TRUE(status->conflict_progress()); 143 ASSERT_TRUE(status->conflict_progress());
296 EXPECT_EQ(1, status->conflict_progress()->SimpleConflictingItemsSize()) 144 EXPECT_EQ(1, status->conflict_progress()->SimpleConflictingItemsSize())
297 << "Unsynced and unapplied item should be a simple conflict"; 145 << "Unsynced and unapplied item should be a simple conflict";
298 } 146 }
299 147
300 // Runs the ApplyUpdatesCommand on an item that has both local and remote 148 // Runs the ApplyUpdatesCommand on an item that has both local and remote
301 // modifications *and* the remote modification cannot be applied without 149 // modifications *and* the remote modification cannot be applied without
302 // violating the tree constraints. We expect the command to detect that this 150 // violating the tree constraints. We expect the command to detect that this
303 // update can't be applied and that this situation can't be resolved with the 151 // update can't be applied and that this situation can't be resolved with the
304 // simple conflict processing logic; it is in a CONFLICT_HIERARCHY state. 152 // simple conflict processing logic; it is in a CONFLICT_HIERARCHY state.
305 TEST_F(ApplyUpdatesCommandTest, HierarchyAndSimpleConflict) { 153 TEST_F(ApplyUpdatesCommandTest, HierarchyAndSimpleConflict) {
306 // Create a simply-conflicting item. It will start with valid parent ids. 154 // Create a simply-conflicting item. It will start with valid parent ids.
307 int64 handle = CreateUnappliedAndUnsyncedItem("orphaned_by_server", 155 int64 handle = entry_factory_->CreateUnappliedAndUnsyncedItem(
308 syncable::BOOKMARKS); 156 "orphaned_by_server", syncable::BOOKMARKS);
309 { 157 {
310 // Manually set the SERVER_PARENT_ID to bad value. 158 // Manually set the SERVER_PARENT_ID to bad value.
311 // A bad parent indicates a hierarchy conflict. 159 // A bad parent indicates a hierarchy conflict.
312 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 160 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
313 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); 161 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle);
314 ASSERT_TRUE(entry.good()); 162 ASSERT_TRUE(entry.good());
315 163
316 entry.Put(syncable::SERVER_PARENT_ID, 164 entry.Put(syncable::SERVER_PARENT_ID,
317 id_factory_.MakeServer("bogus_parent")); 165 TestIdFactory::MakeServer("bogus_parent"));
318 } 166 }
319 167
320 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 168 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
321 apply_updates_command_.ExecuteImpl(session()); 169 apply_updates_command_.ExecuteImpl(session());
322 170
323 sessions::StatusController* status = session()->mutable_status_controller(); 171 sessions::StatusController* status = session()->mutable_status_controller();
324 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 172 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
325 173
326 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()); 174 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize());
327 175
328 // An update that is both a simple conflict and a hierarchy conflict should be 176 // An update that is both a simple conflict and a hierarchy conflict should be
329 // treated as a hierarchy conflict. 177 // treated as a hierarchy conflict.
330 ASSERT_TRUE(status->conflict_progress()); 178 ASSERT_TRUE(status->conflict_progress());
331 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); 179 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize());
332 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); 180 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize());
333 } 181 }
334 182
335 183
336 // Runs the ApplyUpdatesCommand on an item with remote modifications that would 184 // Runs the ApplyUpdatesCommand on an item with remote modifications that would
337 // create a directory loop if the update were applied. We expect the command to 185 // create a directory loop if the update were applied. We expect the command to
338 // detect that this update can't be applied because it is in a 186 // detect that this update can't be applied because it is in a
339 // CONFLICT_HIERARCHY state. 187 // CONFLICT_HIERARCHY state.
340 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDirectoryLoop) { 188 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDirectoryLoop) {
341 // Item 'X' locally has parent of 'root'. Server is updating it to have 189 // Item 'X' locally has parent of 'root'. Server is updating it to have
342 // parent of 'Y'. 190 // parent of 'Y'.
343 { 191 {
344 // Create it as a child of root node. 192 // Create it as a child of root node.
345 int64 handle = CreateSyncedItem("X", syncable::BOOKMARKS, true); 193 int64 handle = entry_factory_->CreateSyncedItem(
194 "X", syncable::BOOKMARKS, true);
346 195
347 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 196 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
348 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); 197 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle);
349 ASSERT_TRUE(entry.good()); 198 ASSERT_TRUE(entry.good());
350 199
351 // Re-parent from root to "Y" 200 // Re-parent from root to "Y"
352 entry.Put(syncable::SERVER_VERSION, GetNextRevision()); 201 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision());
353 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); 202 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
354 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.MakeServer("Y")); 203 entry.Put(syncable::SERVER_PARENT_ID, TestIdFactory::MakeServer("Y"));
355 } 204 }
356 205
357 // Item 'Y' is child of 'X'. 206 // Item 'Y' is child of 'X'.
358 CreateUnsyncedItem(id_factory_.MakeServer("Y"), id_factory_.MakeServer("X"), 207 entry_factory_->CreateUnsyncedItem(
359 "Y", true, syncable::BOOKMARKS, NULL); 208 TestIdFactory::MakeServer("Y"), TestIdFactory::MakeServer("X"), "Y", true,
209 syncable::BOOKMARKS, NULL);
360 210
361 // If the server's update were applied, we would have X be a child of Y, and Y 211 // If the server's update were applied, we would have X be a child of Y, and Y
362 // as a child of X. That's a directory loop. The UpdateApplicator should 212 // as a child of X. That's a directory loop. The UpdateApplicator should
363 // prevent the update from being applied and note that this is a hierarchy 213 // prevent the update from being applied and note that this is a hierarchy
364 // conflict. 214 // conflict.
365 215
366 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 216 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
367 apply_updates_command_.ExecuteImpl(session()); 217 apply_updates_command_.ExecuteImpl(session());
368 218
369 sessions::StatusController* status = session()->mutable_status_controller(); 219 sessions::StatusController* status = session()->mutable_status_controller();
370 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 220 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
371 221
372 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()); 222 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize());
373 223
374 // This should count as a hierarchy conflict. 224 // This should count as a hierarchy conflict.
375 ASSERT_TRUE(status->conflict_progress()); 225 ASSERT_TRUE(status->conflict_progress());
376 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); 226 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize());
377 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); 227 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize());
378 } 228 }
379 229
380 // Runs the ApplyUpdatesCommand on a directory where the server sent us an 230 // Runs the ApplyUpdatesCommand on a directory where the server sent us an
381 // update to add a child to a locally deleted (and unsynced) parent. We expect 231 // update to add a child to a locally deleted (and unsynced) parent. We expect
382 // the command to not apply the update and to indicate the update is in a 232 // the command to not apply the update and to indicate the update is in a
383 // CONFLICT_HIERARCHY state. 233 // CONFLICT_HIERARCHY state.
384 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeletedParent) { 234 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeletedParent) {
385 // Create a locally deleted parent item. 235 // Create a locally deleted parent item.
386 int64 parent_handle; 236 int64 parent_handle;
387 CreateUnsyncedItem(Id::CreateFromServerId("parent"), id_factory_.root(), 237 entry_factory_->CreateUnsyncedItem(
388 "parent", true, syncable::BOOKMARKS, &parent_handle); 238 Id::CreateFromServerId("parent"), TestIdFactory::root(),
239 "parent", true, syncable::BOOKMARKS, &parent_handle);
389 { 240 {
390 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 241 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
391 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, parent_handle); 242 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, parent_handle);
392 entry.Put(syncable::IS_DEL, true); 243 entry.Put(syncable::IS_DEL, true);
393 } 244 }
394 245
395 // Create an incoming child from the server. 246 // Create an incoming child from the server.
396 CreateUnappliedNewItemWithParent("child", DefaultBookmarkSpecifics(), 247 entry_factory_->CreateUnappliedNewItemWithParent(
397 "parent"); 248 "child", DefaultBookmarkSpecifics(), "parent");
398 249
399 // The server's update may seem valid to some other client, but on this client 250 // The server's update may seem valid to some other client, but on this client
400 // that new item's parent no longer exists. The update should not be applied 251 // that new item's parent no longer exists. The update should not be applied
401 // and the update applicator should indicate this is a hierarchy conflict. 252 // and the update applicator should indicate this is a hierarchy conflict.
402 253
403 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 254 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
404 apply_updates_command_.ExecuteImpl(session()); 255 apply_updates_command_.ExecuteImpl(session());
405 256
406 sessions::StatusController* status = session()->mutable_status_controller(); 257 sessions::StatusController* status = session()->mutable_status_controller();
407 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 258 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
408 259
409 // This should count as a hierarchy conflict. 260 // This should count as a hierarchy conflict.
410 ASSERT_TRUE(status->conflict_progress()); 261 ASSERT_TRUE(status->conflict_progress());
411 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); 262 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize());
412 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); 263 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize());
413 } 264 }
414 265
415 // Runs the ApplyUpdatesCommand on a directory where the server is trying to 266 // Runs the ApplyUpdatesCommand on a directory where the server is trying to
416 // delete a folder that has a recently added (and unsynced) child. We expect 267 // delete a folder that has a recently added (and unsynced) child. We expect
417 // the command to not apply the update because it is in a CONFLICT_HIERARCHY 268 // the command to not apply the update because it is in a CONFLICT_HIERARCHY
418 // state. 269 // state.
419 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeleteNonEmptyDirectory) { 270 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictDeleteNonEmptyDirectory) {
420 // Create a server-deleted directory. 271 // Create a server-deleted directory.
421 { 272 {
422 // Create it as a child of root node. 273 // Create it as a child of root node.
423 int64 handle = CreateSyncedItem("parent", syncable::BOOKMARKS, true); 274 int64 handle = entry_factory_->CreateSyncedItem(
275 "parent", syncable::BOOKMARKS, true);
424 276
425 WriteTransaction trans(FROM_HERE, UNITTEST, directory()); 277 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
426 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle); 278 MutableEntry entry(&trans, syncable::GET_BY_HANDLE, handle);
427 ASSERT_TRUE(entry.good()); 279 ASSERT_TRUE(entry.good());
428 280
429 // Delete it on the server. 281 // Delete it on the server.
430 entry.Put(syncable::SERVER_VERSION, GetNextRevision()); 282 entry.Put(syncable::SERVER_VERSION, entry_factory_->GetNextRevision());
431 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true); 283 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
432 entry.Put(syncable::SERVER_PARENT_ID, id_factory_.root()); 284 entry.Put(syncable::SERVER_PARENT_ID, TestIdFactory::root());
433 entry.Put(syncable::SERVER_IS_DEL, true); 285 entry.Put(syncable::SERVER_IS_DEL, true);
434 } 286 }
435 287
436 // Create a local child of the server-deleted directory. 288 // Create a local child of the server-deleted directory.
437 CreateUnsyncedItem(id_factory_.MakeServer("child"), 289 entry_factory_->CreateUnsyncedItem(
438 id_factory_.MakeServer("parent"), "child", false, 290 TestIdFactory::MakeServer("child"), TestIdFactory::MakeServer("parent"),
439 syncable::BOOKMARKS, NULL); 291 "child", false, syncable::BOOKMARKS, NULL);
440 292
441 // The server's request to delete the directory must be ignored, otherwise our 293 // The server's request to delete the directory must be ignored, otherwise our
442 // unsynced new child would be orphaned. This is a hierarchy conflict. 294 // unsynced new child would be orphaned. This is a hierarchy conflict.
443 295
444 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 296 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
445 apply_updates_command_.ExecuteImpl(session()); 297 apply_updates_command_.ExecuteImpl(session());
446 298
447 sessions::StatusController* status = session()->mutable_status_controller(); 299 sessions::StatusController* status = session()->mutable_status_controller();
448 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 300 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
449 301
450 // This should count as a hierarchy conflict. 302 // This should count as a hierarchy conflict.
451 ASSERT_TRUE(status->conflict_progress()); 303 ASSERT_TRUE(status->conflict_progress());
452 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize()); 304 EXPECT_EQ(1, status->conflict_progress()->HierarchyConflictingItemsSize());
453 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()); 305 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize());
454 } 306 }
455 307
456 // Runs the ApplyUpdatesCommand on a server-created item that has a locally 308 // Runs the ApplyUpdatesCommand on a server-created item that has a locally
457 // unknown parent. We expect the command to not apply the update because the 309 // unknown parent. We expect the command to not apply the update because the
458 // item is in a CONFLICT_HIERARCHY state. 310 // item is in a CONFLICT_HIERARCHY state.
459 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictUnknownParent) { 311 TEST_F(ApplyUpdatesCommandTest, HierarchyConflictUnknownParent) {
460 // We shouldn't be able to do anything with either of these items. 312 // We shouldn't be able to do anything with either of these items.
461 CreateUnappliedNewItemWithParent("some_item", 313 entry_factory_->CreateUnappliedNewItemWithParent(
462 DefaultBookmarkSpecifics(), 314 "some_item", DefaultBookmarkSpecifics(), "unknown_parent");
463 "unknown_parent"); 315 entry_factory_->CreateUnappliedNewItemWithParent(
464 CreateUnappliedNewItemWithParent("some_other_item", 316 "some_other_item", DefaultBookmarkSpecifics(), "some_item");
465 DefaultBookmarkSpecifics(),
466 "some_item");
467 317
468 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 318 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
469 apply_updates_command_.ExecuteImpl(session()); 319 apply_updates_command_.ExecuteImpl(session());
470 320
471 sessions::StatusController* status = session()->mutable_status_controller(); 321 sessions::StatusController* status = session()->mutable_status_controller();
472 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 322 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
473 ASSERT_TRUE(status->update_progress()); 323 ASSERT_TRUE(status->update_progress());
474 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) 324 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize())
475 << "All updates should have been attempted"; 325 << "All updates should have been attempted";
476 ASSERT_TRUE(status->conflict_progress()); 326 ASSERT_TRUE(status->conflict_progress());
477 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 327 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
478 << "Updates with unknown parent should not be treated as 'simple'" 328 << "Updates with unknown parent should not be treated as 'simple'"
479 << " conflicts"; 329 << " conflicts";
480 EXPECT_EQ(2, status->conflict_progress()->HierarchyConflictingItemsSize()) 330 EXPECT_EQ(2, status->conflict_progress()->HierarchyConflictingItemsSize())
481 << "All updates with an unknown ancestors should be in conflict"; 331 << "All updates with an unknown ancestors should be in conflict";
482 EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount()) 332 EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount())
483 << "No item with an unknown ancestor should be applied"; 333 << "No item with an unknown ancestor should be applied";
484 } 334 }
485 335
486 TEST_F(ApplyUpdatesCommandTest, ItemsBothKnownAndUnknown) { 336 TEST_F(ApplyUpdatesCommandTest, ItemsBothKnownAndUnknown) {
487 // See what happens when there's a mixture of good and bad updates. 337 // See what happens when there's a mixture of good and bad updates.
488 string root_server_id = syncable::GetNullId().GetServerId(); 338 string root_server_id = syncable::GetNullId().GetServerId();
489 CreateUnappliedNewItemWithParent("first_unknown_item", 339 entry_factory_->CreateUnappliedNewItemWithParent(
490 DefaultBookmarkSpecifics(), 340 "first_unknown_item", DefaultBookmarkSpecifics(), "unknown_parent");
491 "unknown_parent"); 341 entry_factory_->CreateUnappliedNewItemWithParent(
492 CreateUnappliedNewItemWithParent("first_known_item", 342 "first_known_item", DefaultBookmarkSpecifics(), root_server_id);
493 DefaultBookmarkSpecifics(), 343 entry_factory_->CreateUnappliedNewItemWithParent(
494 root_server_id); 344 "second_unknown_item", DefaultBookmarkSpecifics(), "unknown_parent");
495 CreateUnappliedNewItemWithParent("second_unknown_item", 345 entry_factory_->CreateUnappliedNewItemWithParent(
496 DefaultBookmarkSpecifics(), 346 "second_known_item", DefaultBookmarkSpecifics(), "first_known_item");
497 "unknown_parent"); 347 entry_factory_->CreateUnappliedNewItemWithParent(
498 CreateUnappliedNewItemWithParent("second_known_item", 348 "third_known_item", DefaultBookmarkSpecifics(), "fourth_known_item");
499 DefaultBookmarkSpecifics(), 349 entry_factory_->CreateUnappliedNewItemWithParent(
500 "first_known_item"); 350 "fourth_known_item", DefaultBookmarkSpecifics(), root_server_id);
501 CreateUnappliedNewItemWithParent("third_known_item",
502 DefaultBookmarkSpecifics(),
503 "fourth_known_item");
504 CreateUnappliedNewItemWithParent("fourth_known_item",
505 DefaultBookmarkSpecifics(),
506 root_server_id);
507 351
508 ExpectGroupToChange(apply_updates_command_, GROUP_UI); 352 ExpectGroupToChange(apply_updates_command_, GROUP_UI);
509 apply_updates_command_.ExecuteImpl(session()); 353 apply_updates_command_.ExecuteImpl(session());
510 354
511 sessions::StatusController* status = session()->mutable_status_controller(); 355 sessions::StatusController* status = session()->mutable_status_controller();
512 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 356 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
513 ASSERT_TRUE(status->update_progress()); 357 ASSERT_TRUE(status->update_progress());
514 EXPECT_EQ(6, status->update_progress()->AppliedUpdatesSize()) 358 EXPECT_EQ(6, status->update_progress()->AppliedUpdatesSize())
515 << "All updates should have been attempted"; 359 << "All updates should have been attempted";
516 ASSERT_TRUE(status->conflict_progress()); 360 ASSERT_TRUE(status->conflict_progress());
(...skipping 15 matching lines...) Expand all
532 376
533 csync::KeyParams params = {"localhost", "dummy", "foobar"}; 377 csync::KeyParams params = {"localhost", "dummy", "foobar"};
534 cryptographer->AddKey(params); 378 cryptographer->AddKey(params);
535 379
536 sync_pb::EntitySpecifics specifics; 380 sync_pb::EntitySpecifics specifics;
537 sync_pb::PasswordSpecificsData data; 381 sync_pb::PasswordSpecificsData data;
538 data.set_origin("http://example.com"); 382 data.set_origin("http://example.com");
539 383
540 cryptographer->Encrypt(data, 384 cryptographer->Encrypt(data,
541 specifics.mutable_password()->mutable_encrypted()); 385 specifics.mutable_password()->mutable_encrypted());
542 CreateUnappliedNewItem("item", specifics, false); 386 entry_factory_->CreateUnappliedNewItem("item", specifics, false);
543 387
544 ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); 388 ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD);
545 apply_updates_command_.ExecuteImpl(session()); 389 apply_updates_command_.ExecuteImpl(session());
546 390
547 sessions::StatusController* status = session()->mutable_status_controller(); 391 sessions::StatusController* status = session()->mutable_status_controller();
548 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); 392 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD);
549 ASSERT_TRUE(status->update_progress()); 393 ASSERT_TRUE(status->update_progress());
550 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) 394 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize())
551 << "All updates should have been attempted"; 395 << "All updates should have been attempted";
552 ASSERT_TRUE(status->conflict_progress()); 396 ASSERT_TRUE(status->conflict_progress());
553 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 397 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
554 << "No update should be in conflict because they're all decryptable"; 398 << "No update should be in conflict because they're all decryptable";
555 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) 399 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount())
556 << "The updates that can be decrypted should be applied"; 400 << "The updates that can be decrypted should be applied";
557 } 401 }
558 402
559 TEST_F(ApplyUpdatesCommandTest, UndecryptableData) { 403 TEST_F(ApplyUpdatesCommandTest, UndecryptableData) {
560 // Undecryptable updates should not be applied. 404 // Undecryptable updates should not be applied.
561 sync_pb::EntitySpecifics encrypted_bookmark; 405 sync_pb::EntitySpecifics encrypted_bookmark;
562 encrypted_bookmark.mutable_encrypted(); 406 encrypted_bookmark.mutable_encrypted();
563 AddDefaultFieldValue(syncable::BOOKMARKS, &encrypted_bookmark); 407 AddDefaultFieldValue(syncable::BOOKMARKS, &encrypted_bookmark);
564 string root_server_id = syncable::GetNullId().GetServerId(); 408 string root_server_id = syncable::GetNullId().GetServerId();
565 CreateUnappliedNewItemWithParent("folder", 409 entry_factory_->CreateUnappliedNewItemWithParent(
566 encrypted_bookmark, 410 "folder", encrypted_bookmark, root_server_id);
567 root_server_id); 411 entry_factory_->CreateUnappliedNewItem("item2", encrypted_bookmark, false);
568 CreateUnappliedNewItem("item2", encrypted_bookmark, false);
569 sync_pb::EntitySpecifics encrypted_password; 412 sync_pb::EntitySpecifics encrypted_password;
570 encrypted_password.mutable_password(); 413 encrypted_password.mutable_password();
571 CreateUnappliedNewItem("item3", encrypted_password, false); 414 entry_factory_->CreateUnappliedNewItem("item3", encrypted_password, false);
572 415
573 ExpectGroupsToChange(apply_updates_command_, GROUP_UI, GROUP_PASSWORD); 416 ExpectGroupsToChange(apply_updates_command_, GROUP_UI, GROUP_PASSWORD);
574 apply_updates_command_.ExecuteImpl(session()); 417 apply_updates_command_.ExecuteImpl(session());
575 418
576 sessions::StatusController* status = session()->mutable_status_controller(); 419 sessions::StatusController* status = session()->mutable_status_controller();
577 EXPECT_TRUE(status->HasConflictingUpdates()) 420 EXPECT_TRUE(status->HasConflictingUpdates())
578 << "Updates that can't be decrypted should trigger the syncer to have " 421 << "Updates that can't be decrypted should trigger the syncer to have "
579 << "conflicting updates."; 422 << "conflicting updates.";
580 { 423 {
581 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI); 424 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_UI);
582 ASSERT_TRUE(status->update_progress()); 425 ASSERT_TRUE(status->update_progress());
583 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) 426 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize())
584 << "All updates should have been attempted"; 427 << "All updates should have been attempted";
585 ASSERT_TRUE(status->conflict_progress()); 428 ASSERT_TRUE(status->conflict_progress());
586 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 429 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
587 << "The updates that can't be decrypted should not be in regular " 430 << "The updates that can't be decrypted should not be in regular "
588 << "conflict"; 431 << "conflict";
589 EXPECT_EQ(2, status->conflict_progress()->EncryptionConflictingItemsSize()) 432 EXPECT_EQ(2, status->conflict_progress()->EncryptionConflictingItemsSize())
590 << "The updates that can't be decrypted should be in encryption " 433 << "The updates that can't be decrypted should be in encryption "
591 << "conflict"; 434 << "conflict";
592 EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount()) 435 EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount())
593 << "No update that can't be decrypted should be applied"; 436 << "No update that can't be decrypted should be applied";
594 } 437 }
595 { 438 {
596 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); 439 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD);
597 ASSERT_TRUE(status->update_progress()); 440 ASSERT_TRUE(status->update_progress());
598 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize()) 441 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize())
599 << "All updates should have been attempted"; 442 << "All updates should have been attempted";
600 ASSERT_TRUE(status->conflict_progress()); 443 ASSERT_TRUE(status->conflict_progress());
601 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 444 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
602 << "The updates that can't be decrypted should not be in regular " 445 << "The updates that can't be decrypted should not be in regular "
603 << "conflict"; 446 << "conflict";
604 EXPECT_EQ(1, status->conflict_progress()->EncryptionConflictingItemsSize()) 447 EXPECT_EQ(1, status->conflict_progress()->EncryptionConflictingItemsSize())
605 << "The updates that can't be decrypted should be in encryption " 448 << "The updates that can't be decrypted should be in encryption "
606 << "conflict"; 449 << "conflict";
607 EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount()) 450 EXPECT_EQ(0, status->update_progress()->SuccessfullyAppliedUpdateCount())
608 << "No update that can't be decrypted should be applied"; 451 << "No update that can't be decrypted should be applied";
609 } 452 }
610 } 453 }
611 454
612 TEST_F(ApplyUpdatesCommandTest, SomeUndecryptablePassword) { 455 TEST_F(ApplyUpdatesCommandTest, SomeUndecryptablePassword) {
613 // Only decryptable password updates should be applied. 456 // Only decryptable password updates should be applied.
614 { 457 {
615 sync_pb::EntitySpecifics specifics; 458 sync_pb::EntitySpecifics specifics;
616 sync_pb::PasswordSpecificsData data; 459 sync_pb::PasswordSpecificsData data;
617 data.set_origin("http://example.com/1"); 460 data.set_origin("http://example.com/1");
618 { 461 {
619 syncable::ReadTransaction trans(FROM_HERE, directory()); 462 syncable::ReadTransaction trans(FROM_HERE, directory());
620 Cryptographer* cryptographer = directory()->GetCryptographer(&trans); 463 Cryptographer* cryptographer = directory()->GetCryptographer(&trans);
621 464
622 KeyParams params = {"localhost", "dummy", "foobar"}; 465 KeyParams params = {"localhost", "dummy", "foobar"};
623 cryptographer->AddKey(params); 466 cryptographer->AddKey(params);
624 467
625 cryptographer->Encrypt(data, 468 cryptographer->Encrypt(data,
626 specifics.mutable_password()->mutable_encrypted()); 469 specifics.mutable_password()->mutable_encrypted());
627 } 470 }
628 CreateUnappliedNewItem("item1", specifics, false); 471 entry_factory_->CreateUnappliedNewItem("item1", specifics, false);
629 } 472 }
630 { 473 {
631 // Create a new cryptographer, independent of the one in the session. 474 // Create a new cryptographer, independent of the one in the session.
632 Cryptographer cryptographer(&encryptor_); 475 Cryptographer cryptographer(&encryptor_);
633 KeyParams params = {"localhost", "dummy", "bazqux"}; 476 KeyParams params = {"localhost", "dummy", "bazqux"};
634 cryptographer.AddKey(params); 477 cryptographer.AddKey(params);
635 478
636 sync_pb::EntitySpecifics specifics; 479 sync_pb::EntitySpecifics specifics;
637 sync_pb::PasswordSpecificsData data; 480 sync_pb::PasswordSpecificsData data;
638 data.set_origin("http://example.com/2"); 481 data.set_origin("http://example.com/2");
639 482
640 cryptographer.Encrypt(data, 483 cryptographer.Encrypt(data,
641 specifics.mutable_password()->mutable_encrypted()); 484 specifics.mutable_password()->mutable_encrypted());
642 CreateUnappliedNewItem("item2", specifics, false); 485 entry_factory_->CreateUnappliedNewItem("item2", specifics, false);
643 } 486 }
644 487
645 ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD); 488 ExpectGroupToChange(apply_updates_command_, GROUP_PASSWORD);
646 apply_updates_command_.ExecuteImpl(session()); 489 apply_updates_command_.ExecuteImpl(session());
647 490
648 sessions::StatusController* status = session()->mutable_status_controller(); 491 sessions::StatusController* status = session()->mutable_status_controller();
649 EXPECT_TRUE(status->HasConflictingUpdates()) 492 EXPECT_TRUE(status->HasConflictingUpdates())
650 << "Updates that can't be decrypted should trigger the syncer to have " 493 << "Updates that can't be decrypted should trigger the syncer to have "
651 << "conflicting updates."; 494 << "conflicting updates.";
652 { 495 {
653 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD); 496 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSWORD);
654 ASSERT_TRUE(status->update_progress()); 497 ASSERT_TRUE(status->update_progress());
655 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize()) 498 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize())
656 << "All updates should have been attempted"; 499 << "All updates should have been attempted";
657 ASSERT_TRUE(status->conflict_progress()); 500 ASSERT_TRUE(status->conflict_progress());
658 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize()) 501 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
659 << "The updates that can't be decrypted should not be in regular " 502 << "The updates that can't be decrypted should not be in regular "
660 << "conflict"; 503 << "conflict";
661 EXPECT_EQ(1, status->conflict_progress()->EncryptionConflictingItemsSize()) 504 EXPECT_EQ(1, status->conflict_progress()->EncryptionConflictingItemsSize())
662 << "The updates that can't be decrypted should be in encryption " 505 << "The updates that can't be decrypted should be in encryption "
663 << "conflict"; 506 << "conflict";
664 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount()) 507 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount())
665 << "The undecryptable password update shouldn't be applied"; 508 << "The undecryptable password update shouldn't be applied";
666 } 509 }
667 } 510 }
668 511
669 TEST_F(ApplyUpdatesCommandTest, NigoriUpdate) {
670 // Storing the cryptographer separately is bad, but for this test we
671 // know it's safe.
672 Cryptographer* cryptographer;
673 syncable::ModelTypeSet encrypted_types;
674 encrypted_types.Put(syncable::PASSWORDS);
675 encrypted_types.Put(syncable::NIGORI);
676 {
677 syncable::ReadTransaction trans(FROM_HERE, directory());
678 cryptographer = directory()->GetCryptographer(&trans);
679 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
680 }
681
682 // Nigori node updates should update the Cryptographer.
683 Cryptographer other_cryptographer(&encryptor_);
684 KeyParams params = {"localhost", "dummy", "foobar"};
685 other_cryptographer.AddKey(params);
686
687 sync_pb::EntitySpecifics specifics;
688 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
689 other_cryptographer.GetKeys(nigori->mutable_encrypted());
690 nigori->set_encrypt_bookmarks(true);
691 encrypted_types.Put(syncable::BOOKMARKS);
692 CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI),
693 specifics, true);
694 EXPECT_FALSE(cryptographer->has_pending_keys());
695
696 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE);
697 apply_updates_command_.ExecuteImpl(session());
698
699 sessions::StatusController* status = session()->mutable_status_controller();
700 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
701 ASSERT_TRUE(status->update_progress());
702 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize())
703 << "All updates should have been attempted";
704 ASSERT_TRUE(status->conflict_progress());
705 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
706 << "The nigori update shouldn't be in conflict";
707 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount())
708 << "The nigori update should be applied";
709
710 EXPECT_FALSE(cryptographer->is_ready());
711 EXPECT_TRUE(cryptographer->has_pending_keys());
712 EXPECT_TRUE(
713 cryptographer->GetEncryptedTypes()
714 .Equals(syncable::ModelTypeSet::All()));
715 }
716
717 TEST_F(ApplyUpdatesCommandTest, NigoriUpdateForDisabledTypes) {
718 // Storing the cryptographer separately is bad, but for this test we
719 // know it's safe.
720 Cryptographer* cryptographer;
721 syncable::ModelTypeSet encrypted_types;
722 encrypted_types.Put(syncable::PASSWORDS);
723 encrypted_types.Put(syncable::NIGORI);
724 {
725 syncable::ReadTransaction trans(FROM_HERE, directory());
726 cryptographer = directory()->GetCryptographer(&trans);
727 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
728 }
729
730 // Nigori node updates should update the Cryptographer.
731 Cryptographer other_cryptographer(&encryptor_);
732 KeyParams params = {"localhost", "dummy", "foobar"};
733 other_cryptographer.AddKey(params);
734
735 sync_pb::EntitySpecifics specifics;
736 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
737 other_cryptographer.GetKeys(nigori->mutable_encrypted());
738 nigori->set_encrypt_sessions(true);
739 nigori->set_encrypt_themes(true);
740 encrypted_types.Put(syncable::SESSIONS);
741 encrypted_types.Put(syncable::THEMES);
742 CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI),
743 specifics, true);
744 EXPECT_FALSE(cryptographer->has_pending_keys());
745
746 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE);
747 apply_updates_command_.ExecuteImpl(session());
748
749 sessions::StatusController* status = session()->mutable_status_controller();
750 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
751 ASSERT_TRUE(status->update_progress());
752 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize())
753 << "All updates should have been attempted";
754 ASSERT_TRUE(status->conflict_progress());
755 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
756 << "The nigori update shouldn't be in conflict";
757 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount())
758 << "The nigori update should be applied";
759
760 EXPECT_FALSE(cryptographer->is_ready());
761 EXPECT_TRUE(cryptographer->has_pending_keys());
762 EXPECT_TRUE(
763 cryptographer->GetEncryptedTypes()
764 .Equals(syncable::ModelTypeSet::All()));
765 }
766
767 // Create some local unsynced and unencrypted data. Apply a nigori update that
768 // turns on encryption for the unsynced data. Ensure we properly encrypt the
769 // data as part of the nigori update. Apply another nigori update with no
770 // changes. Ensure we ignore already-encrypted unsynced data and that nothing
771 // breaks.
772 TEST_F(ApplyUpdatesCommandTest, EncryptUnsyncedChanges) {
773 // Storing the cryptographer separately is bad, but for this test we
774 // know it's safe.
775 Cryptographer* cryptographer;
776 syncable::ModelTypeSet encrypted_types;
777 encrypted_types.Put(syncable::PASSWORDS);
778 encrypted_types.Put(syncable::NIGORI);
779 {
780 syncable::ReadTransaction trans(FROM_HERE, directory());
781 cryptographer = directory()->GetCryptographer(&trans);
782 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
783
784 // With default encrypted_types, this should be true.
785 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
786
787 Syncer::UnsyncedMetaHandles handles;
788 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
789 EXPECT_TRUE(handles.empty());
790 }
791
792 // Create unsynced bookmarks without encryption.
793 // First item is a folder
794 Id folder_id = id_factory_.NewLocalId();
795 CreateUnsyncedItem(folder_id, id_factory_.root(), "folder",
796 true, syncable::BOOKMARKS, NULL);
797 // Next five items are children of the folder
798 size_t i;
799 size_t batch_s = 5;
800 for (i = 0; i < batch_s; ++i) {
801 CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
802 base::StringPrintf("Item %"PRIuS"", i), false,
803 syncable::BOOKMARKS, NULL);
804 }
805 // Next five items are children of the root.
806 for (; i < 2*batch_s; ++i) {
807 CreateUnsyncedItem(id_factory_.NewLocalId(), id_factory_.root(),
808 base::StringPrintf("Item %"PRIuS"", i), false,
809 syncable::BOOKMARKS, NULL);
810 }
811
812 KeyParams params = {"localhost", "dummy", "foobar"};
813 cryptographer->AddKey(params);
814 sync_pb::EntitySpecifics specifics;
815 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
816 cryptographer->GetKeys(nigori->mutable_encrypted());
817 nigori->set_encrypt_bookmarks(true);
818 encrypted_types.Put(syncable::BOOKMARKS);
819 CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI),
820 specifics, true);
821 EXPECT_FALSE(cryptographer->has_pending_keys());
822 EXPECT_TRUE(cryptographer->is_ready());
823
824 {
825 // Ensure we have unsynced nodes that aren't properly encrypted.
826 syncable::ReadTransaction trans(FROM_HERE, directory());
827 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
828
829 Syncer::UnsyncedMetaHandles handles;
830 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
831 EXPECT_EQ(2*batch_s+1, handles.size());
832 }
833
834 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE);
835 apply_updates_command_.ExecuteImpl(session());
836
837 {
838 sessions::StatusController* status = session()->mutable_status_controller();
839 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
840 ASSERT_TRUE(status->update_progress());
841 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize())
842 << "All updates should have been attempted";
843 ASSERT_TRUE(status->conflict_progress());
844 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
845 << "No updates should be in conflict";
846 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize())
847 << "No updates should be in conflict";
848 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount())
849 << "The nigori update should be applied";
850 }
851 EXPECT_FALSE(cryptographer->has_pending_keys());
852 EXPECT_TRUE(cryptographer->is_ready());
853 {
854 syncable::ReadTransaction trans(FROM_HERE, directory());
855
856 // If ProcessUnsyncedChangesForEncryption worked, all our unsynced changes
857 // should be encrypted now.
858 EXPECT_TRUE(syncable::ModelTypeSet::All().Equals(
859 cryptographer->GetEncryptedTypes()));
860 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
861
862 Syncer::UnsyncedMetaHandles handles;
863 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
864 EXPECT_EQ(2*batch_s+1, handles.size());
865 }
866
867 // Simulate another nigori update that doesn't change anything.
868 {
869 WriteTransaction trans(FROM_HERE, UNITTEST, directory());
870 MutableEntry entry(&trans, syncable::GET_BY_SERVER_TAG,
871 syncable::ModelTypeToRootTag(syncable::NIGORI));
872 ASSERT_TRUE(entry.good());
873 entry.Put(syncable::SERVER_VERSION, GetNextRevision());
874 entry.Put(syncable::IS_UNAPPLIED_UPDATE, true);
875 }
876 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE);
877 apply_updates_command_.ExecuteImpl(session());
878 {
879 sessions::StatusController* status = session()->mutable_status_controller();
880 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
881 ASSERT_TRUE(status->update_progress());
882 EXPECT_EQ(2, status->update_progress()->AppliedUpdatesSize())
883 << "All updates should have been attempted";
884 ASSERT_TRUE(status->conflict_progress());
885 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
886 << "No updates should be in conflict";
887 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize())
888 << "No updates should be in conflict";
889 EXPECT_EQ(2, status->update_progress()->SuccessfullyAppliedUpdateCount())
890 << "The nigori update should be applied";
891 }
892 EXPECT_FALSE(cryptographer->has_pending_keys());
893 EXPECT_TRUE(cryptographer->is_ready());
894 {
895 syncable::ReadTransaction trans(FROM_HERE, directory());
896
897 // All our changes should still be encrypted.
898 EXPECT_TRUE(syncable::ModelTypeSet::All().Equals(
899 cryptographer->GetEncryptedTypes()));
900 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
901
902 Syncer::UnsyncedMetaHandles handles;
903 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
904 EXPECT_EQ(2*batch_s+1, handles.size());
905 }
906 }
907
908 TEST_F(ApplyUpdatesCommandTest, CannotEncryptUnsyncedChanges) {
909 // Storing the cryptographer separately is bad, but for this test we
910 // know it's safe.
911 Cryptographer* cryptographer;
912 syncable::ModelTypeSet encrypted_types;
913 encrypted_types.Put(syncable::PASSWORDS);
914 encrypted_types.Put(syncable::NIGORI);
915 {
916 syncable::ReadTransaction trans(FROM_HERE, directory());
917 cryptographer = directory()->GetCryptographer(&trans);
918 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(encrypted_types));
919
920 // With default encrypted_types, this should be true.
921 EXPECT_TRUE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
922
923 Syncer::UnsyncedMetaHandles handles;
924 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
925 EXPECT_TRUE(handles.empty());
926 }
927
928 // Create unsynced bookmarks without encryption.
929 // First item is a folder
930 Id folder_id = id_factory_.NewLocalId();
931 CreateUnsyncedItem(folder_id, id_factory_.root(), "folder", true,
932 syncable::BOOKMARKS, NULL);
933 // Next five items are children of the folder
934 size_t i;
935 size_t batch_s = 5;
936 for (i = 0; i < batch_s; ++i) {
937 CreateUnsyncedItem(id_factory_.NewLocalId(), folder_id,
938 base::StringPrintf("Item %"PRIuS"", i), false,
939 syncable::BOOKMARKS, NULL);
940 }
941 // Next five items are children of the root.
942 for (; i < 2*batch_s; ++i) {
943 CreateUnsyncedItem(id_factory_.NewLocalId(), id_factory_.root(),
944 base::StringPrintf("Item %"PRIuS"", i), false,
945 syncable::BOOKMARKS, NULL);
946 }
947
948 // We encrypt with new keys, triggering the local cryptographer to be unready
949 // and unable to decrypt data (once updated).
950 Cryptographer other_cryptographer(&encryptor_);
951 KeyParams params = {"localhost", "dummy", "foobar"};
952 other_cryptographer.AddKey(params);
953 sync_pb::EntitySpecifics specifics;
954 sync_pb::NigoriSpecifics* nigori = specifics.mutable_nigori();
955 other_cryptographer.GetKeys(nigori->mutable_encrypted());
956 nigori->set_encrypt_bookmarks(true);
957 encrypted_types.Put(syncable::BOOKMARKS);
958 CreateUnappliedNewItem(syncable::ModelTypeToRootTag(syncable::NIGORI),
959 specifics, true);
960 EXPECT_FALSE(cryptographer->has_pending_keys());
961
962 {
963 // Ensure we have unsynced nodes that aren't properly encrypted.
964 syncable::ReadTransaction trans(FROM_HERE, directory());
965 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
966 Syncer::UnsyncedMetaHandles handles;
967 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
968 EXPECT_EQ(2*batch_s+1, handles.size());
969 }
970
971 ExpectGroupToChange(apply_updates_command_, GROUP_PASSIVE);
972 apply_updates_command_.ExecuteImpl(session());
973
974 sessions::StatusController* status = session()->mutable_status_controller();
975 sessions::ScopedModelSafeGroupRestriction r(status, GROUP_PASSIVE);
976 ASSERT_TRUE(status->update_progress());
977 EXPECT_EQ(1, status->update_progress()->AppliedUpdatesSize())
978 << "All updates should have been attempted";
979 ASSERT_TRUE(status->conflict_progress());
980 EXPECT_EQ(0, status->conflict_progress()->SimpleConflictingItemsSize())
981 << "The unsynced changes don't trigger a blocking conflict with the "
982 << "nigori update.";
983 EXPECT_EQ(0, status->conflict_progress()->EncryptionConflictingItemsSize())
984 << "The unsynced changes don't trigger an encryption conflict with the "
985 << "nigori update.";
986 EXPECT_EQ(1, status->update_progress()->SuccessfullyAppliedUpdateCount())
987 << "The nigori update should be applied";
988 EXPECT_FALSE(cryptographer->is_ready());
989 EXPECT_TRUE(cryptographer->has_pending_keys());
990 {
991 syncable::ReadTransaction trans(FROM_HERE, directory());
992
993 // Since we have pending keys, we would have failed to encrypt, but the
994 // cryptographer should be updated.
995 EXPECT_FALSE(VerifyUnsyncedChangesAreEncrypted(&trans, encrypted_types));
996 EXPECT_TRUE(cryptographer->GetEncryptedTypes().Equals(
997 syncable::ModelTypeSet().All()));
998 EXPECT_FALSE(cryptographer->is_ready());
999 EXPECT_TRUE(cryptographer->has_pending_keys());
1000
1001 Syncer::UnsyncedMetaHandles handles;
1002 SyncerUtil::GetUnsyncedEntries(&trans, &handles);
1003 EXPECT_EQ(2*batch_s+1, handles.size());
1004 }
1005 }
1006
1007 } // namespace csync 512 } // namespace csync
OLDNEW
« no previous file with comments | « sync/engine/apply_updates_command.cc ('k') | sync/engine/conflict_resolver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698