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

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: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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"
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 // This class will be instantiated by the tests rather than the
40 // |PasswordSyncableService| as this class will mock away any calls
41 // that touch the password db.
42 class TestPasswordSyncableService : public PasswordSyncableService {
43 public:
44 explicit TestPasswordSyncableService(PasswordStore* password_store):
Ilya Sherman 2013/11/05 08:39:21 nit: The colon belongs on the next line, formatted
lipalani1 2013/11/19 00:46:54 Done.
45 PasswordSyncableService(password_store) {}
46 virtual ~TestPasswordSyncableService() {}
47 MOCK_METHOD0(NotifyPasswordStore, void());
48 };
49
50 // Concrete implementation of SyncChangeprocessor. The methods will
Ilya Sherman 2013/11/05 08:39:21 nit: "SyncChangeprocessor" -> "SyncChangeProcessor
lipalani1 2013/11/19 00:46:54 Done.
51 // verify that the |PasswordSyncableService| is calling the
52 // |SyncChangeProcessor| with right arguments.
53 class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
54 public:
55 TestSyncChangeProcessor() {}
56 virtual ~TestSyncChangeProcessor() {}
57 virtual SyncError ProcessSyncChanges(
58 const tracked_objects::Location& from_here,
59 const SyncChangeList& change_list) {
60 // Loop through the |change_list| and verify they are present in the
61 // |expected_changes_| list.
62 for (SyncChangeList::const_iterator it = change_list.begin();
63 it != change_list.end();
64 ++it) {
65 SyncChange data = *it;
66 const sync_pb::EntitySpecifics& specifics =
67 data.sync_data().GetSpecifics();
68 const sync_pb::PasswordSpecificsData& password_specifics(
69 specifics.password().client_only_encrypted_data());
70 std::string actual_tag = PasswordSyncableService::MakeTag(
71 password_specifics);
Ilya Sherman 2013/11/05 08:39:21 nit: Might be helpful to decompose lines 66-71 int
lipalani1 2013/11/19 00:46:54 Done.
72
73 bool matched = false;
74 for (SyncChangeList::iterator expected_it = expected_changes_.begin();
75 expected_it != expected_changes_.end();
76 ++expected_it) {
77 SyncChange expected_data = *expected_it;
78 const sync_pb::EntitySpecifics& specifics =
79 expected_data.sync_data().GetSpecifics();
80 const sync_pb::PasswordSpecificsData& password_specifics(
81 specifics.password().client_only_encrypted_data());
82 std::string expected_tag = PasswordSyncableService::MakeTag(
83 password_specifics);
84 if (expected_tag == actual_tag) {
85 if (data.change_type() == expected_data.change_type()) {
86 matched = true;
87 }
88 break;
89 }
90 }
91 EXPECT_TRUE(matched);
92 }
93 EXPECT_EQ(change_list.size(), expected_changes_.size());
94 return SyncError();
95 }
96
97 virtual SyncDataList GetAllSyncData(syncer::ModelType type) const {
98 return SyncDataList();
99 }
100
101 // Adds a password entry to the |expected_changes_| list.
102 void AddExpectedChange(const autofill::PasswordForm& password,
103 SyncChange::SyncChangeType type) {
104 SyncData data = PasswordSyncableService::CreateSyncData(password);
105 SyncChange change(FROM_HERE, type, data);
106 expected_changes_.push_back(change);
107 }
108
109 private:
110 SyncChangeList expected_changes_;
111 DISALLOW_COPY_AND_ASSIGN(TestSyncChangeProcessor);
112 };
113
114 // Class to verify the arguments passed to |PasswordStore|.
115 class PasswordStoreDataVerifier {
116 public:
117 PasswordStoreDataVerifier() {}
118 virtual ~PasswordStoreDataVerifier() {}
119
120 // Adds an expected add change.
121 void AddExpectedAddChange(const SyncData& data) {
122 const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
123 const sync_pb::PasswordSpecificsData& password_specifics(
124 specifics.password().client_only_encrypted_data());
125
126 autofill::PasswordForm form;
127 PasswordSyncableService::ExtractPasswordFromSpecifics(password_specifics,
128 &form);
129 add_changes_.push_back(form);
130 }
131
132 // Adds an expected update change.
133 void AddExpectedUpdateChange(const autofill::PasswordForm& form) {
134 update_changes_.push_back(form);
135 }
136
137 // Verifies that the |password| is present in the |add_changes_| list.
Ilya Sherman 2013/11/05 08:39:21 Please document that this has a side-effect of rem
lipalani1 2013/11/19 00:46:54 Done.
138 void VerifyAdd(const autofill::PasswordForm& password) {
139 VerifyChange(password, &add_changes_);
140 }
141
142 // Verifies that the |password| is present in the |update_changes_| list.
143 void VerifyUpdate(const autofill::PasswordForm& password) {
144 VerifyChange(password, &update_changes_);
145 }
146
147 int AddChangeCount() const {
Ilya Sherman 2013/11/05 08:39:21 nit: Consider making the return value for this met
lipalani1 2013/11/19 00:46:54 Done.
148 return add_changes_.size();
149 }
150
151 int UpdateChangeCount() const {
152 return update_changes_.size();
153 }
154
155 private:
156 void VerifyChange(const autofill::PasswordForm& password,
157 std::vector<autofill::PasswordForm>* password_list) {
158 bool matched = false;
159 for (std::vector<autofill::PasswordForm>::iterator it
160 = password_list->begin();
161 it != password_list->end();
162 ++it) {
163 if (password == *it) {
164 password_list->erase(it);
165 matched = true;
166 break;
167 }
168 }
169 EXPECT_TRUE(matched);
170 }
Ilya Sherman 2013/11/05 08:39:21 nit: Please leave a blank line after this one.
lipalani1 2013/11/19 00:46:54 Done.
171 std::vector<autofill::PasswordForm> add_changes_;
172 std::vector<autofill::PasswordForm> update_changes_;
Ilya Sherman 2013/11/05 08:39:21 nit: Consider naming these variables something mor
lipalani1 2013/11/19 00:46:54 'Add' and 'Update' terminologies are also widely u
173 DISALLOW_COPY_AND_ASSIGN(PasswordStoreDataVerifier);
174 };
175
176 SyncData CreateSyncData(std::string signon_realm) {
Ilya Sherman 2013/11/05 08:39:21 nit: Please pass by const-reference.
Ilya Sherman 2013/11/05 08:39:21 nit: Docs, please.
lipalani1 2013/11/19 00:46:54 Done.
lipalani1 2013/11/19 00:46:54 Done.
177 sync_pb::EntitySpecifics password_data;
178 sync_pb::PasswordSpecificsData* password_specifics =
179 password_data.mutable_password()->mutable_client_only_encrypted_data();
180 password_specifics->set_signon_realm(signon_realm);
181
182 std::string tag = PasswordSyncableService::MakeTag(*password_specifics);
183 return syncer::SyncData::CreateLocalData(tag, tag, password_data);
184 }
Ilya Sherman 2013/11/05 08:39:21 nit: Please tuck all of the code above this line i
lipalani1 2013/11/19 00:46:54 Done.
185
186 class PasswordSyncableServiceTest : public testing::Test {
187 public:
188 PasswordSyncableServiceTest() {}
189 ~PasswordSyncableServiceTest() {}
190
191 virtual void SetUp() OVERRIDE {
192 TestingProfile::Builder builder;
193 scoped_ptr<Profile> profile = builder.Build().Pass();
194 password_store_ = static_cast<MockPasswordStore*>(
195 PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
196 profile.get(), MockPasswordStore::Build).get());
197 service_.reset(new TestPasswordSyncableService(password_store_));
198 sync_change_processor_.reset(new TestSyncChangeProcessor);
199 }
200
201 TestPasswordSyncableService* service() {
202 return service_.get();
203 }
204
205 PasswordStoreDataVerifier* verifier() {
206 return &verifier_;
207 }
208
209 TestSyncChangeProcessor* sync_change_processor() {
210 return sync_change_processor_.get();
211 }
212
213 scoped_ptr<TestSyncChangeProcessor> ReleaseSyncChangeProcessor() {
214 return sync_change_processor_.Pass();
215 }
Ilya Sherman 2013/11/05 08:39:21 These four accessors seem unnecessary given that t
lipalani1 2013/11/19 00:46:54 Done. However I have left the verififer() in place
216
217 void SetPasswordStoreData(
218 const std::vector<autofill::PasswordForm*>& forms) {
Ilya Sherman 2013/11/05 08:39:21 nit: Docs, please.
lipalani1 2013/11/19 00:46:54 Done.
219 EXPECT_CALL(*(password_store_.get()), FillAutofillableLogins(_))
220 .WillOnce(DoAll(SetArgumentPointee<0>(forms), Return(true)));
221 EXPECT_CALL(*(password_store_.get()), FillBlacklistLogins(_))
222 .WillOnce(Return(true));
Ilya Sherman 2013/11/05 08:39:21 Please also add test coverage for FillBlacklistLog
lipalani1 2013/11/19 00:46:54 Good point. this cl has gotten big already. I have
Ilya Sherman 2013/11/19 22:49:03 I'm not comfortable with punting tests to follow-u
223 }
224
225 protected:
226 scoped_refptr<MockPasswordStore> password_store_;
227 scoped_ptr<TestPasswordSyncableService> service_;
228 PasswordStoreDataVerifier verifier_;
229 scoped_ptr<TestSyncChangeProcessor> sync_change_processor_;
230 };
231
232 // Both sync and password db have data that are not present in the other.
233 TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) {
234 autofill::PasswordForm *form1 = new autofill::PasswordForm;
Ilya Sherman 2013/11/05 08:39:21 nit: Asterisk belongs before the space.
Ilya Sherman 2013/11/05 08:39:21 Please use a scoped_ptr to own the memory for this
lipalani1 2013/11/19 00:46:54 Done.
lipalani1 2013/11/19 00:46:54 Done.
235 form1->signon_realm = "abc";
236
237 std::vector<autofill::PasswordForm*> forms;
238 forms.push_back(form1);
239
240 SyncData sync_data = CreateSyncData("def");
241 SyncDataList list;
242 list.push_back(sync_data);
243
244 sync_change_processor()->AddExpectedChange(*form1,
245 SyncChange::ACTION_ADD);
246
247 verifier()->AddExpectedAddChange(sync_data);
248
249 SetPasswordStoreData(forms);
250 EXPECT_CALL(*password_store_, AddLoginImpl(_))
251 .WillRepeatedly(Invoke(
252 verifier(), &PasswordStoreDataVerifier::VerifyAdd));
253
254 EXPECT_CALL(*service(), NotifyPasswordStore());
255
256 service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
257 list,
258 ReleaseSyncChangeProcessor(),
259 scoped_ptr<syncer::SyncErrorFactory>());
260
261 EXPECT_EQ(0, verifier()->AddChangeCount());
262 }
263
264 // Sync has data that is not present in the password db.
265 TEST_F(PasswordSyncableServiceTest, AdditionOnlyInSync) {
266 std::vector<autofill::PasswordForm*> forms;
267
268 SyncData sync_data = CreateSyncData("def");
269 SyncDataList list;
270 list.push_back(sync_data);
271
272 verifier()->AddExpectedAddChange(sync_data);
273
274 SetPasswordStoreData(forms);
275
276 EXPECT_CALL(*password_store_, AddLoginImpl(_))
277 .WillRepeatedly(Invoke(
278 verifier(), &PasswordStoreDataVerifier::VerifyAdd));
279
280 EXPECT_CALL(*service(), NotifyPasswordStore());
281
282 service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
283 list,
284 ReleaseSyncChangeProcessor(),
285 scoped_ptr<syncer::SyncErrorFactory>());
286
287 EXPECT_EQ(0, verifier()->AddChangeCount());
288 }
289
290 // Passwords db has data that is not present in sync.
291 TEST_F(PasswordSyncableServiceTest, AdditionOnlyInPasswordStore) {
292 autofill::PasswordForm *form1 = new autofill::PasswordForm;
293 form1->signon_realm = "abc";
294
295 std::vector<autofill::PasswordForm*> forms;
296 forms.push_back(form1);
297
298 SyncDataList list;
299
300 sync_change_processor()->AddExpectedChange(*form1,
301 SyncChange::ACTION_ADD);
302
303 SetPasswordStoreData(forms);
304
305 service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
306 list,
307 ReleaseSyncChangeProcessor(),
308 scoped_ptr<syncer::SyncErrorFactory>());
309
310 EXPECT_EQ(0, verifier()->AddChangeCount());
311 }
312
313 // Both passwords db and sync contain the same data.
314 TEST_F(PasswordSyncableServiceTest, BothInSync) {
315 autofill::PasswordForm *form1 = new autofill::PasswordForm;
316 form1->signon_realm = "abc";
317
318 std::vector<autofill::PasswordForm*> forms;
319 forms.push_back(form1);
320
321 SyncData sync_data = CreateSyncData("abc");
322 SyncDataList list;
323 list.push_back(sync_data);
324
325 SetPasswordStoreData(forms);
326
327 service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
328 list,
329 ReleaseSyncChangeProcessor(),
330 scoped_ptr<syncer::SyncErrorFactory>());
331 EXPECT_EQ(0, verifier()->AddChangeCount());
332 EXPECT_EQ(0, verifier()->UpdateChangeCount());
333 }
334
335 // Both passwords db and sync have the same data but they need to be merged
336 // as some fields of the data differ.
337 TEST_F(PasswordSyncableServiceTest, Merge) {
338 autofill::PasswordForm *form1 = new autofill::PasswordForm;
339 form1->signon_realm = "abc";
340 form1->action = GURL("http://pie.com");
341
342 std::vector<autofill::PasswordForm*> forms;
343 forms.push_back(form1);
344
345 SyncData sync_data = CreateSyncData("abc");
346 SyncDataList list;
347 list.push_back(sync_data);
348
349 sync_change_processor()->AddExpectedChange(*form1,
350 SyncChange::ACTION_UPDATE);
351
352 verifier()->AddExpectedUpdateChange(*form1);
Ilya Sherman 2013/11/05 08:39:21 Why are both the local and the sync value expected
lipalani1 2013/11/19 00:46:54 In this case form1 wins. But in our production cod
353
354 SetPasswordStoreData(forms);
355
356 EXPECT_CALL(*password_store_, UpdateLoginImpl(_))
357 .WillRepeatedly(Invoke(verifier(),
358 &PasswordStoreDataVerifier::VerifyUpdate));
359
360 EXPECT_CALL(*service(), NotifyPasswordStore());
361
362 service()->MergeDataAndStartSyncing(syncer::PASSWORDS,
363 list,
364 ReleaseSyncChangeProcessor(),
365 scoped_ptr<syncer::SyncErrorFactory>());
366
367 EXPECT_EQ(0, verifier()->UpdateChangeCount());
368 }
Ilya Sherman 2013/11/05 08:39:21 Please also add test coverage to verify that *all*
lipalani1 2013/11/19 00:46:54 When verifying add/update we compare all fields. O
369
370 } // namespace
371
Ilya Sherman 2013/11/05 08:39:21 nit: Spurious newline.
lipalani1 2013/11/19 00:46:54 Done.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698