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

Side by Side Diff: chrome/browser/password_manager/password_syncable_service_unittest.cc

Issue 131003006: Password sync refactoring: implemented |MergeDataAndStartSyncing| and unit_tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: win compilation Created 6 years, 10 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 2014 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 "chrome/browser/password_manager/password_syncable_service.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/location.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "chrome/browser/password_manager/mock_password_store.h"
16 #include "sync/api/sync_change_processor.h"
17 #include "sync/api/sync_error.h"
18 #include "sync/api/sync_error_factory.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using syncer::SyncChange;
23 using syncer::SyncData;
24 using syncer::SyncDataList;
25 using syncer::SyncError;
26 using testing::Invoke;
27 using testing::Return;
28 using testing::SetArgPointee;
29 using testing::_;
30
31 namespace {
32
33 typedef std::vector<SyncChange> SyncChangeList;
34
35 const sync_pb::PasswordSpecificsData& GetPasswordSpecifics(
36 const syncer::SyncData& sync_change) {
37 const sync_pb::EntitySpecifics& specifics = sync_change.GetSpecifics();
38 return specifics.password().client_only_encrypted_data();
39 }
40
41 void PasswordsEqual(const sync_pb::PasswordSpecificsData& expected_password,
42 const sync_pb::PasswordSpecificsData& actual_password) {
43 EXPECT_EQ(expected_password.scheme(), actual_password.scheme());
44 EXPECT_EQ(expected_password.signon_realm(), actual_password.signon_realm());
45 EXPECT_EQ(expected_password.origin(), actual_password.origin());
46 EXPECT_EQ(expected_password.action(), actual_password.action());
47 EXPECT_EQ(expected_password.username_element(),
48 actual_password.username_element());
49 EXPECT_EQ(expected_password.password_element(),
50 actual_password.password_element());
51 EXPECT_EQ(expected_password.username_value(),
52 actual_password.username_value());
53 EXPECT_EQ(expected_password.password_value(),
54 actual_password.password_value());
55 EXPECT_EQ(expected_password.ssl_valid(), actual_password.ssl_valid());
56 EXPECT_EQ(expected_password.preferred(), actual_password.preferred());
57 EXPECT_EQ(expected_password.date_created(), actual_password.date_created());
58 EXPECT_EQ(expected_password.blacklisted(), actual_password.blacklisted());
59 }
60
61 // Creates a sync data consisting of password specifics. The sign on realm is
62 // set to |signon_realm|.
63 SyncData CreateSyncData(const std::string& signon_realm) {
64 sync_pb::EntitySpecifics password_data;
65 sync_pb::PasswordSpecificsData* password_specifics =
66 password_data.mutable_password()->mutable_client_only_encrypted_data();
67 password_specifics->set_signon_realm(signon_realm);
68
69 std::string tag = MakePasswordSyncTag(*password_specifics);
70 return syncer::SyncData::CreateLocalData(tag, tag, password_data);
71 }
72
73 SyncChange CreateSyncChange(const autofill::PasswordForm& password,
74 SyncChange::SyncChangeType type) {
75 SyncData data = SyncDataFromPassword(password);
76 return SyncChange(FROM_HERE, type, data);
77 }
78
79 // A testable implementation of the |PasswordSyncableService| that mocks
80 // out all interaction with the password database.
81 class MockPasswordSyncableService : public PasswordSyncableService {
82 public:
83 explicit MockPasswordSyncableService(PasswordStore* password_store)
84 : PasswordSyncableService(password_store) {}
85 virtual ~MockPasswordSyncableService() {}
86
87 MOCK_METHOD0(NotifyPasswordStoreOfLoginChanges, void());
88 };
89
90 // Concrete implementation of SyncChangeProcessor. The methods will
91 // verify that the |PasswordSyncableService| is calling the
92 // |SyncChangeProcessor| with right arguments.
93 class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
94 public:
95 TestSyncChangeProcessor() {}
96 virtual ~TestSyncChangeProcessor() {}
97
98 MOCK_METHOD2(ProcessSyncChanges, SyncError(const tracked_objects::Location&,
99 const SyncChangeList&));
100
101 virtual SyncDataList GetAllSyncData(syncer::ModelType type) const OVERRIDE {
102 return SyncDataList();
103 }
104 };
105
106 // Class to verify the arguments passed to |PasswordStore|.
107 class PasswordStoreDataVerifier {
108 public:
109 PasswordStoreDataVerifier() {}
110 ~PasswordStoreDataVerifier() {
111 EXPECT_TRUE(expected_db_add_changes_.empty());
112 EXPECT_TRUE(expected_db_update_changes_.empty());
113 }
114
115 // Sets expected changes to the password database.
116 void SetExpectedDBChanges(
117 const SyncDataList& add_forms,
118 const std::vector<autofill::PasswordForm*>& update_forms,
119 MockPasswordStore* password_store);
120 // Sets expected changes to |sync_processor|.
121 void SetExpectedSyncChanges(SyncChangeList list,
122 TestSyncChangeProcessor* sync_processor);
123
124 private:
125 // Checks that |change_list| matches |expected_sync_change_list_|.
126 SyncError TestSyncChanges(const tracked_objects::Location& from_here,
127 const SyncChangeList& change_list);
128
129 // Verifies that the |password| is present in the |expected_db_add_changes_|
130 // list. If found |password| would be removed from
131 // |expected_db_add_changes_| list.
132 void VerifyAdd(const autofill::PasswordForm& password) {
133 VerifyChange(password, &expected_db_add_changes_);
134 }
135
136 // Verifies that the |password| is present in the
137 // |expected_db_update_changes_| list.
138 void VerifyUpdate(const autofill::PasswordForm& password) {
139 VerifyChange(password, &expected_db_update_changes_);
140 }
141
142 static void VerifyChange(const autofill::PasswordForm& password,
143 std::vector<autofill::PasswordForm>* password_list);
144
145 std::vector<autofill::PasswordForm> expected_db_add_changes_;
146 std::vector<autofill::PasswordForm> expected_db_update_changes_;
147 SyncChangeList expected_sync_change_list_;
148
149 DISALLOW_COPY_AND_ASSIGN(PasswordStoreDataVerifier);
150 };
151
152 void PasswordStoreDataVerifier::SetExpectedDBChanges(
153 const SyncDataList& add_forms,
154 const std::vector<autofill::PasswordForm*>& update_forms,
155 MockPasswordStore* password_store) {
156 DCHECK(expected_db_add_changes_.empty());
157 DCHECK(expected_db_update_changes_.empty());
158 DCHECK(password_store);
159
160 for (SyncDataList::const_iterator i = add_forms.begin();
161 i != add_forms.end(); ++i) {
162 autofill::PasswordForm form;
163 PasswordFromSpecifics(GetPasswordSpecifics(*i), &form);
164 expected_db_add_changes_.push_back(form);
165 }
166 if (expected_db_add_changes_.empty()) {
167 EXPECT_CALL(*password_store, AddLoginImpl(_)).Times(0);
168 } else {
169 EXPECT_CALL(*password_store, AddLoginImpl(_))
170 .Times(expected_db_add_changes_.size())
171 .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyAdd));
172 }
173
174 for (std::vector<autofill::PasswordForm*>::const_iterator i =
175 update_forms.begin();
176 i != update_forms.end(); ++i) {
177 expected_db_update_changes_.push_back(**i);
178 }
179 if (expected_db_update_changes_.empty()) {
180 EXPECT_CALL(*password_store, UpdateLoginImpl(_)).Times(0);
181 } else {
182 EXPECT_CALL(*password_store, UpdateLoginImpl(_))
183 .Times(expected_db_update_changes_.size())
184 .WillRepeatedly(Invoke(this, &PasswordStoreDataVerifier::VerifyUpdate));
Nicolas Zea 2014/01/31 07:56:01 Same comment as below (here and elsewhere). If pos
vasilii 2014/01/31 13:23:23 UpdateLoginImpl is a mock method from MockPassword
185 }
186 }
187
188 void PasswordStoreDataVerifier::SetExpectedSyncChanges(
189 SyncChangeList list, TestSyncChangeProcessor* sync_processor) {
190 DCHECK(sync_processor);
191 expected_sync_change_list_.swap(list);
192 EXPECT_CALL(*sync_processor, ProcessSyncChanges(_,_))
Nicolas Zea 2014/01/31 07:56:01 Why not make the sync processor's ProcessSyncChang
vasilii 2014/01/31 13:23:23 Done.
193 .WillOnce(Invoke(this, &PasswordStoreDataVerifier::TestSyncChanges));
194 }
195
196 SyncError PasswordStoreDataVerifier::TestSyncChanges(
197 const tracked_objects::Location& from_here,
198 const SyncChangeList& change_list) {
199 for (SyncChangeList::const_iterator it = change_list.begin();
200 it != change_list.end(); ++it) {
201 const SyncChange& data = *it;
202 const sync_pb::PasswordSpecificsData& actual_password(
203 GetPasswordSpecifics(data.sync_data()));
204 std::string actual_tag = MakePasswordSyncTag(actual_password);
205
206 bool matched = false;
207 for (SyncChangeList::iterator expected_it =
208 expected_sync_change_list_.begin();
209 expected_it != expected_sync_change_list_.end();
210 ++expected_it) {
211 const sync_pb::PasswordSpecificsData& expected_password(
212 GetPasswordSpecifics(expected_it->sync_data()));
213 if (actual_tag == MakePasswordSyncTag(expected_password)) {
214 PasswordsEqual(expected_password, actual_password);
215 EXPECT_EQ(expected_it->change_type(), data.change_type());
216 matched = true;
217 break;
218 }
219 }
220 EXPECT_TRUE(matched) << actual_tag;
221 }
222 EXPECT_EQ(expected_sync_change_list_.size(), change_list.size());
223 return SyncError();
224 }
225
226 // static
227 void PasswordStoreDataVerifier::VerifyChange(
228 const autofill::PasswordForm& password,
229 std::vector<autofill::PasswordForm>* password_list) {
230 std::vector<autofill::PasswordForm>::iterator it =
231 std::find(password_list->begin(), password_list->end(), password);
232 ASSERT_NE(password_list->end(), it);
233 password_list->erase(it);
234 }
235
236 class PasswordSyncableServiceTest : public testing::Test {
237 public:
238 PasswordSyncableServiceTest() {}
239 virtual ~PasswordSyncableServiceTest() {}
240
241 virtual void SetUp() OVERRIDE {
242 password_store_ = new MockPasswordStore;
243 service_.reset(new MockPasswordSyncableService(password_store_));
244 sync_change_processor_.reset(new TestSyncChangeProcessor);
245 }
246
247 PasswordStoreDataVerifier* verifier() {
248 return &verifier_;
249 }
250
251 scoped_ptr<syncer::SyncChangeProcessor> ReleaseSyncChangeProcessor() {
252 return sync_change_processor_.PassAs<syncer::SyncChangeProcessor>();
253 }
254
255 // Sets the data that will be returned to the caller accessing password store.
256 void SetPasswordStoreData(const std::vector<autofill::PasswordForm*>& forms) {
257 EXPECT_CALL(*password_store_, FillAutofillableLogins(_))
258 .WillOnce(DoAll(SetArgPointee<0>(forms), Return(true)));
259 }
260
261 protected:
262 scoped_refptr<MockPasswordStore> password_store_;
263 scoped_ptr<MockPasswordSyncableService> service_;
264 PasswordStoreDataVerifier verifier_;
265 scoped_ptr<TestSyncChangeProcessor> sync_change_processor_;
266 };
267
268
269 // Both sync and password db have data that are not present in the other.
270 TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) {
271 autofill::PasswordForm* form1 = new autofill::PasswordForm;
272 form1->signon_realm = "abc";
273 std::vector<autofill::PasswordForm*> forms;
274 forms.push_back(form1);
275 SetPasswordStoreData(forms);
276
277 SyncData sync_data = CreateSyncData("def");
278 SyncDataList list;
279 list.push_back(sync_data);
280
281 verifier()->SetExpectedDBChanges(list,
282 std::vector<autofill::PasswordForm*>(),
283 password_store_);
284 verifier()->SetExpectedSyncChanges(
285 SyncChangeList(1, CreateSyncChange(*form1, SyncChange::ACTION_ADD)),
286 sync_change_processor_.get());
287 EXPECT_CALL(*service_, NotifyPasswordStoreOfLoginChanges());
288
289 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
290 list,
291 ReleaseSyncChangeProcessor(),
292 scoped_ptr<syncer::SyncErrorFactory>());
293 }
294
295 // Sync has data that is not present in the password db.
296 TEST_F(PasswordSyncableServiceTest, AdditionOnlyInSync) {
297 SetPasswordStoreData(std::vector<autofill::PasswordForm*>());
298
299 SyncData sync_data = CreateSyncData("def");
300 SyncDataList list;
301 list.push_back(sync_data);
302
303 verifier()->SetExpectedDBChanges(list,
304 std::vector<autofill::PasswordForm*>(),
305 password_store_);
306 verifier()->SetExpectedSyncChanges(SyncChangeList(),
307 sync_change_processor_.get());
308 EXPECT_CALL(*service_, NotifyPasswordStoreOfLoginChanges());
309
310 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
311 list,
312 ReleaseSyncChangeProcessor(),
313 scoped_ptr<syncer::SyncErrorFactory>());
314 }
315
316 // Passwords db has data that is not present in sync.
317 TEST_F(PasswordSyncableServiceTest, AdditionOnlyInPasswordStore) {
318 autofill::PasswordForm* form1 = new autofill::PasswordForm;
319 form1->signon_realm = "abc";
320 std::vector<autofill::PasswordForm*> forms;
321 forms.push_back(form1);
322 SetPasswordStoreData(forms);
323
324 verifier()->SetExpectedDBChanges(SyncDataList(),
325 std::vector<autofill::PasswordForm*>(),
326 password_store_);
327 verifier()->SetExpectedSyncChanges(
328 SyncChangeList(1, CreateSyncChange(*form1, SyncChange::ACTION_ADD)),
329 sync_change_processor_.get());
330
331 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
332 SyncDataList(),
333 ReleaseSyncChangeProcessor(),
334 scoped_ptr<syncer::SyncErrorFactory>());
335 }
336
337 // Both passwords db and sync contain the same data.
338 TEST_F(PasswordSyncableServiceTest, BothInSync) {
339 autofill::PasswordForm *form1 = new autofill::PasswordForm;
340 form1->signon_realm = "abc";
341 std::vector<autofill::PasswordForm*> forms;
342 forms.push_back(form1);
343 SetPasswordStoreData(forms);
344
345 verifier()->SetExpectedDBChanges(SyncDataList(),
346 std::vector<autofill::PasswordForm*>(),
347 password_store_);
348 verifier()->SetExpectedSyncChanges(SyncChangeList(),
349 sync_change_processor_.get());
350
351 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
352 SyncDataList(1, CreateSyncData("abc")),
353 ReleaseSyncChangeProcessor(),
354 scoped_ptr<syncer::SyncErrorFactory>());
355 }
356
357 // Both passwords db and sync have the same data but they need to be merged
358 // as some fields of the data differ.
359 TEST_F(PasswordSyncableServiceTest, Merge) {
360 autofill::PasswordForm *form1 = new autofill::PasswordForm;
361 form1->signon_realm = "abc";
362 form1->action = GURL("http://pie.com");
363 form1->date_created = base::Time::Now();
364 std::vector<autofill::PasswordForm*> forms;
365 forms.push_back(form1);
366 SetPasswordStoreData(forms);
367
368 verifier()->SetExpectedDBChanges(SyncDataList(),
369 forms,
370 password_store_);
371 verifier()->SetExpectedSyncChanges(
372 SyncChangeList(1, CreateSyncChange(*form1, SyncChange::ACTION_UPDATE)),
373 sync_change_processor_.get());
374
375 EXPECT_CALL(*service_, NotifyPasswordStoreOfLoginChanges());
376
377 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
378 SyncDataList(1, CreateSyncData("abc")),
379 ReleaseSyncChangeProcessor(),
380 scoped_ptr<syncer::SyncErrorFactory>());
381 }
382
383 // Initiate sync due to local DB changes.
384 TEST_F(PasswordSyncableServiceTest, PasswordStoreChanges) {
385 // Set the sync change processor first.
386 SetPasswordStoreData(std::vector<autofill::PasswordForm*>());
387 TestSyncChangeProcessor* sync_processor = sync_change_processor_.get();
388 verifier()->SetExpectedSyncChanges(SyncChangeList(), sync_processor);
389 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
390 SyncDataList(),
391 ReleaseSyncChangeProcessor(),
392 scoped_ptr<syncer::SyncErrorFactory>());
393 ::testing::Mock::VerifyAndClearExpectations(sync_processor);
394
395 autofill::PasswordForm form1;
396 form1.signon_realm = "abc";
397 autofill::PasswordForm form2;
398 form2.signon_realm = "def";
399 autofill::PasswordForm form3;
400 form3.signon_realm = "xyz";
401
402 SyncChangeList sync_list;
403 sync_list.push_back(CreateSyncChange(form1, SyncChange::ACTION_ADD));
404 sync_list.push_back(CreateSyncChange(form2, SyncChange::ACTION_UPDATE));
405 sync_list.push_back(CreateSyncChange(form3, SyncChange::ACTION_DELETE));
406
407 verifier()->SetExpectedDBChanges(SyncDataList(),
408 std::vector<autofill::PasswordForm*>(),
409 password_store_);
410 verifier()->SetExpectedSyncChanges(sync_list, sync_processor);
411
412 PasswordStoreChangeList list;
413 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form1));
414 list.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, form2));
415 list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form3));
416 service_->ActOnPasswordStoreChanges(list);
417 }
418
419 } // namespace
OLDNEW
« no previous file with comments | « chrome/browser/password_manager/password_syncable_service.cc ('k') | chrome/chrome_tests_unit.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698