Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_default_unittest.cc
blobf44f656f5162cef71e8e2ecb92ef42abebaa8c47
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/prefs/pref_service.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/password_manager/password_form_data.h"
16 #include "chrome/browser/password_manager/password_store_change.h"
17 #include "chrome/browser/password_manager/password_store_consumer.h"
18 #include "chrome/browser/password_manager/password_store_default.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_registrar.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/test/mock_notification_observer.h"
25 #include "content/public/test/test_browser_thread.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using autofill::PasswordForm;
30 using base::WaitableEvent;
31 using content::BrowserThread;
32 using testing::_;
33 using testing::DoAll;
34 using testing::ElementsAreArray;
35 using testing::Pointee;
36 using testing::Property;
37 using testing::WithArg;
39 namespace {
41 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
42 public:
43 MOCK_METHOD2(OnPasswordStoreRequestDone,
44 void(CancelableRequestProvider::Handle,
45 const std::vector<PasswordForm*>&));
46 MOCK_METHOD1(OnGetPasswordStoreResults,
47 void(const std::vector<PasswordForm*>&));
50 // This class will add and remove a mock notification observer from
51 // the DB thread.
52 class DBThreadObserverHelper
53 : public base::RefCountedThreadSafe<DBThreadObserverHelper,
54 BrowserThread::DeleteOnDBThread> {
55 public:
56 DBThreadObserverHelper() : done_event_(true, false) {}
58 void Init(PasswordStore* password_store) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
60 BrowserThread::PostTask(
61 BrowserThread::DB,
62 FROM_HERE,
63 base::Bind(&DBThreadObserverHelper::AddObserverTask,
64 this,
65 make_scoped_refptr(password_store)));
66 done_event_.Wait();
69 content::MockNotificationObserver& observer() {
70 return observer_;
73 protected:
74 friend struct BrowserThread::DeleteOnThread<BrowserThread::DB>;
75 friend class base::DeleteHelper<DBThreadObserverHelper>;
77 virtual ~DBThreadObserverHelper() {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
79 registrar_.RemoveAll();
82 void AddObserverTask(PasswordStore* password_store) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
84 registrar_.Add(&observer_,
85 chrome::NOTIFICATION_LOGINS_CHANGED,
86 content::Source<PasswordStore>(password_store));
87 done_event_.Signal();
90 WaitableEvent done_event_;
91 content::NotificationRegistrar registrar_;
92 content::MockNotificationObserver observer_;
95 } // anonymous namespace
97 class PasswordStoreDefaultTest : public testing::Test {
98 protected:
99 PasswordStoreDefaultTest()
100 : ui_thread_(BrowserThread::UI, &message_loop_),
101 db_thread_(BrowserThread::DB) {
104 virtual void SetUp() {
105 ASSERT_TRUE(db_thread_.Start());
107 profile_.reset(new TestingProfile());
109 login_db_.reset(new LoginDatabase());
110 ASSERT_TRUE(login_db_->Init(profile_->GetPath().Append(
111 FILE_PATH_LITERAL("login_test"))));
114 virtual void TearDown() {
115 base::MessageLoop::current()->PostTask(FROM_HERE,
116 base::MessageLoop::QuitClosure());
117 base::MessageLoop::current()->Run();
118 db_thread_.Stop();
121 base::MessageLoopForUI message_loop_;
122 content::TestBrowserThread ui_thread_;
123 // PasswordStore, WDS schedule work on this thread.
124 content::TestBrowserThread db_thread_;
126 scoped_ptr<LoginDatabase> login_db_;
127 scoped_ptr<TestingProfile> profile_;
130 ACTION(STLDeleteElements0) {
131 STLDeleteContainerPointers(arg0.begin(), arg0.end());
134 ACTION(QuitUIMessageLoop) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
136 base::MessageLoop::current()->Quit();
139 TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
140 scoped_refptr<PasswordStoreDefault> store(
141 new PasswordStoreDefault(login_db_.release(), profile_.get()));
142 store->Init();
144 // Some non-ASCII password form data.
145 static const PasswordFormData form_data[] = {
146 { PasswordForm::SCHEME_HTML,
147 "http://foo.example.com",
148 "http://foo.example.com/origin",
149 "http://foo.example.com/action",
150 L"มีสีสัน",
151 L"お元気ですか?",
152 L"盆栽",
153 L"أحب كرة",
154 L"£éä국수çà",
155 true, false, 1 },
158 // Build the expected forms vector and add the forms to the store.
159 std::vector<PasswordForm*> expected_forms;
160 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
161 PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
162 expected_forms.push_back(form);
163 store->AddLogin(*form);
166 // The PasswordStore schedules tasks to run on the DB thread so we schedule
167 // yet another task to notify us that it's safe to carry on with the test.
168 // The PasswordStore doesn't really understand that it's "done" once the tasks
169 // we posted above have completed, so there's no formal notification for that.
170 WaitableEvent done(false, false);
171 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
172 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
173 done.Wait();
175 MockPasswordStoreConsumer consumer;
177 // Make sure we quit the MessageLoop even if the test fails.
178 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
179 .WillByDefault(QuitUIMessageLoop());
181 // We expect to get the same data back, even though it's not all ASCII.
182 EXPECT_CALL(consumer,
183 OnPasswordStoreRequestDone(_,
184 ContainsAllPasswordForms(expected_forms)))
185 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
187 store->GetAutofillableLogins(&consumer);
188 base::MessageLoop::current()->Run();
190 STLDeleteElements(&expected_forms);
193 TEST_F(PasswordStoreDefaultTest, Notifications) {
194 scoped_refptr<PasswordStore> store(
195 new PasswordStoreDefault(login_db_.release(), profile_.get()));
196 store->Init();
198 PasswordFormData form_data =
199 { PasswordForm::SCHEME_HTML,
200 "http://bar.example.com",
201 "http://bar.example.com/origin",
202 "http://bar.example.com/action",
203 L"submit_element",
204 L"username_element",
205 L"password_element",
206 L"username_value",
207 L"password_value",
208 true, false, 1 };
209 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
211 scoped_refptr<DBThreadObserverHelper> helper = new DBThreadObserverHelper;
212 helper->Init(store.get());
214 const PasswordStoreChange expected_add_changes[] = {
215 PasswordStoreChange(PasswordStoreChange::ADD, *form),
218 EXPECT_CALL(
219 helper->observer(),
220 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
221 content::Source<PasswordStore>(store.get()),
222 Property(&content::Details<const PasswordStoreChangeList>::ptr,
223 Pointee(ElementsAreArray(expected_add_changes)))));
225 // Adding a login should trigger a notification.
226 store->AddLogin(*form);
228 // The PasswordStore schedules tasks to run on the DB thread so we schedule
229 // yet another task to notify us that it's safe to carry on with the test.
230 WaitableEvent done(false, false);
231 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
232 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
233 done.Wait();
235 // Change the password.
236 form->password_value = base::ASCIIToUTF16("a different password");
238 const PasswordStoreChange expected_update_changes[] = {
239 PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
242 EXPECT_CALL(
243 helper->observer(),
244 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
245 content::Source<PasswordStore>(store.get()),
246 Property(&content::Details<const PasswordStoreChangeList>::ptr,
247 Pointee(ElementsAreArray(expected_update_changes)))));
249 // Updating the login with the new password should trigger a notification.
250 store->UpdateLogin(*form);
252 // Wait for PasswordStore to send the notification.
253 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
254 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
255 done.Wait();
257 const PasswordStoreChange expected_delete_changes[] = {
258 PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
261 EXPECT_CALL(
262 helper->observer(),
263 Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
264 content::Source<PasswordStore>(store.get()),
265 Property(&content::Details<const PasswordStoreChangeList>::ptr,
266 Pointee(ElementsAreArray(expected_delete_changes)))));
268 // Deleting the login should trigger a notification.
269 store->RemoveLogin(*form);
271 // Wait for PasswordStore to send the notification.
272 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
273 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
274 done.Wait();
276 store->ShutdownOnUIThread();