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

Side by Side Diff: chrome/browser/password_manager/password_store_proxy_mac_unittest.cc

Issue 2931863002: Rename PasswordStoreProxyMac to PasswordStoreMac. (Closed)
Patch Set: Created 3 years, 6 months 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
« no previous file with comments | « chrome/browser/password_manager/password_store_proxy_mac.cc ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 <utility>
8
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/macros.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/run_loop.h"
13 #include "base/scoped_observer.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/histogram_tester.h"
16 #include "chrome/browser/prefs/browser_prefs.h"
17 #include "components/os_crypt/os_crypt_mocker.h"
18 #include "components/password_manager/core/browser/login_database.h"
19 #include "components/password_manager/core/browser/password_manager_test_utils.h "
20 #include "components/password_manager/core/browser/password_store_consumer.h"
21 #include "components/password_manager/core/common/password_manager_pref_names.h"
22 #include "components/sync_preferences/testing_pref_service_syncable.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"
27
28 namespace {
29
30 using autofill::PasswordForm;
31 using content::BrowserThread;
32 using password_manager::MigrationStatus;
33 using password_manager::PasswordStore;
34 using password_manager::PasswordStoreChange;
35 using password_manager::PasswordStoreChangeList;
36 using testing::_;
37 using testing::ElementsAre;
38 using testing::IsEmpty;
39 using testing::Pointee;
40
41 class MockPasswordStoreConsumer
42 : public password_manager::PasswordStoreConsumer {
43 public:
44 MockPasswordStoreConsumer() = default;
45
46 void WaitForResult() {
47 base::RunLoop run_loop;
48 nested_loop_ = &run_loop;
49 run_loop.Run();
50 nested_loop_ = nullptr;
51 }
52
53 const std::vector<std::unique_ptr<PasswordForm>>& forms() const {
54 return forms_;
55 }
56
57 private:
58 void OnGetPasswordStoreResults(
59 std::vector<std::unique_ptr<PasswordForm>> results) override {
60 forms_.swap(results);
61 if (nested_loop_)
62 nested_loop_->Quit();
63 }
64
65 std::vector<std::unique_ptr<PasswordForm>> forms_;
66 base::RunLoop* nested_loop_ = nullptr;
67
68 DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreConsumer);
69 };
70
71 class MockPasswordStoreObserver
72 : public password_manager::PasswordStore::Observer {
73 public:
74 explicit MockPasswordStoreObserver(PasswordStoreProxyMac* password_store)
75 : guard_(this) {
76 guard_.Add(password_store);
77 }
78 MOCK_METHOD1(OnLoginsChanged,
79 void(const password_manager::PasswordStoreChangeList& changes));
80
81 private:
82 ScopedObserver<PasswordStoreProxyMac, MockPasswordStoreObserver> guard_;
83
84 DISALLOW_COPY_AND_ASSIGN(MockPasswordStoreObserver);
85 };
86
87 // A mock LoginDatabase that simulates a failing Init() method.
88 class BadLoginDatabase : public password_manager::LoginDatabase {
89 public:
90 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {}
91 ~BadLoginDatabase() override {}
92
93 // LoginDatabase:
94 bool Init() override { return false; }
95
96 private:
97 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase);
98 };
99
100 class PasswordStoreProxyMacTest
101 : public testing::TestWithParam<MigrationStatus> {
102 public:
103 PasswordStoreProxyMacTest();
104 ~PasswordStoreProxyMacTest() override;
105
106 void CreateAndInitPasswordStore(
107 std::unique_ptr<password_manager::LoginDatabase> login_db);
108
109 void ClosePasswordStore();
110
111 // Do a store-level query to wait for all the previously enqueued operations
112 // to finish.
113 void FinishAsyncProcessing();
114
115 // Add/Update/Remove |form| and verify the operation succeeded.
116 void AddForm(const PasswordForm& form);
117 void UpdateForm(const PasswordForm& form);
118 void RemoveForm(const PasswordForm& form);
119
120 base::FilePath test_login_db_file_path() const;
121
122 // Returns the expected migration status after the password store was inited.
123 MigrationStatus GetTargetStatus() const;
124
125 password_manager::LoginDatabase* login_db() const {
126 return store_->login_metadata_db();
127 }
128
129 PasswordStoreProxyMac* store() { return store_.get(); }
130
131 protected:
132 content::TestBrowserThreadBundle ui_thread_;
133
134 base::ScopedTempDir db_dir_;
135 scoped_refptr<PasswordStoreProxyMac> store_;
136 sync_preferences::TestingPrefServiceSyncable testing_prefs_;
137 };
138
139 PasswordStoreProxyMacTest::PasswordStoreProxyMacTest() {
140 EXPECT_TRUE(db_dir_.CreateUniqueTempDir());
141 chrome::RegisterUserProfilePrefs(testing_prefs_.registry());
142 testing_prefs_.SetInteger(password_manager::prefs::kKeychainMigrationStatus,
143 static_cast<int>(GetParam()));
144 // Ensure that LoginDatabase will use the mock keychain if it needs to
145 // encrypt/decrypt a password.
146 OSCryptMocker::SetUpWithSingleton();
147 }
148
149 PasswordStoreProxyMacTest::~PasswordStoreProxyMacTest() {
150 ClosePasswordStore();
151 OSCryptMocker::TearDown();
152 }
153
154 void PasswordStoreProxyMacTest::CreateAndInitPasswordStore(
155 std::unique_ptr<password_manager::LoginDatabase> login_db) {
156 store_ = new PasswordStoreProxyMac(
157 BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
158 std::move(login_db), &testing_prefs_);
159 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr));
160 }
161
162 void PasswordStoreProxyMacTest::ClosePasswordStore() {
163 if (!store_)
164 return;
165 store_->ShutdownOnUIThread();
166 EXPECT_FALSE(store_->GetBackgroundTaskRunner());
167 store_ = nullptr;
168 }
169
170 void PasswordStoreProxyMacTest::FinishAsyncProcessing() {
171 // Do a store-level query to wait for all the previously enqueued operations
172 // to finish.
173 MockPasswordStoreConsumer consumer;
174 store_->GetLogins({PasswordForm::SCHEME_HTML, std::string(), GURL()},
175 &consumer);
176 consumer.WaitForResult();
177 }
178
179 base::FilePath PasswordStoreProxyMacTest::test_login_db_file_path() const {
180 return db_dir_.GetPath().Append(FILE_PATH_LITERAL("login.db"));
181 }
182
183 MigrationStatus PasswordStoreProxyMacTest::GetTargetStatus() const {
184 if (GetParam() == MigrationStatus::NOT_STARTED ||
185 GetParam() == MigrationStatus::FAILED_ONCE ||
186 GetParam() == MigrationStatus::FAILED_TWICE) {
187 return MigrationStatus::MIGRATION_STOPPED;
188 }
189 return GetParam();
190 }
191
192 void PasswordStoreProxyMacTest::AddForm(const PasswordForm& form) {
193 MockPasswordStoreObserver mock_observer(store());
194
195 password_manager::PasswordStoreChangeList list;
196 list.push_back(password_manager::PasswordStoreChange(
197 password_manager::PasswordStoreChange::ADD, form));
198 EXPECT_CALL(mock_observer, OnLoginsChanged(list));
199 store()->AddLogin(form);
200 FinishAsyncProcessing();
201 }
202
203 void PasswordStoreProxyMacTest::UpdateForm(const PasswordForm& form) {
204 MockPasswordStoreObserver mock_observer(store());
205
206 password_manager::PasswordStoreChangeList list;
207 list.push_back(password_manager::PasswordStoreChange(
208 password_manager::PasswordStoreChange::UPDATE, form));
209 EXPECT_CALL(mock_observer, OnLoginsChanged(list));
210 store()->UpdateLogin(form);
211 FinishAsyncProcessing();
212 }
213
214 void PasswordStoreProxyMacTest::RemoveForm(const PasswordForm& form) {
215 MockPasswordStoreObserver mock_observer(store());
216
217 password_manager::PasswordStoreChangeList list;
218 list.push_back(password_manager::PasswordStoreChange(
219 password_manager::PasswordStoreChange::REMOVE, form));
220 EXPECT_CALL(mock_observer, OnLoginsChanged(list));
221 store()->RemoveLogin(form);
222 FinishAsyncProcessing();
223 }
224
225 // ----------- Tests -------------
226
227 TEST_P(PasswordStoreProxyMacTest, Sanity) {
228 base::HistogramTester histogram_tester;
229
230 CreateAndInitPasswordStore(base::MakeUnique<password_manager::LoginDatabase>(
231 test_login_db_file_path()));
232 FinishAsyncProcessing();
233 ClosePasswordStore();
234
235 int status = testing_prefs_.GetInteger(
236 password_manager::prefs::kKeychainMigrationStatus);
237 EXPECT_EQ(static_cast<int>(GetTargetStatus()), status);
238 histogram_tester.ExpectUniqueSample(
239 "PasswordManager.KeychainMigration.Status", status, 1);
240 }
241
242 TEST_P(PasswordStoreProxyMacTest, StartAndStop) {
243 base::HistogramTester histogram_tester;
244 // PasswordStore::ShutdownOnUIThread() immediately follows
245 // PasswordStore::Init(). The message loop isn't running in between. Anyway,
246 // PasswordStore should not collapse.
247 CreateAndInitPasswordStore(base::MakeUnique<password_manager::LoginDatabase>(
248 test_login_db_file_path()));
249 ClosePasswordStore();
250
251 histogram_tester.ExpectUniqueSample(
252 "PasswordManager.KeychainMigration.Status",
253 static_cast<int>(GetTargetStatus()), 1);
254 }
255
256 TEST_P(PasswordStoreProxyMacTest, OperationsOnABadDatabaseSilentlyFail) {
257 // Verify that operations on a PasswordStore with a bad database cause no
258 // explosions, but fail without side effect, return no data and trigger no
259 // notifications.
260 CreateAndInitPasswordStore(base::MakeUnique<BadLoginDatabase>());
261 FinishAsyncProcessing();
262 EXPECT_FALSE(login_db());
263
264 // The store should outlive the observer.
265 scoped_refptr<PasswordStoreProxyMac> store_refptr = store();
266 MockPasswordStoreObserver mock_observer(store());
267 EXPECT_CALL(mock_observer, OnLoginsChanged(_)).Times(0);
268
269 // Add a new autofillable login + a blacklisted login.
270 password_manager::PasswordFormData www_form_data = {
271 PasswordForm::SCHEME_HTML,
272 "http://www.facebook.com/",
273 "http://www.facebook.com/index.html",
274 "login",
275 L"username",
276 L"password",
277 L"submit",
278 L"not_joe_user",
279 L"12345",
280 true,
281 1};
282 std::unique_ptr<PasswordForm> form =
283 CreatePasswordFormFromDataForTesting(www_form_data);
284 std::unique_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
285 blacklisted_form->signon_realm = "http://foo.example.com";
286 blacklisted_form->origin = GURL("http://foo.example.com/origin");
287 blacklisted_form->action = GURL("http://foo.example.com/action");
288 blacklisted_form->blacklisted_by_user = true;
289 store()->AddLogin(*form);
290 store()->AddLogin(*blacklisted_form);
291 FinishAsyncProcessing();
292
293 // Get all logins; autofillable logins; blacklisted logins.
294 MockPasswordStoreConsumer mock_consumer;
295 store()->GetLogins(PasswordStore::FormDigest(*form), &mock_consumer);
296 mock_consumer.WaitForResult();
297 EXPECT_THAT(mock_consumer.forms(), IsEmpty());
298
299 store()->GetAutofillableLogins(&mock_consumer);
300 mock_consumer.WaitForResult();
301 EXPECT_THAT(mock_consumer.forms(), IsEmpty());
302
303 store()->GetBlacklistLogins(&mock_consumer);
304 mock_consumer.WaitForResult();
305 EXPECT_THAT(mock_consumer.forms(), IsEmpty());
306
307 // Report metrics.
308 store()->ReportMetrics("Test Username", true);
309 FinishAsyncProcessing();
310
311 // Change the login.
312 form->password_value = base::ASCIIToUTF16("a different password");
313 store()->UpdateLogin(*form);
314 FinishAsyncProcessing();
315
316 // Delete one login; a range of logins.
317 store()->RemoveLogin(*form);
318 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
319 base::Closure());
320 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
321 FinishAsyncProcessing();
322
323 // Verify no notifications are fired during shutdown either.
324 ClosePasswordStore();
325 }
326
327 INSTANTIATE_TEST_CASE_P(,
328 PasswordStoreProxyMacTest,
329 testing::Values(MigrationStatus::NOT_STARTED,
330 MigrationStatus::MIGRATED,
331 MigrationStatus::FAILED_ONCE,
332 MigrationStatus::FAILED_TWICE,
333 MigrationStatus::MIGRATED_DELETED,
334 MigrationStatus::MIGRATED_PARTIALLY,
335 MigrationStatus::MIGRATION_STOPPED));
336
337 } // namespace
OLDNEW
« no previous file with comments | « chrome/browser/password_manager/password_store_proxy_mac.cc ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698