password_store_x_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/platform_file.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/scoped_temp_dir.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/stl_util.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/string_util.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stringprintf.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/time.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/utf_string_conversions.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/password_manager/password_form_data.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/password_manager/password_store_change.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/password_manager/password_store_consumer.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/password_manager/password_store_x.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/prefs/pref_service.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_notification_types.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/pref_names.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/base/testing_browser_process.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/base/testing_profile.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_details.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_registrar.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_source.h"
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/test/mock_notification_observer.h"
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/test/test_browser_thread.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::WaitableEvent;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using testing::_;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using testing::DoAll;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using testing::ElementsAreArray;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using testing::Pointee;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using testing::Property;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using testing::WithArg;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::PasswordForm;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef std::vector<PasswordForm*> VectorOfForms;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockPasswordStoreConsumer : public PasswordStoreConsumer {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD2(OnPasswordStoreRequestDone,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               void(CancelableRequestProvider::Handle,
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    const std::vector<PasswordForm*>&));
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)};
54
55// This class will add and remove a mock notification observer from
56// the DB thread.
57class DBThreadObserverHelper
58    : public base::RefCountedThreadSafe<DBThreadObserverHelper,
59                                        BrowserThread::DeleteOnDBThread> {
60 public:
61  DBThreadObserverHelper() : done_event_(true, false) {}
62
63  void Init(PasswordStore* password_store) {
64    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65    BrowserThread::PostTask(
66        BrowserThread::DB,
67        FROM_HERE,
68        base::Bind(&DBThreadObserverHelper::AddObserverTask,
69                   this, make_scoped_refptr(password_store)));
70    done_event_.Wait();
71  }
72
73  content::MockNotificationObserver& observer() {
74    return observer_;
75  }
76
77 protected:
78  friend struct BrowserThread::DeleteOnThread<BrowserThread::DB>;
79  friend class base::DeleteHelper<DBThreadObserverHelper>;
80
81  virtual ~DBThreadObserverHelper() {
82    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
83    registrar_.RemoveAll();
84  }
85
86  void AddObserverTask(PasswordStore* password_store) {
87    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
88    registrar_.Add(&observer_,
89                   chrome::NOTIFICATION_LOGINS_CHANGED,
90                   content::Source<PasswordStore>(password_store));
91    done_event_.Signal();
92  }
93
94  WaitableEvent done_event_;
95  content::NotificationRegistrar registrar_;
96  content::MockNotificationObserver observer_;
97};
98
99class FailingBackend : public PasswordStoreX::NativeBackend {
100 public:
101  virtual bool Init() { return true; }
102
103  virtual bool AddLogin(const PasswordForm& form) { return false; }
104  virtual bool UpdateLogin(const PasswordForm& form) { return false; }
105  virtual bool RemoveLogin(const PasswordForm& form) { return false; }
106
107  virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin,
108                                          const base::Time& delete_end) {
109    return false;
110  }
111
112  virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) {
113    return false;
114  }
115
116  virtual bool GetLoginsCreatedBetween(const base::Time& get_begin,
117                                       const base::Time& get_end,
118                                       PasswordFormList* forms) {
119    return false;
120  }
121
122  virtual bool GetAutofillableLogins(PasswordFormList* forms) { return false; }
123  virtual bool GetBlacklistLogins(PasswordFormList* forms) { return false; }
124};
125
126class MockBackend : public PasswordStoreX::NativeBackend {
127 public:
128  virtual bool Init() { return true; }
129
130  virtual bool AddLogin(const PasswordForm& form) {
131    all_forms_.push_back(form);
132    return true;
133  }
134
135  virtual bool UpdateLogin(const PasswordForm& form) {
136    for (size_t i = 0; i < all_forms_.size(); ++i)
137      if (CompareForms(all_forms_[i], form, true))
138        all_forms_[i] = form;
139    return true;
140  }
141
142  virtual bool RemoveLogin(const PasswordForm& form) {
143    for (size_t i = 0; i < all_forms_.size(); ++i)
144      if (CompareForms(all_forms_[i], form, false))
145        erase(i--);
146    return true;
147  }
148
149  virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin,
150                                          const base::Time& delete_end) {
151    for (size_t i = 0; i < all_forms_.size(); ++i) {
152      if (delete_begin <= all_forms_[i].date_created &&
153          (delete_end.is_null() || all_forms_[i].date_created < delete_end))
154        erase(i--);
155    }
156    return true;
157  }
158
159  virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) {
160    for (size_t i = 0; i < all_forms_.size(); ++i)
161      if (all_forms_[i].signon_realm == form.signon_realm)
162        forms->push_back(new PasswordForm(all_forms_[i]));
163    return true;
164  }
165
166  virtual bool GetLoginsCreatedBetween(const base::Time& get_begin,
167                                       const base::Time& get_end,
168                                       PasswordFormList* forms) {
169    for (size_t i = 0; i < all_forms_.size(); ++i)
170      if (get_begin <= all_forms_[i].date_created &&
171          (get_end.is_null() || all_forms_[i].date_created < get_end))
172        forms->push_back(new PasswordForm(all_forms_[i]));
173    return true;
174  }
175
176  virtual bool GetAutofillableLogins(PasswordFormList* forms) {
177    for (size_t i = 0; i < all_forms_.size(); ++i)
178      if (!all_forms_[i].blacklisted_by_user)
179        forms->push_back(new PasswordForm(all_forms_[i]));
180    return true;
181  }
182
183  virtual bool GetBlacklistLogins(PasswordFormList* forms) {
184    for (size_t i = 0; i < all_forms_.size(); ++i)
185      if (all_forms_[i].blacklisted_by_user)
186        forms->push_back(new PasswordForm(all_forms_[i]));
187    return true;
188  }
189
190 private:
191  void erase(size_t index) {
192    if (index < all_forms_.size() - 1)
193      all_forms_[index] = all_forms_[all_forms_.size() - 1];
194    all_forms_.pop_back();
195  }
196
197  bool CompareForms(const PasswordForm& a, const PasswordForm& b, bool update) {
198    // An update check doesn't care about the submit element.
199    if (!update && a.submit_element != b.submit_element)
200      return false;
201    return a.origin           == b.origin &&
202           a.password_element == b.password_element &&
203           a.signon_realm     == b.signon_realm &&
204           a.username_element == b.username_element &&
205           a.username_value   == b.username_value;
206  }
207
208  std::vector<PasswordForm> all_forms_;
209};
210
211class MockLoginDatabaseReturn {
212 public:
213  MOCK_METHOD1(OnLoginDatabaseQueryDone,
214               void(const std::vector<PasswordForm*>&));
215};
216
217void LoginDatabaseQueryCallback(LoginDatabase* login_db,
218                                bool autofillable,
219                                MockLoginDatabaseReturn* mock_return) {
220  std::vector<PasswordForm*> forms;
221  if (autofillable)
222    login_db->GetAutofillableLogins(&forms);
223  else
224    login_db->GetBlacklistLogins(&forms);
225  mock_return->OnLoginDatabaseQueryDone(forms);
226}
227
228// Generate |count| expected logins, either auto-fillable or blacklisted.
229void InitExpectedForms(bool autofillable, size_t count, VectorOfForms* forms) {
230  const char* domain = autofillable ? "example" : "blacklisted";
231  for (size_t i = 0; i < count; ++i) {
232    std::string realm = base::StringPrintf("http://%zu.%s.com", i, domain);
233    std::string origin = base::StringPrintf("http://%zu.%s.com/origin",
234                                            i, domain);
235    std::string action = base::StringPrintf("http://%zu.%s.com/action",
236                                            i, domain);
237    PasswordFormData data = {
238      PasswordForm::SCHEME_HTML,
239      realm.c_str(),
240      origin.c_str(),
241      action.c_str(),
242      L"submit_element",
243      L"username_element",
244      L"password_element",
245      autofillable ? L"username_value" : NULL,
246      autofillable ? L"password_value" : NULL,
247      autofillable, false, i + 1 };
248    forms->push_back(CreatePasswordFormFromData(data));
249  }
250}
251
252}  // anonymous namespace
253
254enum BackendType {
255  NO_BACKEND,
256  FAILING_BACKEND,
257  WORKING_BACKEND
258};
259
260class PasswordStoreXTest : public testing::TestWithParam<BackendType> {
261 protected:
262  PasswordStoreXTest()
263      : ui_thread_(BrowserThread::UI, &message_loop_),
264        db_thread_(BrowserThread::DB) {
265  }
266
267  virtual void SetUp() {
268    ASSERT_TRUE(db_thread_.Start());
269    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
270
271    profile_.reset(new TestingProfile());
272
273    login_db_.reset(new LoginDatabase());
274    ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append("login_test")));
275  }
276
277  virtual void TearDown() {
278    MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
279    MessageLoop::current()->Run();
280    db_thread_.Stop();
281  }
282
283  PasswordStoreX::NativeBackend* GetBackend() {
284    switch (GetParam()) {
285      case FAILING_BACKEND:
286        return new FailingBackend();
287      case WORKING_BACKEND:
288        return new MockBackend();
289      default:
290        return NULL;
291    }
292  }
293
294  MessageLoopForUI message_loop_;
295  content::TestBrowserThread ui_thread_;
296  // PasswordStore, WDS schedule work on this thread.
297  content::TestBrowserThread db_thread_;
298
299  scoped_ptr<LoginDatabase> login_db_;
300  scoped_ptr<TestingProfile> profile_;
301  ScopedTempDir temp_dir_;
302};
303
304ACTION(STLDeleteElements0) {
305  STLDeleteContainerPointers(arg0.begin(), arg0.end());
306}
307
308ACTION(QuitUIMessageLoop) {
309  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
310  MessageLoop::current()->Quit();
311}
312
313TEST_P(PasswordStoreXTest, Notifications) {
314  scoped_refptr<PasswordStoreX> store(
315      new PasswordStoreX(login_db_.release(),
316                         profile_.get(),
317                         GetBackend()));
318  store->Init();
319
320  PasswordFormData form_data =
321  { PasswordForm::SCHEME_HTML,
322    "http://bar.example.com",
323    "http://bar.example.com/origin",
324    "http://bar.example.com/action",
325    L"submit_element",
326    L"username_element",
327    L"password_element",
328    L"username_value",
329    L"password_value",
330    true, false, 1 };
331  scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
332
333  scoped_refptr<DBThreadObserverHelper> helper = new DBThreadObserverHelper;
334  helper->Init(store);
335
336  const PasswordStoreChange expected_add_changes[] = {
337    PasswordStoreChange(PasswordStoreChange::ADD, *form),
338  };
339
340  EXPECT_CALL(helper->observer(),
341      Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
342              content::Source<PasswordStore>(store),
343              Property(&content::Details<const PasswordStoreChangeList>::ptr,
344                       Pointee(ElementsAreArray(
345                           expected_add_changes)))));
346
347  // Adding a login should trigger a notification.
348  store->AddLogin(*form);
349
350  // The PasswordStore schedules tasks to run on the DB thread so we schedule
351  // yet another task to notify us that it's safe to carry on with the test.
352  WaitableEvent done(false, false);
353  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
354      base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
355  done.Wait();
356
357  // Change the password.
358  form->password_value = WideToUTF16(L"a different password");
359
360  const PasswordStoreChange expected_update_changes[] = {
361    PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
362  };
363
364  EXPECT_CALL(helper->observer(),
365      Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
366              content::Source<PasswordStore>(store),
367              Property(&content::Details<const PasswordStoreChangeList>::ptr,
368                       Pointee(ElementsAreArray(
369                           expected_update_changes)))));
370
371  // Updating the login with the new password should trigger a notification.
372  store->UpdateLogin(*form);
373
374  // Wait for PasswordStore to send the notification.
375  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
376      base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
377  done.Wait();
378
379  const PasswordStoreChange expected_delete_changes[] = {
380    PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
381  };
382
383  EXPECT_CALL(helper->observer(),
384      Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
385              content::Source<PasswordStore>(store),
386              Property(&content::Details<const PasswordStoreChangeList>::ptr,
387                       Pointee(ElementsAreArray(
388                           expected_delete_changes)))));
389
390  // Deleting the login should trigger a notification.
391  store->RemoveLogin(*form);
392
393  // Wait for PasswordStore to send the notification.
394  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
395      base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
396  done.Wait();
397
398  // Public in PasswordStore, protected in PasswordStoreX.
399  static_cast<PasswordStore*>(store)->ShutdownOnUIThread();
400}
401
402TEST_P(PasswordStoreXTest, NativeMigration) {
403  VectorOfForms expected_autofillable;
404  InitExpectedForms(true, 50, &expected_autofillable);
405
406  VectorOfForms expected_blacklisted;
407  InitExpectedForms(false, 50, &expected_blacklisted);
408
409  // Get the initial size of the login DB file, before we populate it.
410  // This will be used later to make sure it gets back to this size.
411  const FilePath login_db_file = temp_dir_.path().Append("login_test");
412  base::PlatformFileInfo db_file_start_info;
413  ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_start_info));
414
415  LoginDatabase* login_db = login_db_.get();
416
417  // Populate the login DB with logins that should be migrated.
418  for (VectorOfForms::iterator it = expected_autofillable.begin();
419       it != expected_autofillable.end(); ++it) {
420    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
421                            base::Bind(
422                                base::IgnoreResult(&LoginDatabase::AddLogin),
423                                base::Unretained(login_db), **it));
424  }
425  for (VectorOfForms::iterator it = expected_blacklisted.begin();
426       it != expected_blacklisted.end(); ++it) {
427    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
428                            base::Bind(
429                                base::IgnoreResult(&LoginDatabase::AddLogin),
430                                base::Unretained(login_db), **it));
431  }
432
433  // Schedule another task on the DB thread to notify us that it's safe to
434  // carry on with the test.
435  WaitableEvent done(false, false);
436  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
437      base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
438  done.Wait();
439
440  // Get the new size of the login DB file. We expect it to be larger.
441  base::PlatformFileInfo db_file_full_info;
442  ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_full_info));
443  EXPECT_GT(db_file_full_info.size, db_file_start_info.size);
444
445  // Initializing the PasswordStore shouldn't trigger a native migration (yet).
446  scoped_refptr<PasswordStoreX> store(
447      new PasswordStoreX(login_db_.release(),
448                         profile_.get(),
449                         GetBackend()));
450  store->Init();
451
452  MockPasswordStoreConsumer consumer;
453
454  // Make sure we quit the MessageLoop even if the test fails.
455  ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
456      .WillByDefault(QuitUIMessageLoop());
457
458  // The autofillable forms should have been migrated to the native backend.
459  EXPECT_CALL(consumer,
460      OnPasswordStoreRequestDone(_,
461          ContainsAllPasswordForms(expected_autofillable)))
462      .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
463
464  store->GetAutofillableLogins(&consumer);
465  MessageLoop::current()->Run();
466
467  // The blacklisted forms should have been migrated to the native backend.
468  EXPECT_CALL(consumer,
469      OnPasswordStoreRequestDone(_,
470          ContainsAllPasswordForms(expected_blacklisted)))
471      .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
472
473  store->GetBlacklistLogins(&consumer);
474  MessageLoop::current()->Run();
475
476  VectorOfForms empty;
477  MockLoginDatabaseReturn ld_return;
478
479  if (GetParam() == WORKING_BACKEND) {
480    // No autofillable logins should be left in the login DB.
481    EXPECT_CALL(ld_return,
482                OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty)));
483  } else {
484    // The autofillable logins should still be in the login DB.
485    EXPECT_CALL(ld_return,
486                OnLoginDatabaseQueryDone(
487                    ContainsAllPasswordForms(expected_autofillable)))
488        .WillOnce(WithArg<0>(STLDeleteElements0()));
489  }
490
491  BrowserThread::PostTask(
492      BrowserThread::DB, FROM_HERE,
493      base::Bind(&LoginDatabaseQueryCallback, login_db, true, &ld_return));
494
495  // Wait for the login DB methods to execute on the DB thread.
496  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
497      base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
498  done.Wait();
499
500  if (GetParam() == WORKING_BACKEND) {
501    // Likewise, no blacklisted logins should be left in the login DB.
502    EXPECT_CALL(ld_return,
503                OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty)));
504  } else {
505    // The blacklisted logins should still be in the login DB.
506    EXPECT_CALL(ld_return,
507                OnLoginDatabaseQueryDone(
508                    ContainsAllPasswordForms(expected_blacklisted)))
509        .WillOnce(WithArg<0>(STLDeleteElements0()));
510  }
511
512  BrowserThread::PostTask(
513      BrowserThread::DB, FROM_HERE,
514      base::Bind(&LoginDatabaseQueryCallback, login_db, false, &ld_return));
515
516  // Wait for the login DB methods to execute on the DB thread.
517  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
518      base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
519  done.Wait();
520
521  if (GetParam() == WORKING_BACKEND) {
522    // If the migration succeeded, then not only should there be no logins left
523    // in the login DB, but also the file should have been deleted and then
524    // recreated. We approximate checking for this by checking that the file
525    // size is equal to the size before we populated it, even though it was
526    // larger after populating it.
527    base::PlatformFileInfo db_file_end_info;
528    ASSERT_TRUE(file_util::GetFileInfo(login_db_file, &db_file_end_info));
529    EXPECT_EQ(db_file_start_info.size, db_file_end_info.size);
530  }
531
532  STLDeleteElements(&expected_autofillable);
533  STLDeleteElements(&expected_blacklisted);
534
535  // Public in PasswordStore, protected in PasswordStoreX.
536  static_cast<PasswordStore*>(store)->ShutdownOnUIThread();
537}
538
539INSTANTIATE_TEST_CASE_P(NoBackend,
540                        PasswordStoreXTest,
541                        testing::Values(NO_BACKEND));
542INSTANTIATE_TEST_CASE_P(FailingBackend,
543                        PasswordStoreXTest,
544                        testing::Values(FAILING_BACKEND));
545INSTANTIATE_TEST_CASE_P(WorkingBackend,
546                        PasswordStoreXTest,
547                        testing::Values(WORKING_BACKEND));
548