OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 "chrome/browser/password_manager/password_store_proxy_mac.h" |
| 6 |
| 7 #include "base/files/scoped_temp_dir.h" |
| 8 #include "base/scoped_observer.h" |
| 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "components/os_crypt/os_crypt.h" |
| 11 #include "components/password_manager/core/browser/login_database.h" |
| 12 #include "components/password_manager/core/browser/password_store_consumer.h" |
| 13 #include "content/public/browser/browser_thread.h" |
| 14 #include "content/public/test/test_browser_thread_bundle.h" |
| 15 #include "crypto/mock_apple_keychain.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 namespace { |
| 20 |
| 21 using autofill::PasswordForm; |
| 22 using content::BrowserThread; |
| 23 using testing::_; |
| 24 using testing::ElementsAre; |
| 25 using testing::Pointee; |
| 26 |
| 27 ACTION(QuitUIMessageLoop) { |
| 28 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 29 base::MessageLoop::current()->Quit(); |
| 30 } |
| 31 |
| 32 class MockPasswordStoreConsumer |
| 33 : public password_manager::PasswordStoreConsumer { |
| 34 public: |
| 35 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef, |
| 36 void(const std::vector<PasswordForm*>&)); |
| 37 |
| 38 // GMock cannot mock methods with move-only args. |
| 39 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override { |
| 40 OnGetPasswordStoreResultsConstRef(results.get()); |
| 41 } |
| 42 }; |
| 43 |
| 44 class MockPasswordStoreObserver |
| 45 : public password_manager::PasswordStore::Observer { |
| 46 public: |
| 47 MockPasswordStoreObserver(PasswordStoreProxyMac* password_store) |
| 48 : guard_(this) { |
| 49 guard_.Add(password_store); |
| 50 } |
| 51 MOCK_METHOD1(OnLoginsChanged, |
| 52 void(const password_manager::PasswordStoreChangeList& changes)); |
| 53 |
| 54 private: |
| 55 ScopedObserver<PasswordStoreProxyMac, MockPasswordStoreObserver> guard_; |
| 56 }; |
| 57 |
| 58 class PasswordStoreProxyMacTest : public testing::Test { |
| 59 public: |
| 60 void SetUp() override; |
| 61 void TearDown() override; |
| 62 |
| 63 void CreateAndInitPasswordStore( |
| 64 scoped_ptr<password_manager::LoginDatabase> login_db); |
| 65 |
| 66 void ClosePasswordStore(); |
| 67 |
| 68 // Do a store-level query to wait for all the previously enqueued operations |
| 69 // to finish. |
| 70 void FinishAsyncProcessing(); |
| 71 |
| 72 // Add/Update/Remove |form| and verify the operation succeeded. |
| 73 void AddForm(const PasswordForm& form); |
| 74 void UpdateForm(const PasswordForm& form); |
| 75 void RemoveForm(const PasswordForm& form); |
| 76 |
| 77 // Tests RemoveLoginsCreatedBetween or RemoveLoginsSyncedBetween depending on |
| 78 // |check_created|. |
| 79 void CheckRemoveLoginsBetween(bool check_created); |
| 80 |
| 81 base::FilePath test_login_db_file_path() const; |
| 82 |
| 83 password_manager::LoginDatabase* login_db() const { |
| 84 return store_->login_metadata_db(); |
| 85 } |
| 86 |
| 87 PasswordStoreProxyMac* store() { return store_.get(); } |
| 88 |
| 89 protected: |
| 90 content::TestBrowserThreadBundle ui_thread_; |
| 91 |
| 92 base::ScopedTempDir db_dir_; |
| 93 scoped_refptr<PasswordStoreProxyMac> store_; |
| 94 }; |
| 95 |
| 96 void PasswordStoreProxyMacTest::SetUp() { |
| 97 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); |
| 98 |
| 99 // Ensure that LoginDatabase will use the mock keychain if it needs to |
| 100 // encrypt/decrypt a password. |
| 101 OSCrypt::UseMockKeychain(true); |
| 102 scoped_ptr<password_manager::LoginDatabase> login_db( |
| 103 new password_manager::LoginDatabase(test_login_db_file_path())); |
| 104 CreateAndInitPasswordStore(login_db.Pass()); |
| 105 // Make sure deferred initialization is performed before some tests start |
| 106 // accessing the |login_db| directly. |
| 107 FinishAsyncProcessing(); |
| 108 } |
| 109 |
| 110 void PasswordStoreProxyMacTest::TearDown() { |
| 111 ClosePasswordStore(); |
| 112 } |
| 113 |
| 114 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore( |
| 115 scoped_ptr<password_manager::LoginDatabase> login_db) { |
| 116 store_ = new PasswordStoreProxyMac( |
| 117 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), |
| 118 make_scoped_ptr(new crypto::MockAppleKeychain), login_db.Pass()); |
| 119 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); |
| 120 } |
| 121 |
| 122 void PasswordStoreProxyMacTest::ClosePasswordStore() { |
| 123 store_->Shutdown(); |
| 124 EXPECT_FALSE(store_->GetBackgroundTaskRunner()); |
| 125 base::MessageLoop::current()->RunUntilIdle(); |
| 126 store_ = nullptr; |
| 127 } |
| 128 |
| 129 void PasswordStoreProxyMacTest::FinishAsyncProcessing() { |
| 130 // Do a store-level query to wait for all the previously enqueued operations |
| 131 // to finish. |
| 132 MockPasswordStoreConsumer consumer; |
| 133 store_->GetLogins(PasswordForm(), |
| 134 password_manager::PasswordStore::ALLOW_PROMPT, &consumer); |
| 135 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(_)) |
| 136 .WillOnce(QuitUIMessageLoop()); |
| 137 base::MessageLoop::current()->Run(); |
| 138 } |
| 139 |
| 140 base::FilePath PasswordStoreProxyMacTest::test_login_db_file_path() const { |
| 141 return db_dir_.path().Append(FILE_PATH_LITERAL("login.db")); |
| 142 } |
| 143 |
| 144 void PasswordStoreProxyMacTest::AddForm(const PasswordForm& form) { |
| 145 MockPasswordStoreObserver mock_observer(store()); |
| 146 |
| 147 password_manager::PasswordStoreChangeList list; |
| 148 list.push_back(password_manager::PasswordStoreChange( |
| 149 password_manager::PasswordStoreChange::ADD, form)); |
| 150 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 151 store()->AddLogin(form); |
| 152 FinishAsyncProcessing(); |
| 153 } |
| 154 |
| 155 void PasswordStoreProxyMacTest::UpdateForm(const PasswordForm& form) { |
| 156 MockPasswordStoreObserver mock_observer(store()); |
| 157 |
| 158 password_manager::PasswordStoreChangeList list; |
| 159 list.push_back(password_manager::PasswordStoreChange( |
| 160 password_manager::PasswordStoreChange::UPDATE, form)); |
| 161 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 162 store()->UpdateLogin(form); |
| 163 FinishAsyncProcessing(); |
| 164 } |
| 165 |
| 166 void PasswordStoreProxyMacTest::RemoveForm(const PasswordForm& form) { |
| 167 MockPasswordStoreObserver mock_observer(store()); |
| 168 |
| 169 password_manager::PasswordStoreChangeList list; |
| 170 list.push_back(password_manager::PasswordStoreChange( |
| 171 password_manager::PasswordStoreChange::REMOVE, form)); |
| 172 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 173 store()->RemoveLogin(form); |
| 174 FinishAsyncProcessing(); |
| 175 } |
| 176 |
| 177 void PasswordStoreProxyMacTest::CheckRemoveLoginsBetween(bool check_created) { |
| 178 PasswordForm old_form; |
| 179 old_form.origin = GURL("http://accounts.google.com/LoginAuth"); |
| 180 old_form.signon_realm = "http://accounts.google.com/"; |
| 181 old_form.username_value = base::ASCIIToUTF16("my_username"); |
| 182 old_form.federation_url = GURL("http://accounts.google.com/federation"); |
| 183 |
| 184 PasswordForm new_form = old_form; |
| 185 new_form.origin = GURL("http://accounts.google2.com/LoginAuth"); |
| 186 new_form.signon_realm = "http://accounts.google2.com/"; |
| 187 |
| 188 base::Time now = base::Time::Now(); |
| 189 base::Time next_day = now + base::TimeDelta::FromDays(1); |
| 190 if (check_created) { |
| 191 old_form.date_created = now; |
| 192 new_form.date_created = next_day; |
| 193 } else { |
| 194 old_form.date_synced = now; |
| 195 new_form.date_synced = next_day; |
| 196 } |
| 197 |
| 198 AddForm(old_form); |
| 199 AddForm(new_form); |
| 200 |
| 201 MockPasswordStoreObserver mock_observer(store()); |
| 202 password_manager::PasswordStoreChangeList list; |
| 203 list.push_back(password_manager::PasswordStoreChange( |
| 204 password_manager::PasswordStoreChange::REMOVE, old_form)); |
| 205 EXPECT_CALL(mock_observer, OnLoginsChanged(list)); |
| 206 if (check_created) |
| 207 store()->RemoveLoginsCreatedBetween(base::Time(), next_day); |
| 208 else |
| 209 store()->RemoveLoginsSyncedBetween(base::Time(), next_day); |
| 210 FinishAsyncProcessing(); |
| 211 } |
| 212 |
| 213 TEST_F(PasswordStoreProxyMacTest, FormLifeCycle) { |
| 214 PasswordForm password_form; |
| 215 password_form.origin = GURL("http://example.com"); |
| 216 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com"); |
| 217 password_form.password_value = base::ASCIIToUTF16("12345"); |
| 218 password_form.signon_realm = "http://example.com/"; |
| 219 |
| 220 AddForm(password_form); |
| 221 password_form.password_value = base::ASCIIToUTF16("password"); |
| 222 UpdateForm(password_form); |
| 223 RemoveForm(password_form); |
| 224 } |
| 225 |
| 226 TEST_F(PasswordStoreProxyMacTest, TestRemoveLoginsCreatedBetween) { |
| 227 CheckRemoveLoginsBetween(true); |
| 228 } |
| 229 |
| 230 TEST_F(PasswordStoreProxyMacTest, TestRemoveLoginsSyncedBetween) { |
| 231 CheckRemoveLoginsBetween(false); |
| 232 } |
| 233 |
| 234 TEST_F(PasswordStoreProxyMacTest, FillLogins) { |
| 235 PasswordForm password_form; |
| 236 password_form.origin = GURL("http://example.com"); |
| 237 password_form.signon_realm = "http://example.com/"; |
| 238 password_form.username_value = base::ASCIIToUTF16("test1@gmail.com"); |
| 239 password_form.password_value = base::ASCIIToUTF16("12345"); |
| 240 AddForm(password_form); |
| 241 |
| 242 PasswordForm blacklisted_form; |
| 243 blacklisted_form.origin = GURL("http://example2.com"); |
| 244 blacklisted_form.signon_realm = "http://example2.com/"; |
| 245 blacklisted_form.blacklisted_by_user = true; |
| 246 AddForm(blacklisted_form); |
| 247 |
| 248 MockPasswordStoreConsumer mock_consumer; |
| 249 store()->GetLogins(password_form, PasswordStoreProxyMac::ALLOW_PROMPT, |
| 250 &mock_consumer); |
| 251 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef( |
| 252 ElementsAre(Pointee(password_form)))) |
| 253 .WillOnce(QuitUIMessageLoop()); |
| 254 base::MessageLoop::current()->Run(); |
| 255 |
| 256 store()->GetBlacklistLogins(&mock_consumer); |
| 257 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef( |
| 258 ElementsAre(Pointee(blacklisted_form)))) |
| 259 .WillOnce(QuitUIMessageLoop()); |
| 260 base::MessageLoop::current()->Run(); |
| 261 |
| 262 store()->GetAutofillableLogins(&mock_consumer); |
| 263 EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef( |
| 264 ElementsAre(Pointee(password_form)))) |
| 265 .WillOnce(QuitUIMessageLoop()); |
| 266 base::MessageLoop::current()->Run(); |
| 267 } |
| 268 |
| 269 } // namespace |
OLD | NEW |