OLD | NEW |
---|---|
(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 | |
OLD | NEW |