Update mojo surfaces bindings and mojo/cc/ glue
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_x_unittest.cc
blob60865aa1eabb8e90bad5bd586ada28d870d379d0
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
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/bind_helpers.h"
8 #include "base/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/password_manager/password_store_x.h"
18 #include "chrome/test/base/testing_browser_process.h"
19 #include "components/password_manager/core/browser/password_form_data.h"
20 #include "components/password_manager/core/browser/password_store_change.h"
21 #include "components/password_manager/core/browser/password_store_consumer.h"
22 #include "components/password_manager/core/common/password_manager_pref_names.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 using autofill::PasswordForm;
29 using content::BrowserThread;
30 using password_manager::ContainsAllPasswordForms;
31 using password_manager::PasswordStoreChange;
32 using password_manager::PasswordStoreChangeList;
33 using testing::_;
34 using testing::DoAll;
35 using testing::ElementsAreArray;
36 using testing::Pointee;
37 using testing::Property;
38 using testing::WithArg;
40 typedef std::vector<PasswordForm*> VectorOfForms;
42 namespace {
44 class MockPasswordStoreConsumer
45 : public password_manager::PasswordStoreConsumer {
46 public:
47 MOCK_METHOD1(OnGetPasswordStoreResults,
48 void(const std::vector<PasswordForm*>&));
51 class MockPasswordStoreObserver
52 : public password_manager::PasswordStore::Observer {
53 public:
54 MOCK_METHOD1(OnLoginsChanged,
55 void(const password_manager::PasswordStoreChangeList& changes));
58 class FailingBackend : public PasswordStoreX::NativeBackend {
59 public:
60 virtual bool Init() OVERRIDE { return true; }
62 virtual PasswordStoreChangeList AddLogin(const PasswordForm& form) OVERRIDE {
63 return PasswordStoreChangeList();
65 virtual bool UpdateLogin(const PasswordForm& form,
66 PasswordStoreChangeList* changes) OVERRIDE {
67 return false;
69 virtual bool RemoveLogin(const PasswordForm& form) OVERRIDE { return false; }
71 virtual bool RemoveLoginsCreatedBetween(
72 base::Time delete_begin,
73 base::Time delete_end,
74 password_manager::PasswordStoreChangeList* changes) OVERRIDE {
75 return false;
78 virtual bool RemoveLoginsSyncedBetween(
79 base::Time delete_begin,
80 base::Time delete_end,
81 password_manager::PasswordStoreChangeList* changes) OVERRIDE {
82 return false;
85 virtual bool GetLogins(const PasswordForm& form,
86 PasswordFormList* forms) OVERRIDE {
87 return false;
90 virtual bool GetAutofillableLogins(PasswordFormList* forms) OVERRIDE {
91 return false;
93 virtual bool GetBlacklistLogins(PasswordFormList* forms) OVERRIDE {
94 return false;
98 class MockBackend : public PasswordStoreX::NativeBackend {
99 public:
100 virtual bool Init() OVERRIDE { return true; }
102 virtual PasswordStoreChangeList AddLogin(const PasswordForm& form) OVERRIDE {
103 all_forms_.push_back(form);
104 PasswordStoreChange change(PasswordStoreChange::ADD, form);
105 return PasswordStoreChangeList(1, change);
108 virtual bool UpdateLogin(const PasswordForm& form,
109 PasswordStoreChangeList* changes) OVERRIDE {
110 for (size_t i = 0; i < all_forms_.size(); ++i)
111 if (CompareForms(all_forms_[i], form, true)) {
112 all_forms_[i] = form;
113 changes->push_back(PasswordStoreChange(PasswordStoreChange::UPDATE,
114 form));
116 return true;
119 virtual bool RemoveLogin(const PasswordForm& form) OVERRIDE {
120 for (size_t i = 0; i < all_forms_.size(); ++i)
121 if (CompareForms(all_forms_[i], form, false))
122 erase(i--);
123 return true;
126 virtual bool RemoveLoginsCreatedBetween(
127 base::Time delete_begin,
128 base::Time delete_end,
129 password_manager::PasswordStoreChangeList* changes) OVERRIDE {
130 for (size_t i = 0; i < all_forms_.size(); ++i) {
131 if (delete_begin <= all_forms_[i].date_created &&
132 (delete_end.is_null() || all_forms_[i].date_created < delete_end))
133 erase(i--);
135 return true;
138 virtual bool RemoveLoginsSyncedBetween(
139 base::Time delete_begin,
140 base::Time delete_end,
141 password_manager::PasswordStoreChangeList* changes) OVERRIDE {
142 DCHECK(changes);
143 for (size_t i = 0; i < all_forms_.size(); ++i) {
144 if (delete_begin <= all_forms_[i].date_synced &&
145 (delete_end.is_null() || all_forms_[i].date_synced < delete_end)) {
146 changes->push_back(password_manager::PasswordStoreChange(
147 password_manager::PasswordStoreChange::REMOVE, all_forms_[i]));
148 erase(i--);
151 return true;
154 virtual bool GetLogins(const PasswordForm& form,
155 PasswordFormList* forms) OVERRIDE {
156 for (size_t i = 0; i < all_forms_.size(); ++i)
157 if (all_forms_[i].signon_realm == form.signon_realm)
158 forms->push_back(new PasswordForm(all_forms_[i]));
159 return true;
162 virtual bool GetAutofillableLogins(PasswordFormList* forms) OVERRIDE {
163 for (size_t i = 0; i < all_forms_.size(); ++i)
164 if (!all_forms_[i].blacklisted_by_user)
165 forms->push_back(new PasswordForm(all_forms_[i]));
166 return true;
169 virtual bool GetBlacklistLogins(PasswordFormList* forms) OVERRIDE {
170 for (size_t i = 0; i < all_forms_.size(); ++i)
171 if (all_forms_[i].blacklisted_by_user)
172 forms->push_back(new PasswordForm(all_forms_[i]));
173 return true;
176 private:
177 void erase(size_t index) {
178 if (index < all_forms_.size() - 1)
179 all_forms_[index] = all_forms_[all_forms_.size() - 1];
180 all_forms_.pop_back();
183 bool CompareForms(const PasswordForm& a, const PasswordForm& b, bool update) {
184 // An update check doesn't care about the submit element.
185 if (!update && a.submit_element != b.submit_element)
186 return false;
187 return a.origin == b.origin &&
188 a.password_element == b.password_element &&
189 a.signon_realm == b.signon_realm &&
190 a.username_element == b.username_element &&
191 a.username_value == b.username_value;
194 std::vector<PasswordForm> all_forms_;
197 class MockLoginDatabaseReturn {
198 public:
199 MOCK_METHOD1(OnLoginDatabaseQueryDone,
200 void(const std::vector<PasswordForm*>&));
203 void LoginDatabaseQueryCallback(password_manager::LoginDatabase* login_db,
204 bool autofillable,
205 MockLoginDatabaseReturn* mock_return) {
206 std::vector<PasswordForm*> forms;
207 if (autofillable)
208 login_db->GetAutofillableLogins(&forms);
209 else
210 login_db->GetBlacklistLogins(&forms);
211 mock_return->OnLoginDatabaseQueryDone(forms);
214 // Generate |count| expected logins, either auto-fillable or blacklisted.
215 void InitExpectedForms(bool autofillable, size_t count, VectorOfForms* forms) {
216 const char* domain = autofillable ? "example" : "blacklisted";
217 for (size_t i = 0; i < count; ++i) {
218 std::string realm = base::StringPrintf("http://%zu.%s.com", i, domain);
219 std::string origin = base::StringPrintf("http://%zu.%s.com/origin",
220 i, domain);
221 std::string action = base::StringPrintf("http://%zu.%s.com/action",
222 i, domain);
223 password_manager::PasswordFormData data = {
224 PasswordForm::SCHEME_HTML,
225 realm.c_str(),
226 origin.c_str(),
227 action.c_str(),
228 L"submit_element",
229 L"username_element",
230 L"password_element",
231 autofillable ? L"username_value" : NULL,
232 autofillable ? L"password_value" : NULL,
233 autofillable,
234 false,
235 static_cast<double>(i + 1)};
236 forms->push_back(CreatePasswordFormFromData(data));
240 } // anonymous namespace
242 enum BackendType {
243 NO_BACKEND,
244 FAILING_BACKEND,
245 WORKING_BACKEND
248 class PasswordStoreXTest : public testing::TestWithParam<BackendType> {
249 protected:
250 virtual void SetUp() {
251 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
253 login_db_.reset(new password_manager::LoginDatabase());
254 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append("login_test")));
257 virtual void TearDown() {
258 base::RunLoop().RunUntilIdle();
261 PasswordStoreX::NativeBackend* GetBackend() {
262 switch (GetParam()) {
263 case FAILING_BACKEND:
264 return new FailingBackend();
265 case WORKING_BACKEND:
266 return new MockBackend();
267 default:
268 return NULL;
272 content::TestBrowserThreadBundle thread_bundle_;
274 scoped_ptr<password_manager::LoginDatabase> login_db_;
275 base::ScopedTempDir temp_dir_;
278 ACTION(STLDeleteElements0) {
279 STLDeleteContainerPointers(arg0.begin(), arg0.end());
282 TEST_P(PasswordStoreXTest, Notifications) {
283 scoped_refptr<PasswordStoreX> store(
284 new PasswordStoreX(base::MessageLoopProxy::current(),
285 base::MessageLoopProxy::current(),
286 login_db_.release(),
287 GetBackend()));
288 store->Init(syncer::SyncableService::StartSyncFlare(), "");
290 password_manager::PasswordFormData form_data = {
291 PasswordForm::SCHEME_HTML, "http://bar.example.com",
292 "http://bar.example.com/origin", "http://bar.example.com/action",
293 L"submit_element", L"username_element",
294 L"password_element", L"username_value",
295 L"password_value", true,
296 false, 1};
297 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
299 MockPasswordStoreObserver observer;
300 store->AddObserver(&observer);
302 const PasswordStoreChange expected_add_changes[] = {
303 PasswordStoreChange(PasswordStoreChange::ADD, *form),
306 EXPECT_CALL(
307 observer,
308 OnLoginsChanged(ElementsAreArray(expected_add_changes)));
310 // Adding a login should trigger a notification.
311 store->AddLogin(*form);
313 // The PasswordStore schedules tasks to run on the DB thread. Wait for them
314 // to complete.
315 base::RunLoop().RunUntilIdle();
317 // Change the password.
318 form->password_value = base::ASCIIToUTF16("a different password");
320 const PasswordStoreChange expected_update_changes[] = {
321 PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
324 EXPECT_CALL(
325 observer,
326 OnLoginsChanged(ElementsAreArray(expected_update_changes)));
328 // Updating the login with the new password should trigger a notification.
329 store->UpdateLogin(*form);
331 // Wait for PasswordStore to send execute.
332 base::RunLoop().RunUntilIdle();
334 const PasswordStoreChange expected_delete_changes[] = {
335 PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
338 EXPECT_CALL(
339 observer,
340 OnLoginsChanged(ElementsAreArray(expected_delete_changes)));
342 // Deleting the login should trigger a notification.
343 store->RemoveLogin(*form);
345 // Wait for PasswordStore to execute.
346 base::RunLoop().RunUntilIdle();
348 store->RemoveObserver(&observer);
350 store->Shutdown();
353 TEST_P(PasswordStoreXTest, NativeMigration) {
354 VectorOfForms expected_autofillable;
355 InitExpectedForms(true, 50, &expected_autofillable);
357 VectorOfForms expected_blacklisted;
358 InitExpectedForms(false, 50, &expected_blacklisted);
360 // Get the initial size of the login DB file, before we populate it.
361 // This will be used later to make sure it gets back to this size.
362 const base::FilePath login_db_file = temp_dir_.path().Append("login_test");
363 base::File::Info db_file_start_info;
364 ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_start_info));
366 password_manager::LoginDatabase* login_db = login_db_.get();
368 // Populate the login DB with logins that should be migrated.
369 for (VectorOfForms::iterator it = expected_autofillable.begin();
370 it != expected_autofillable.end(); ++it) {
371 login_db->AddLogin(**it);
373 for (VectorOfForms::iterator it = expected_blacklisted.begin();
374 it != expected_blacklisted.end(); ++it) {
375 login_db->AddLogin(**it);
378 // Get the new size of the login DB file. We expect it to be larger.
379 base::File::Info db_file_full_info;
380 ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_full_info));
381 EXPECT_GT(db_file_full_info.size, db_file_start_info.size);
383 // Initializing the PasswordStore shouldn't trigger a native migration (yet).
384 scoped_refptr<PasswordStoreX> store(
385 new PasswordStoreX(base::MessageLoopProxy::current(),
386 base::MessageLoopProxy::current(),
387 login_db_.release(),
388 GetBackend()));
389 store->Init(syncer::SyncableService::StartSyncFlare(), "");
391 MockPasswordStoreConsumer consumer;
393 // The autofillable forms should have been migrated to the native backend.
394 EXPECT_CALL(consumer,
395 OnGetPasswordStoreResults(
396 ContainsAllPasswordForms(expected_autofillable)))
397 .WillOnce(WithArg<0>(STLDeleteElements0()));
399 store->GetAutofillableLogins(&consumer);
400 base::RunLoop().RunUntilIdle();
402 // The blacklisted forms should have been migrated to the native backend.
403 EXPECT_CALL(consumer,
404 OnGetPasswordStoreResults(ContainsAllPasswordForms(expected_blacklisted)))
405 .WillOnce(WithArg<0>(STLDeleteElements0()));
407 store->GetBlacklistLogins(&consumer);
408 base::RunLoop().RunUntilIdle();
410 VectorOfForms empty;
411 MockLoginDatabaseReturn ld_return;
413 if (GetParam() == WORKING_BACKEND) {
414 // No autofillable logins should be left in the login DB.
415 EXPECT_CALL(ld_return,
416 OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty)));
417 } else {
418 // The autofillable logins should still be in the login DB.
419 EXPECT_CALL(ld_return,
420 OnLoginDatabaseQueryDone(
421 ContainsAllPasswordForms(expected_autofillable)))
422 .WillOnce(WithArg<0>(STLDeleteElements0()));
425 LoginDatabaseQueryCallback(login_db, true, &ld_return);
427 // Wait for the login DB methods to execute.
428 base::RunLoop().RunUntilIdle();
430 if (GetParam() == WORKING_BACKEND) {
431 // Likewise, no blacklisted logins should be left in the login DB.
432 EXPECT_CALL(ld_return,
433 OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty)));
434 } else {
435 // The blacklisted logins should still be in the login DB.
436 EXPECT_CALL(ld_return,
437 OnLoginDatabaseQueryDone(
438 ContainsAllPasswordForms(expected_blacklisted)))
439 .WillOnce(WithArg<0>(STLDeleteElements0()));
442 LoginDatabaseQueryCallback(login_db, false, &ld_return);
444 // Wait for the login DB methods to execute.
445 base::RunLoop().RunUntilIdle();
447 if (GetParam() == WORKING_BACKEND) {
448 // If the migration succeeded, then not only should there be no logins left
449 // in the login DB, but also the file should have been deleted and then
450 // recreated. We approximate checking for this by checking that the file
451 // size is equal to the size before we populated it, even though it was
452 // larger after populating it.
453 base::File::Info db_file_end_info;
454 ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_end_info));
455 EXPECT_EQ(db_file_start_info.size, db_file_end_info.size);
458 STLDeleteElements(&expected_autofillable);
459 STLDeleteElements(&expected_blacklisted);
461 store->Shutdown();
464 INSTANTIATE_TEST_CASE_P(NoBackend,
465 PasswordStoreXTest,
466 testing::Values(NO_BACKEND));
467 INSTANTIATE_TEST_CASE_P(FailingBackend,
468 PasswordStoreXTest,
469 testing::Values(FAILING_BACKEND));
470 INSTANTIATE_TEST_CASE_P(WorkingBackend,
471 PasswordStoreXTest,
472 testing::Values(WORKING_BACKEND));