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

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

Issue 27233003: [Sync] Implementation of model association for passwords using sync API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: For review. Created 7 years 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 2013 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 <string>
6 #include <vector>
7
8 #include "base/basictypes.h"
9 #include "base/location.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/scoped_vector.h"
13 #include "chrome/browser/password_manager/mock_password_store.h"
14 #include "chrome/browser/password_manager/password_store_factory.h"
15 #include "chrome/browser/password_manager/password_syncable_service.h"
Ilya Sherman 2013/12/05 07:01:54 nit: This include should be at the very top -- see
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "sync/api/sync_change_processor.h"
19 #include "sync/api/sync_error.h"
20 #include "sync/api/sync_error_factory.h"
21 #include "sync/protocol/password_specifics.pb.h"
22 #include "sync/protocol/sync.pb.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using syncer::SyncChange;
27 using syncer::SyncData;
28 using syncer::SyncDataList;
29 using syncer::SyncError;
30 using testing::Invoke;
31 using testing::Return;
32 using testing::SetArgumentPointee;
33 using testing::_;
34
35 namespace {
36
37 typedef std::vector<SyncChange> SyncChangeList;
38
39 const sync_pb::PasswordSpecificsData& GetPasswordSpecifics(
40 const syncer::SyncData& sync_change) {
41 const sync_pb::EntitySpecifics& specifics = sync_change.GetSpecifics();
42 return specifics.password().client_only_encrypted_data();
43 }
44
45 } // namespace
46
47 // A testable implementation of the |PasswordSyncableService| that mocks
48 // out all interaction with the password database.
49 class TestPasswordSyncableService : public PasswordSyncableService {
Ilya Sherman 2013/12/05 07:01:54 nit: TestPasswordSyncableService -> MockPasswordSy
50 public:
51 explicit TestPasswordSyncableService(PasswordStore* password_store)
52 : PasswordSyncableService(password_store) {}
53 virtual ~TestPasswordSyncableService() {}
54 MOCK_METHOD0(NotifyPasswordStoreOfLoginChanges, void());
55 };
56
57 bool PasswordsEqual(const sync_pb::PasswordSpecificsData& actual_password,
58 const sync_pb::PasswordSpecificsData& expected_password) {
59 return (actual_password.scheme() == expected_password.scheme() &&
60 actual_password.signon_realm() == expected_password.signon_realm() &&
61 actual_password.origin() == expected_password.origin() &&
62 actual_password.action() == expected_password.action() &&
63 actual_password.username_element() ==
64 expected_password.username_element() &&
65 actual_password.password_element() ==
66 expected_password.password_element() &&
67 actual_password.username_value() ==
68 expected_password.username_value() &&
69 actual_password.password_value() ==
70 expected_password.password_value() &&
71 actual_password.ssl_valid() == expected_password.ssl_valid() &&
72 actual_password.preferred() == expected_password.preferred() &&
73 actual_password.date_created() ==
74 expected_password.date_created() &&
75 actual_password.blacklisted() ==
76 expected_password.blacklisted());
77 }
78
79 // Concrete implementation of SyncChangeProcessor. The methods will
80 // verify that the |PasswordSyncableService| is calling the
81 // |SyncChangeProcessor| with right arguments.
82 class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
83 public:
84 TestSyncChangeProcessor() {}
85 virtual ~TestSyncChangeProcessor() {}
86 virtual SyncError ProcessSyncChanges(
87 const tracked_objects::Location& from_here,
88 const SyncChangeList& change_list) OVERRIDE {
89 // Verifies the |change_list| matches the expected changes.
90 for (SyncChangeList::const_iterator it = change_list.begin();
91 it != change_list.end();
92 ++it) {
93 const SyncChange& data = *it;
94 const sync_pb::PasswordSpecificsData& actual_password(
95 GetPasswordSpecifics(data.sync_data()));
96 std::string actual_tag = PasswordSyncableService::MakeTag(
97 actual_password);
98
99 bool matched = false;
100 for (SyncChangeList::iterator expected_it = expected_changes_.begin();
101 expected_it != expected_changes_.end();
102 ++expected_it) {
103 SyncChange expected_data = *expected_it;
104 const sync_pb::PasswordSpecificsData& expected_password(
105 GetPasswordSpecifics(expected_data.sync_data()));
106 std::string expected_tag = PasswordSyncableService::MakeTag(
107 expected_password);
108 if (expected_tag == actual_tag &&
109 PasswordsEqual(actual_password, expected_password)) {
110 if (data.change_type() == expected_data.change_type()) {
111 matched = true;
112 }
113 break;
114 }
115 }
116 EXPECT_TRUE(matched);
117 }
118 EXPECT_EQ(change_list.size(), expected_changes_.size());
119 return SyncError();
120 }
121
122 virtual SyncDataList GetAllSyncData(
123 syncer::ModelType type) const OVERRIDE{
124 return SyncDataList();
125 }
126
127 // Adds a password entry to the |expected_changes_| list.
128 void AddExpectedChange(const autofill::PasswordForm& password,
129 SyncChange::SyncChangeType type) {
130 SyncData data = PasswordSyncableService::CreateSyncData(password);
131 SyncChange change(FROM_HERE, type, data);
132 expected_changes_.push_back(change);
133 }
134
135 private:
136 SyncChangeList expected_changes_;
137 DISALLOW_COPY_AND_ASSIGN(TestSyncChangeProcessor);
138 };
139
140 // Class to verify the arguments passed to |PasswordStore|.
141 class PasswordStoreDataVerifier {
142 public:
143 PasswordStoreDataVerifier() {}
144 virtual ~PasswordStoreDataVerifier() {}
145
146 // Adds an expected add change.
147 void AddExpectedAddChange(const SyncData& data) {
148 const sync_pb::PasswordSpecificsData& password_specifics(
149 GetPasswordSpecifics(data));
150
151 autofill::PasswordForm form;
152 PasswordSyncableService::ExtractPasswordFromSpecifics(password_specifics,
153 &form);
154 expected_add_changes_.push_back(form);
155 }
156
157 // Adds an expected update change.
158 void AddExpectedUpdateChange(const autofill::PasswordForm& form) {
159 expected_update_changes_.push_back(form);
160 }
161
162 // Verifies that the |password| is present in the |expected_add_changes_|
163 // list. If found |password| would be removed from
164 // |expected_add_changes_| list.
165 void VerifyAdd(const autofill::PasswordForm& password) {
166 VerifyChange(password, &expected_add_changes_);
167 }
168
169 // Verifies that the |password| is present in the |expected_update_changes_|
170 // list.
Ilya Sherman 2013/12/05 07:01:54 nit: Please document here as well that the entry w
171 void VerifyUpdate(const autofill::PasswordForm& password) {
172 VerifyChange(password, &expected_update_changes_);
173 }
174
175 size_t AddChangeCount() const {
176 return expected_add_changes_.size();
177 }
178
179 size_t UpdateChangeCount() const {
180 return expected_update_changes_.size();
181 }
182
183 private:
184 void VerifyChange(const autofill::PasswordForm& password,
185 std::vector<autofill::PasswordForm>* password_list) {
186 bool matched = false;
187 for (std::vector<autofill::PasswordForm>::iterator it =
188 password_list->begin();
189 it != password_list->end();
190 ++it) {
191 if (password == *it) {
192 password_list->erase(it);
193 matched = true;
194 break;
195 }
196 }
197 EXPECT_TRUE(matched);
198 }
199
200 std::vector<autofill::PasswordForm> expected_add_changes_;
201 std::vector<autofill::PasswordForm> expected_update_changes_;
202
203 DISALLOW_COPY_AND_ASSIGN(PasswordStoreDataVerifier);
204 };
205
206 namespace {
207
208 // Creates a sync data consisting of password specifics. The sign on realm is
209 // set to |signon_realm|.
210 SyncData CreateSyncData(const std::string& signon_realm) {
211 sync_pb::EntitySpecifics password_data;
212 sync_pb::PasswordSpecificsData* password_specifics =
213 password_data.mutable_password()->mutable_client_only_encrypted_data();
214 password_specifics->set_signon_realm(signon_realm);
215
216 std::string tag = PasswordSyncableService::MakeTag(*password_specifics);
217 return syncer::SyncData::CreateLocalData(tag, tag, password_data);
218 }
Ilya Sherman 2013/12/05 07:01:54 nit: The anonymous namespace should end here. The
219
220 class PasswordSyncableServiceTest : public testing::Test {
221 public:
222 PasswordSyncableServiceTest() {}
223 ~PasswordSyncableServiceTest() {}
224
225 virtual void SetUp() OVERRIDE {
226 TestingProfile::Builder builder;
227 scoped_ptr<Profile> profile = builder.Build().Pass();
228 password_store_ = static_cast<MockPasswordStore*>(
229 PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
230 profile.get(), MockPasswordStore::Build).get());
231 service_.reset(new TestPasswordSyncableService(password_store_));
232 sync_change_processor_.reset(new TestSyncChangeProcessor);
233 }
234
235 PasswordStoreDataVerifier* verifier() {
236 return &verifier_;
237 }
238
239 scoped_ptr<TestSyncChangeProcessor> ReleaseSyncChangeProcessor() {
240 return sync_change_processor_.Pass();
241 }
242
243 // Sets the data that will be returned to the caller accessing password store.
244 void SetPasswordStoreData(
245 const std::vector<autofill::PasswordForm*>& forms) {
246 EXPECT_CALL(*(password_store_.get()), FillAutofillableLogins(_))
247 .WillOnce(DoAll(SetArgumentPointee<0>(forms), Return(true)));
248 }
249
250 protected:
251 scoped_refptr<MockPasswordStore> password_store_;
252 scoped_ptr<TestPasswordSyncableService> service_;
253 PasswordStoreDataVerifier verifier_;
254 scoped_ptr<TestSyncChangeProcessor> sync_change_processor_;
255 };
256
257 } // namespace
258
259 // Both sync and password db have data that are not present in the other.
260 TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) {
261 scoped_ptr<autofill::PasswordForm> form1(new autofill::PasswordForm);
262 form1->signon_realm = "abc";
263
264 sync_change_processor_->AddExpectedChange(*form1,
265 SyncChange::ACTION_ADD);
266
267 std::vector<autofill::PasswordForm*> forms;
268 forms.push_back(form1.release());
269
270 SyncData sync_data = CreateSyncData("def");
271 SyncDataList list;
272 list.push_back(sync_data);
273
274 verifier()->AddExpectedAddChange(sync_data);
275
276 SetPasswordStoreData(forms);
277 EXPECT_CALL(*password_store_, AddLoginImpl(_))
278 .WillRepeatedly(Invoke(
279 verifier(), &PasswordStoreDataVerifier::VerifyAdd));
280
281 EXPECT_CALL(*service_, NotifyPasswordStoreOfLoginChanges());
282
283 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
284 list,
285 ReleaseSyncChangeProcessor(),
286 scoped_ptr<syncer::SyncErrorFactory>());
287
288 EXPECT_EQ(0, verifier()->AddChangeCount());
289 }
290
291 // Sync has data that is not present in the password db.
292 TEST_F(PasswordSyncableServiceTest, AdditionOnlyInSync) {
293 std::vector<autofill::PasswordForm*> forms;
294
295 SyncData sync_data = CreateSyncData("def");
296 SyncDataList list;
297 list.push_back(sync_data);
298
299 verifier()->AddExpectedAddChange(sync_data);
300
301 SetPasswordStoreData(forms);
302
303 EXPECT_CALL(*password_store_, AddLoginImpl(_))
304 .WillRepeatedly(Invoke(
305 verifier(), &PasswordStoreDataVerifier::VerifyAdd));
306
307 EXPECT_CALL(*service_, NotifyPasswordStoreOfLoginChanges());
308
309 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
310 list,
311 ReleaseSyncChangeProcessor(),
312 scoped_ptr<syncer::SyncErrorFactory>());
Ilya Sherman 2013/12/05 07:01:54 nit: Please align params.
313
314 EXPECT_EQ(0, verifier()->AddChangeCount());
315 }
316
317 // Passwords db has data that is not present in sync.
318 TEST_F(PasswordSyncableServiceTest, AdditionOnlyInPasswordStore) {
319 autofill::PasswordForm *form1 = new autofill::PasswordForm;
Ilya Sherman 2013/12/05 07:01:54 nit: "autofill::PasswordForm *form1" -> "scoped_pt
320 form1->signon_realm = "abc";
321
322 std::vector<autofill::PasswordForm*> forms;
Ilya Sherman 2013/12/05 07:01:54 nit: ScopedVector (applies throughout)
323 forms.push_back(form1);
324
325 SyncDataList list;
Ilya Sherman 2013/12/05 07:01:54 nit: You could just pass SyncDataList() on line 33
326
327 sync_change_processor_->AddExpectedChange(*form1,
328 SyncChange::ACTION_ADD);
329
330 SetPasswordStoreData(forms);
331
332 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
333 list,
334 ReleaseSyncChangeProcessor(),
335 scoped_ptr<syncer::SyncErrorFactory>());
336
337 EXPECT_EQ(0, verifier()->AddChangeCount());
338 }
339
340 // Both passwords db and sync contain the same data.
341 TEST_F(PasswordSyncableServiceTest, BothInSync) {
342 autofill::PasswordForm *form1 = new autofill::PasswordForm;
343 form1->signon_realm = "abc";
344
345 std::vector<autofill::PasswordForm*> forms;
346 forms.push_back(form1);
347
348 SyncData sync_data = CreateSyncData("abc");
349 SyncDataList list;
350 list.push_back(sync_data);
351
352 SetPasswordStoreData(forms);
353
354 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
355 list,
356 ReleaseSyncChangeProcessor(),
357 scoped_ptr<syncer::SyncErrorFactory>());
Ilya Sherman 2013/12/05 07:01:54 nit: Align args.
358 EXPECT_EQ(0, verifier()->AddChangeCount());
359 EXPECT_EQ(0, verifier()->UpdateChangeCount());
360 }
361
362 // Both passwords db and sync have the same data but they need to be merged
363 // as some fields of the data differ.
364 TEST_F(PasswordSyncableServiceTest, Merge) {
365 autofill::PasswordForm *form1 = new autofill::PasswordForm;
366 form1->signon_realm = "abc";
367 form1->action = GURL("http://pie.com");
368
369 std::vector<autofill::PasswordForm*> forms;
370 forms.push_back(form1);
371
372 SyncData sync_data = CreateSyncData("abc");
373 SyncDataList list;
374 list.push_back(sync_data);
375
376 sync_change_processor_->AddExpectedChange(*form1,
377 SyncChange::ACTION_UPDATE);
378
379 verifier()->AddExpectedUpdateChange(*form1);
380
381 SetPasswordStoreData(forms);
382
383 EXPECT_CALL(*password_store_, UpdateLoginImpl(_))
384 .WillRepeatedly(Invoke(verifier(),
385 &PasswordStoreDataVerifier::VerifyUpdate));
386
387 EXPECT_CALL(*service_, NotifyPasswordStoreOfLoginChanges());
388
389 service_->MergeDataAndStartSyncing(syncer::PASSWORDS,
390 list,
391 ReleaseSyncChangeProcessor(),
392 scoped_ptr<syncer::SyncErrorFactory>());
Ilya Sherman 2013/12/05 07:01:54 nit: Align args.
393
394 EXPECT_EQ(0, verifier()->UpdateChangeCount());
395 }
396
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698