Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / password_store_default_unittest.cc
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.
4
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"
28
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;
38
39 namespace {
40
41 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
42  public:
43   MOCK_METHOD1(OnGetPasswordStoreResults,
44                void(const std::vector<PasswordForm*>&));
45 };
46
47 // This class will add and remove a mock notification observer from
48 // the DB thread.
49 class DBThreadObserverHelper
50     : public base::RefCountedThreadSafe<DBThreadObserverHelper,
51                                         BrowserThread::DeleteOnDBThread> {
52  public:
53   DBThreadObserverHelper() : done_event_(true, false) {}
54
55   void Init(PasswordStore* password_store) {
56     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
57     BrowserThread::PostTask(
58         BrowserThread::DB,
59         FROM_HERE,
60         base::Bind(&DBThreadObserverHelper::AddObserverTask,
61                    this,
62                    make_scoped_refptr(password_store)));
63     done_event_.Wait();
64   }
65
66   content::MockNotificationObserver& observer() {
67     return observer_;
68   }
69
70  protected:
71   friend struct BrowserThread::DeleteOnThread<BrowserThread::DB>;
72   friend class base::DeleteHelper<DBThreadObserverHelper>;
73
74   virtual ~DBThreadObserverHelper() {
75     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
76     registrar_.RemoveAll();
77   }
78
79   void AddObserverTask(PasswordStore* password_store) {
80     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
81     registrar_.Add(&observer_,
82                    chrome::NOTIFICATION_LOGINS_CHANGED,
83                    content::Source<PasswordStore>(password_store));
84     done_event_.Signal();
85   }
86
87   WaitableEvent done_event_;
88   content::NotificationRegistrar registrar_;
89   content::MockNotificationObserver observer_;
90 };
91
92 }  // anonymous namespace
93
94 class PasswordStoreDefaultTest : public testing::Test {
95  protected:
96   PasswordStoreDefaultTest()
97       : ui_thread_(BrowserThread::UI, &message_loop_),
98         db_thread_(BrowserThread::DB) {
99   }
100
101   virtual void SetUp() {
102     ASSERT_TRUE(db_thread_.Start());
103
104     profile_.reset(new TestingProfile());
105
106     login_db_.reset(new LoginDatabase());
107     ASSERT_TRUE(login_db_->Init(profile_->GetPath().Append(
108         FILE_PATH_LITERAL("login_test"))));
109   }
110
111   virtual void TearDown() {
112     base::MessageLoop::current()->PostTask(FROM_HERE,
113                                            base::MessageLoop::QuitClosure());
114     base::MessageLoop::current()->Run();
115     db_thread_.Stop();
116   }
117
118   base::MessageLoopForUI message_loop_;
119   content::TestBrowserThread ui_thread_;
120   // PasswordStore, WDS schedule work on this thread.
121   content::TestBrowserThread db_thread_;
122
123   scoped_ptr<LoginDatabase> login_db_;
124   scoped_ptr<TestingProfile> profile_;
125 };
126
127 ACTION(STLDeleteElements0) {
128   STLDeleteContainerPointers(arg0.begin(), arg0.end());
129 }
130
131 ACTION(QuitUIMessageLoop) {
132   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133   base::MessageLoop::current()->Quit();
134 }
135
136 TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
137   scoped_refptr<PasswordStoreDefault> store(
138       new PasswordStoreDefault(login_db_.release(), profile_.get()));
139   store->Init();
140
141   // Some non-ASCII password form data.
142   static const PasswordFormData form_data[] = {
143     { PasswordForm::SCHEME_HTML,
144       "http://foo.example.com",
145       "http://foo.example.com/origin",
146       "http://foo.example.com/action",
147       L"มีสีสัน",
148       L"お元気ですか?",
149       L"盆栽",
150       L"أحب كرة",
151       L"£éä국수çà",
152       true, false, 1 },
153   };
154
155   // Build the expected forms vector and add the forms to the store.
156   std::vector<PasswordForm*> expected_forms;
157   for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
158     PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
159     expected_forms.push_back(form);
160     store->AddLogin(*form);
161   }
162
163   // The PasswordStore schedules tasks to run on the DB thread so we schedule
164   // yet another task to notify us that it's safe to carry on with the test.
165   // The PasswordStore doesn't really understand that it's "done" once the tasks
166   // we posted above have completed, so there's no formal notification for that.
167   WaitableEvent done(false, false);
168   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
169       base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
170   done.Wait();
171
172   MockPasswordStoreConsumer consumer;
173
174   // Make sure we quit the MessageLoop even if the test fails.
175   ON_CALL(consumer, OnGetPasswordStoreResults(_))
176       .WillByDefault(QuitUIMessageLoop());
177
178   // We expect to get the same data back, even though it's not all ASCII.
179   EXPECT_CALL(consumer,
180       OnGetPasswordStoreResults(ContainsAllPasswordForms(expected_forms)))
181       .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
182
183   store->GetAutofillableLogins(&consumer);
184   base::MessageLoop::current()->Run();
185
186   STLDeleteElements(&expected_forms);
187 }
188
189 TEST_F(PasswordStoreDefaultTest, Notifications) {
190   scoped_refptr<PasswordStore> store(
191       new PasswordStoreDefault(login_db_.release(), profile_.get()));
192   store->Init();
193
194   PasswordFormData form_data =
195   { PasswordForm::SCHEME_HTML,
196     "http://bar.example.com",
197     "http://bar.example.com/origin",
198     "http://bar.example.com/action",
199     L"submit_element",
200     L"username_element",
201     L"password_element",
202     L"username_value",
203     L"password_value",
204     true, false, 1 };
205   scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
206
207   scoped_refptr<DBThreadObserverHelper> helper = new DBThreadObserverHelper;
208   helper->Init(store.get());
209
210   const PasswordStoreChange expected_add_changes[] = {
211     PasswordStoreChange(PasswordStoreChange::ADD, *form),
212   };
213
214   EXPECT_CALL(
215       helper->observer(),
216       Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
217               content::Source<PasswordStore>(store.get()),
218               Property(&content::Details<const PasswordStoreChangeList>::ptr,
219                        Pointee(ElementsAreArray(expected_add_changes)))));
220
221   // Adding a login should trigger a notification.
222   store->AddLogin(*form);
223
224   // The PasswordStore schedules tasks to run on the DB thread so we schedule
225   // yet another task to notify us that it's safe to carry on with the test.
226   WaitableEvent done(false, false);
227   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
228       base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
229   done.Wait();
230
231   // Change the password.
232   form->password_value = base::ASCIIToUTF16("a different password");
233
234   const PasswordStoreChange expected_update_changes[] = {
235     PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
236   };
237
238   EXPECT_CALL(
239       helper->observer(),
240       Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
241               content::Source<PasswordStore>(store.get()),
242               Property(&content::Details<const PasswordStoreChangeList>::ptr,
243                        Pointee(ElementsAreArray(expected_update_changes)))));
244
245   // Updating the login with the new password should trigger a notification.
246   store->UpdateLogin(*form);
247
248   // Wait for PasswordStore to send the notification.
249   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
250       base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
251   done.Wait();
252
253   const PasswordStoreChange expected_delete_changes[] = {
254     PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
255   };
256
257   EXPECT_CALL(
258       helper->observer(),
259       Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
260               content::Source<PasswordStore>(store.get()),
261               Property(&content::Details<const PasswordStoreChangeList>::ptr,
262                        Pointee(ElementsAreArray(expected_delete_changes)))));
263
264   // Deleting the login should trigger a notification.
265   store->RemoveLogin(*form);
266
267   // Wait for PasswordStore to send the notification.
268   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
269       base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
270   done.Wait();
271
272   store->ShutdownOnUIThread();
273 }