Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_win_unittest.cc
blob177c62cee3c3fc5cd5aa9928e5e948a22d278852
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 <windows.h>
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/stl_util.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/password_manager/password_store_win.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "components/os_crypt/ie7_password_win.h"
22 #include "components/password_manager/core/browser/password_manager_test_utils.h"
23 #include "components/password_manager/core/browser/password_store_consumer.h"
24 #include "components/password_manager/core/browser/webdata/logins_table.h"
25 #include "components/password_manager/core/browser/webdata/password_web_data_service_win.h"
26 #include "components/password_manager/core/common/password_manager_pref_names.h"
27 #include "components/webdata/common/web_database_service.h"
28 #include "content/public/test/test_browser_thread.h"
29 #include "crypto/wincrypt_shim.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 using autofill::PasswordForm;
34 using base::WaitableEvent;
35 using content::BrowserThread;
36 using password_manager::LoginDatabase;
37 using password_manager::PasswordFormData;
38 using password_manager::PasswordStore;
39 using password_manager::PasswordStoreConsumer;
40 using password_manager::UnorderedPasswordFormElementsAre;
41 using testing::_;
42 using testing::DoAll;
43 using testing::IsEmpty;
44 using testing::WithArg;
46 namespace {
48 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
49 public:
50 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
51 void(const std::vector<PasswordForm*>&));
53 // GMock cannot mock methods with move-only args.
54 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
55 OnGetPasswordStoreResultsConstRef(results.get());
59 class MockWebDataServiceConsumer : public WebDataServiceConsumer {
60 public:
61 MOCK_METHOD2(OnWebDataServiceRequestDone,
62 void(PasswordWebDataService::Handle, const WDTypedResult*));
65 } // anonymous namespace
67 class PasswordStoreWinTest : public testing::Test {
68 protected:
69 PasswordStoreWinTest()
70 : ui_thread_(BrowserThread::UI, &message_loop_),
71 db_thread_(BrowserThread::DB) {
74 bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created,
75 IE7PasswordInfo* info) {
76 // Copied from chrome/browser/importer/importer_unittest.cc
77 // The username is "abcdefgh" and the password "abcdefghijkl".
78 unsigned char data[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
79 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
80 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
81 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
82 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
83 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
84 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
85 "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
86 "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
87 "\x6c\x00\x00\x00";
88 DATA_BLOB input = {0};
89 DATA_BLOB url_key = {0};
90 DATA_BLOB output = {0};
92 input.pbData = data;
93 input.cbData = sizeof(data);
95 url_key.pbData = reinterpret_cast<unsigned char*>(
96 const_cast<wchar_t*>(url.data()));
97 url_key.cbData = static_cast<DWORD>((url.size() + 1) *
98 sizeof(std::wstring::value_type));
100 if (!CryptProtectData(&input, nullptr, &url_key, nullptr, nullptr,
101 CRYPTPROTECT_UI_FORBIDDEN, &output))
102 return false;
104 std::vector<unsigned char> encrypted_data;
105 encrypted_data.resize(output.cbData);
106 memcpy(&encrypted_data.front(), output.pbData, output.cbData);
108 LocalFree(output.pbData);
110 info->url_hash = ie7_password::GetUrlHash(url);
111 info->encrypted_data = encrypted_data;
112 info->date_created = created;
114 return true;
117 virtual void SetUp() {
118 ASSERT_TRUE(db_thread_.Start());
119 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
121 profile_.reset(new TestingProfile());
123 base::FilePath path = temp_dir_.path().AppendASCII("web_data_test");
124 wdbs_ = new WebDatabaseService(path,
125 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
126 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
127 // Need to add at least one table so the database gets created.
128 wdbs_->AddTable(scoped_ptr<WebDatabaseTable>(new LoginsTable()));
129 wdbs_->LoadDatabase();
130 wds_ = new PasswordWebDataService(
131 wdbs_,
132 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
133 WebDataServiceBase::ProfileErrorCallback());
134 wds_->Init();
137 virtual void TearDown() {
138 if (store_.get())
139 store_->Shutdown();
140 wds_->ShutdownOnUIThread();
141 wdbs_->ShutdownDatabase();
142 wds_ = nullptr;
143 wdbs_ = nullptr;
144 base::WaitableEvent done(false, false);
145 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
146 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
147 done.Wait();
148 base::MessageLoop::current()->PostTask(FROM_HERE,
149 base::MessageLoop::QuitClosure());
150 base::MessageLoop::current()->Run();
151 db_thread_.Stop();
154 base::FilePath test_login_db_file_path() const {
155 return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
158 PasswordStoreWin* CreatePasswordStore() {
159 return new PasswordStoreWin(
160 base::MessageLoopProxy::current(),
161 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
162 make_scoped_ptr(new LoginDatabase(test_login_db_file_path())),
163 wds_.get());
166 base::MessageLoopForUI message_loop_;
167 content::TestBrowserThread ui_thread_;
168 // PasswordStore, WDS schedule work on this thread.
169 content::TestBrowserThread db_thread_;
171 base::ScopedTempDir temp_dir_;
172 scoped_ptr<TestingProfile> profile_;
173 scoped_refptr<PasswordWebDataService> wds_;
174 scoped_refptr<WebDatabaseService> wdbs_;
175 scoped_refptr<PasswordStore> store_;
178 ACTION(STLDeleteElements0) {
179 STLDeleteContainerPointers(arg0.begin(), arg0.end());
182 ACTION(QuitUIMessageLoop) {
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
184 base::MessageLoop::current()->Quit();
187 MATCHER(EmptyWDResult, "") {
188 return static_cast<const WDResult<std::vector<PasswordForm*> >*>(
189 arg)->GetValue().empty();
192 // Hangs flakily, http://crbug.com/71385.
193 TEST_F(PasswordStoreWinTest, DISABLED_ConvertIE7Login) {
194 IE7PasswordInfo password_info;
195 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
196 base::Time::FromDoubleT(1),
197 &password_info));
198 // Verify the URL hash
199 ASSERT_EQ(L"39471418FF5453FEEB3731E382DEB5D53E14FAF9B5",
200 password_info.url_hash);
202 // This IE7 password will be retrieved by the GetLogins call.
203 wds_->AddIE7Login(password_info);
205 // The WDS schedules tasks to run on the DB thread so we schedule yet another
206 // task to notify us that it's safe to carry on with the test.
207 WaitableEvent done(false, false);
208 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
209 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
210 done.Wait();
212 store_ = CreatePasswordStore();
213 EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
215 MockPasswordStoreConsumer consumer;
217 // Make sure we quit the MessageLoop even if the test fails.
218 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
219 .WillByDefault(QuitUIMessageLoop());
221 PasswordFormData form_data = {
222 PasswordForm::SCHEME_HTML,
223 "http://example.com/",
224 "http://example.com/origin",
225 "http://example.com/action",
226 L"submit_element",
227 L"username_element",
228 L"password_element",
229 L"",
230 L"",
231 true, false, 1,
233 scoped_ptr<PasswordForm> form =
234 CreatePasswordFormFromDataForTesting(form_data);
236 // The returned form will not have 'action' or '*_element' fields set. This
237 // is because credentials imported from IE don't have this information.
238 PasswordFormData expected_form_data = {
239 PasswordForm::SCHEME_HTML,
240 "http://example.com/",
241 "http://example.com/origin",
243 L"",
244 L"",
245 L"",
246 L"abcdefgh",
247 L"abcdefghijkl",
248 true, false, 1,
250 ScopedVector<autofill::PasswordForm> expected_forms;
251 expected_forms.push_back(
252 CreatePasswordFormFromDataForTesting(expected_form_data));
254 // The IE7 password should be returned.
255 EXPECT_CALL(consumer,
256 OnGetPasswordStoreResultsConstRef(
257 UnorderedPasswordFormElementsAre(expected_forms.get())));
259 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
260 base::MessageLoop::current()->Run();
263 // Crashy. http://crbug.com/86558
264 TEST_F(PasswordStoreWinTest, DISABLED_OutstandingWDSQueries) {
265 store_ = CreatePasswordStore();
266 EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
268 PasswordFormData form_data = {
269 PasswordForm::SCHEME_HTML,
270 "http://example.com/",
271 "http://example.com/origin",
272 "http://example.com/action",
273 L"submit_element",
274 L"username_element",
275 L"password_element",
276 L"",
277 L"",
278 true, false, 1,
280 scoped_ptr<PasswordForm> form =
281 CreatePasswordFormFromDataForTesting(form_data);
283 MockPasswordStoreConsumer consumer;
284 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
286 // Release the PSW and the WDS before the query can return.
287 store_->Shutdown();
288 store_ = nullptr;
289 wds_ = nullptr;
291 base::MessageLoop::current()->RunUntilIdle();
294 // Hangs flakily, see http://crbug.com/43836.
295 TEST_F(PasswordStoreWinTest, DISABLED_MultipleWDSQueriesOnDifferentThreads) {
296 IE7PasswordInfo password_info;
297 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
298 base::Time::FromDoubleT(1),
299 &password_info));
300 wds_->AddIE7Login(password_info);
302 // The WDS schedules tasks to run on the DB thread so we schedule yet another
303 // task to notify us that it's safe to carry on with the test.
304 WaitableEvent done(false, false);
305 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
306 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
307 done.Wait();
309 store_ = CreatePasswordStore();
310 EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
312 MockPasswordStoreConsumer password_consumer;
313 // Make sure we quit the MessageLoop even if the test fails.
314 ON_CALL(password_consumer, OnGetPasswordStoreResultsConstRef(_))
315 .WillByDefault(QuitUIMessageLoop());
317 PasswordFormData form_data = {
318 PasswordForm::SCHEME_HTML,
319 "http://example.com/",
320 "http://example.com/origin",
321 "http://example.com/action",
322 L"submit_element",
323 L"username_element",
324 L"password_element",
325 L"",
326 L"",
327 true, false, 1,
329 scoped_ptr<PasswordForm> form =
330 CreatePasswordFormFromDataForTesting(form_data);
332 PasswordFormData expected_form_data = {
333 PasswordForm::SCHEME_HTML,
334 "http://example.com/",
335 "http://example.com/origin",
336 "http://example.com/action",
337 L"submit_element",
338 L"username_element",
339 L"password_element",
340 L"abcdefgh",
341 L"abcdefghijkl",
342 true, false, 1,
344 ScopedVector<autofill::PasswordForm> expected_forms;
345 expected_forms.push_back(
346 CreatePasswordFormFromDataForTesting(expected_form_data));
348 // The IE7 password should be returned.
349 EXPECT_CALL(password_consumer,
350 OnGetPasswordStoreResultsConstRef(
351 UnorderedPasswordFormElementsAre(expected_forms.get())));
353 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &password_consumer);
355 MockWebDataServiceConsumer wds_consumer;
357 EXPECT_CALL(wds_consumer, OnWebDataServiceRequestDone(_, _))
358 .WillOnce(QuitUIMessageLoop());
360 wds_->GetIE7Login(password_info, &wds_consumer);
362 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin
363 // schedules on the DB thread and once for the one we just scheduled on the UI
364 // thread.
365 base::MessageLoop::current()->Run();
366 base::MessageLoop::current()->Run();
369 TEST_F(PasswordStoreWinTest, EmptyLogins) {
370 store_ = CreatePasswordStore();
371 store_->Init(syncer::SyncableService::StartSyncFlare());
373 PasswordFormData form_data = {
374 PasswordForm::SCHEME_HTML,
375 "http://example.com/",
376 "http://example.com/origin",
377 "http://example.com/action",
378 L"submit_element",
379 L"username_element",
380 L"password_element",
381 L"",
382 L"",
383 true, false, 1,
385 scoped_ptr<PasswordForm> form =
386 CreatePasswordFormFromDataForTesting(form_data);
388 MockPasswordStoreConsumer consumer;
390 // Make sure we quit the MessageLoop even if the test fails.
391 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
392 .WillByDefault(QuitUIMessageLoop());
394 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
396 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
397 base::MessageLoop::current()->Run();
400 TEST_F(PasswordStoreWinTest, EmptyBlacklistLogins) {
401 store_ = CreatePasswordStore();
402 store_->Init(syncer::SyncableService::StartSyncFlare());
404 MockPasswordStoreConsumer consumer;
406 // Make sure we quit the MessageLoop even if the test fails.
407 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
408 .WillByDefault(QuitUIMessageLoop());
410 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
412 store_->GetBlacklistLogins(&consumer);
413 base::MessageLoop::current()->Run();
416 TEST_F(PasswordStoreWinTest, EmptyAutofillableLogins) {
417 store_ = CreatePasswordStore();
418 store_->Init(syncer::SyncableService::StartSyncFlare());
420 MockPasswordStoreConsumer consumer;
422 // Make sure we quit the MessageLoop even if the test fails.
423 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
424 .WillByDefault(QuitUIMessageLoop());
426 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
428 store_->GetAutofillableLogins(&consumer);
429 base::MessageLoop::current()->Run();