| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/basictypes.h" | 5 #include "base/basictypes.h" |
| 6 #include "base/scoped_temp_dir.h" |
| 6 #include "base/stl_util-inl.h" | 7 #include "base/stl_util-inl.h" |
| 7 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 8 #include "base/scoped_temp_dir.h" | |
| 9 #include "base/time.h" | 9 #include "base/time.h" |
| 10 #include "base/waitable_event.h" | 10 #include "base/waitable_event.h" |
| 11 #include "chrome/browser/password_manager/password_form_data.h" |
| 11 #include "chrome/browser/password_manager/password_store_change.h" | 12 #include "chrome/browser/password_manager/password_store_change.h" |
| 12 #include "chrome/browser/password_manager/password_store_default.h" | 13 #include "chrome/browser/password_manager/password_store_x.h" |
| 13 #include "chrome/browser/password_manager/password_form_data.h" | |
| 14 #include "chrome/browser/webdata/web_data_service.h" | 14 #include "chrome/browser/webdata/web_data_service.h" |
| 15 #include "chrome/common/notification_service.h" | 15 #include "chrome/common/notification_service.h" |
| 16 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
| 17 #include "chrome/test/testing_profile.h" | 17 #include "chrome/test/testing_profile.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 20 |
| 21 using base::WaitableEvent; | 21 using base::WaitableEvent; |
| 22 using testing::_; | 22 using testing::_; |
| 23 using testing::DoAll; | 23 using testing::DoAll; |
| 24 using testing::ElementsAreArray; | 24 using testing::ElementsAreArray; |
| 25 using testing::Pointee; | 25 using testing::Pointee; |
| 26 using testing::Property; | 26 using testing::Property; |
| 27 using testing::WithArg; | 27 using testing::WithArg; |
| 28 using webkit_glue::PasswordForm; | 28 using webkit_glue::PasswordForm; |
| 29 | 29 |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 class MockPasswordStoreConsumer : public PasswordStoreConsumer { | 32 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
| 33 public: | 33 public: |
| 34 MOCK_METHOD2(OnPasswordStoreRequestDone, | 34 MOCK_METHOD2(OnPasswordStoreRequestDone, |
| 35 void(int, const std::vector<webkit_glue::PasswordForm*>&)); | 35 void(int, const std::vector<PasswordForm*>&)); |
| 36 }; | 36 }; |
| 37 | 37 |
| 38 class MockWebDataServiceConsumer : public WebDataServiceConsumer { | 38 class MockWebDataServiceConsumer : public WebDataServiceConsumer { |
| 39 public: | 39 public: |
| 40 MOCK_METHOD2(OnWebDataServiceRequestDone, void(WebDataService::Handle, | 40 MOCK_METHOD2(OnWebDataServiceRequestDone, void(WebDataService::Handle, |
| 41 const WDTypedResult*)); | 41 const WDTypedResult*)); |
| 42 }; | 42 }; |
| 43 | 43 |
| 44 class SignalingTask : public Task { | 44 class SignalingTask : public Task { |
| 45 public: | 45 public: |
| 46 explicit SignalingTask(WaitableEvent* event) : event_(event) { | 46 explicit SignalingTask(WaitableEvent* event) : event_(event) { |
| 47 } | 47 } |
| 48 virtual void Run() { | 48 virtual void Run() { |
| 49 event_->Signal(); | 49 event_->Signal(); |
| 50 } | 50 } |
| 51 private: | 51 private: |
| 52 WaitableEvent* event_; | 52 WaitableEvent* event_; |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 class MockNotificationObserver : public NotificationObserver { | 55 class MockNotificationObserver : public NotificationObserver { |
| 56 public: | 56 public: |
| 57 MOCK_METHOD3(Observe, void(NotificationType, | 57 MOCK_METHOD3(Observe, void(NotificationType, |
| 58 const NotificationSource&, | 58 const NotificationSource&, |
| 59 const NotificationDetails&)); | 59 const NotificationDetails&)); |
| 60 }; | 60 }; |
| 61 | 61 |
| 62 // This class will add and remove a mock notification observer from | 62 // This class will add and remove a mock notification observer from |
| 63 // the DB thread. | 63 // the DB thread. |
| 64 class DBThreadObserverHelper : | 64 class DBThreadObserverHelper |
| 65 public base::RefCountedThreadSafe<DBThreadObserverHelper, | 65 : public base::RefCountedThreadSafe<DBThreadObserverHelper, |
| 66 ChromeThread::DeleteOnDBThread> { | 66 ChromeThread::DeleteOnDBThread> { |
| 67 public: | 67 public: |
| 68 DBThreadObserverHelper() : done_event_(true, false) {} | 68 DBThreadObserverHelper() : done_event_(true, false) {} |
| 69 | 69 |
| 70 void Init() { | 70 void Init() { |
| 71 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 71 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 72 ChromeThread::PostTask( | 72 ChromeThread::PostTask( |
| 73 ChromeThread::DB, | 73 ChromeThread::DB, |
| 74 FROM_HERE, | 74 FROM_HERE, |
| 75 NewRunnableMethod(this, &DBThreadObserverHelper::AddObserverTask)); | 75 NewRunnableMethod(this, &DBThreadObserverHelper::AddObserverTask)); |
| 76 done_event_.Wait(); | 76 done_event_.Wait(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 94 NotificationType::LOGINS_CHANGED, | 94 NotificationType::LOGINS_CHANGED, |
| 95 NotificationService::AllSources()); | 95 NotificationService::AllSources()); |
| 96 done_event_.Signal(); | 96 done_event_.Signal(); |
| 97 } | 97 } |
| 98 | 98 |
| 99 WaitableEvent done_event_; | 99 WaitableEvent done_event_; |
| 100 NotificationRegistrar registrar_; | 100 NotificationRegistrar registrar_; |
| 101 MockNotificationObserver observer_; | 101 MockNotificationObserver observer_; |
| 102 }; | 102 }; |
| 103 | 103 |
| 104 class FailingBackend : public PasswordStoreX::NativeBackend { |
| 105 public: |
| 106 virtual bool Init() { return true; } |
| 107 |
| 108 virtual bool AddLogin(const PasswordForm& form) { return false; } |
| 109 virtual bool UpdateLogin(const PasswordForm& form) { return false; } |
| 110 virtual bool RemoveLogin(const PasswordForm& form) { return false; } |
| 111 |
| 112 virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin, |
| 113 const base::Time& delete_end) { |
| 114 return false; |
| 115 } |
| 116 |
| 117 virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) { |
| 118 return false; |
| 119 } |
| 120 |
| 121 virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, |
| 122 const base::Time& get_end, |
| 123 PasswordFormList* forms) { |
| 124 return false; |
| 125 } |
| 126 |
| 127 virtual bool GetAutofillableLogins(PasswordFormList* forms) { return false; } |
| 128 virtual bool GetBlacklistLogins(PasswordFormList* forms) { return false; } |
| 129 }; |
| 130 |
| 131 class MockBackend : public PasswordStoreX::NativeBackend { |
| 132 public: |
| 133 virtual bool Init() { return true; } |
| 134 |
| 135 virtual bool AddLogin(const PasswordForm& form) { |
| 136 all_forms_.push_back(form); |
| 137 return true; |
| 138 } |
| 139 |
| 140 virtual bool UpdateLogin(const PasswordForm& form) { |
| 141 for (size_t i = 0; i < all_forms_.size(); ++i) |
| 142 if (CompareForms(all_forms_[i], form, true)) |
| 143 all_forms_[i] = form; |
| 144 return true; |
| 145 } |
| 146 |
| 147 virtual bool RemoveLogin(const PasswordForm& form) { |
| 148 for (size_t i = 0; i < all_forms_.size(); ++i) |
| 149 if (CompareForms(all_forms_[i], form, false)) |
| 150 erase(i--); |
| 151 return true; |
| 152 } |
| 153 |
| 154 virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin, |
| 155 const base::Time& delete_end) { |
| 156 for (size_t i = 0; i < all_forms_.size(); ++i) { |
| 157 if (delete_begin <= all_forms_[i].date_created && |
| 158 (delete_end.is_null() || all_forms_[i].date_created < delete_end)) |
| 159 erase(i--); |
| 160 } |
| 161 return true; |
| 162 } |
| 163 |
| 164 virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) { |
| 165 for (size_t i = 0; i < all_forms_.size(); ++i) |
| 166 if (all_forms_[i].signon_realm == form.signon_realm) |
| 167 forms->push_back(new PasswordForm(all_forms_[i])); |
| 168 return true; |
| 169 } |
| 170 |
| 171 virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, |
| 172 const base::Time& get_end, |
| 173 PasswordFormList* forms) { |
| 174 for (size_t i = 0; i < all_forms_.size(); ++i) |
| 175 if (get_begin <= all_forms_[i].date_created && |
| 176 (get_end.is_null() || all_forms_[i].date_created < get_end)) |
| 177 forms->push_back(new PasswordForm(all_forms_[i])); |
| 178 return true; |
| 179 } |
| 180 |
| 181 virtual bool GetAutofillableLogins(PasswordFormList* forms) { |
| 182 for (size_t i = 0; i < all_forms_.size(); ++i) |
| 183 if (!all_forms_[i].blacklisted_by_user) |
| 184 forms->push_back(new PasswordForm(all_forms_[i])); |
| 185 return true; |
| 186 } |
| 187 |
| 188 virtual bool GetBlacklistLogins(PasswordFormList* forms) { |
| 189 for (size_t i = 0; i < all_forms_.size(); ++i) |
| 190 if (all_forms_[i].blacklisted_by_user) |
| 191 forms->push_back(new PasswordForm(all_forms_[i])); |
| 192 return true; |
| 193 } |
| 194 |
| 195 private: |
| 196 void erase(size_t index) { |
| 197 if (index < all_forms_.size() - 1) |
| 198 all_forms_[index] = all_forms_[all_forms_.size() - 1]; |
| 199 all_forms_.pop_back(); |
| 200 } |
| 201 |
| 202 bool CompareForms(const PasswordForm& a, const PasswordForm& b, bool update) { |
| 203 // An update check doesn't care about the submit element. |
| 204 if (!update && a.submit_element != b.submit_element) |
| 205 return false; |
| 206 return a.origin == b.origin && |
| 207 a.password_element == b.password_element && |
| 208 a.signon_realm == b.signon_realm && |
| 209 a.username_element == b.username_element && |
| 210 a.username_value == b.username_value; |
| 211 } |
| 212 |
| 213 std::vector<PasswordForm> all_forms_; |
| 214 }; |
| 215 |
| 216 class MockLoginDatabaseReturn { |
| 217 public: |
| 218 MOCK_METHOD1(OnLoginDatabaseQueryDone, |
| 219 void(const std::vector<PasswordForm*>&)); |
| 220 }; |
| 221 |
| 222 class LoginDatabaseQueryTask : public Task { |
| 223 public: |
| 224 LoginDatabaseQueryTask(LoginDatabase* login_db, |
| 225 bool autofillable, |
| 226 MockLoginDatabaseReturn* mock_return) |
| 227 : login_db_(login_db), autofillable_(autofillable), |
| 228 mock_return_(mock_return) { |
| 229 } |
| 230 |
| 231 virtual void Run() { |
| 232 std::vector<PasswordForm*> forms; |
| 233 if (autofillable_) |
| 234 login_db_->GetAutofillableLogins(&forms); |
| 235 else |
| 236 login_db_->GetBlacklistLogins(&forms); |
| 237 mock_return_->OnLoginDatabaseQueryDone(forms); |
| 238 } |
| 239 |
| 240 private: |
| 241 LoginDatabase* login_db_; |
| 242 bool autofillable_; |
| 243 MockLoginDatabaseReturn* mock_return_; |
| 244 }; |
| 245 |
| 246 const PasswordFormData g_autofillable_data[] = { |
| 247 { PasswordForm::SCHEME_HTML, |
| 248 "http://foo.example.com", |
| 249 "http://foo.example.com/origin", |
| 250 "http://foo.example.com/action", |
| 251 L"submit_element", |
| 252 L"username_element", |
| 253 L"password_element", |
| 254 L"username_value", |
| 255 L"password_value", |
| 256 true, false, 1 }, |
| 257 { PasswordForm::SCHEME_HTML, |
| 258 "http://bar.example.com", |
| 259 "http://bar.example.com/origin", |
| 260 "http://bar.example.com/action", |
| 261 L"submit_element", |
| 262 L"username_element", |
| 263 L"password_element", |
| 264 L"username_value", |
| 265 L"password_value", |
| 266 true, false, 2 }, |
| 267 { PasswordForm::SCHEME_HTML, |
| 268 "http://baz.example.com", |
| 269 "http://baz.example.com/origin", |
| 270 "http://baz.example.com/action", |
| 271 L"submit_element", |
| 272 L"username_element", |
| 273 L"password_element", |
| 274 L"username_value", |
| 275 L"password_value", |
| 276 true, false, 3 }, |
| 277 }; |
| 278 const PasswordFormData g_blacklisted_data[] = { |
| 279 { PasswordForm::SCHEME_HTML, |
| 280 "http://blacklisted.example.com", |
| 281 "http://blacklisted.example.com/origin", |
| 282 "http://blacklisted.example.com/action", |
| 283 L"submit_element", |
| 284 L"username_element", |
| 285 L"password_element", |
| 286 NULL, |
| 287 NULL, |
| 288 false, false, 1 }, |
| 289 { PasswordForm::SCHEME_HTML, |
| 290 "http://blacklisted2.example.com", |
| 291 "http://blacklisted2.example.com/origin", |
| 292 "http://blacklisted2.example.com/action", |
| 293 L"submit_element", |
| 294 L"username_element", |
| 295 L"password_element", |
| 296 NULL, |
| 297 NULL, |
| 298 false, false, 2 }, |
| 299 }; |
| 300 |
| 104 } // anonymous namespace | 301 } // anonymous namespace |
| 105 | 302 |
| 106 typedef std::vector<PasswordForm*> VectorOfForms; | 303 typedef std::vector<PasswordForm*> VectorOfForms; |
| 107 | 304 |
| 108 class PasswordStoreDefaultTest : public testing::Test { | 305 // LoginDatabase isn't reference counted, but in these unit tests that won't be |
| 306 // a problem as it always outlives the threads we post tasks to. |
| 307 template<> |
| 308 struct RunnableMethodTraits<LoginDatabase> { |
| 309 void RetainCallee(LoginDatabase*) {} |
| 310 void ReleaseCallee(LoginDatabase*) {} |
| 311 }; |
| 312 |
| 313 enum BackendType { |
| 314 NO_BACKEND, |
| 315 FAILING_BACKEND, |
| 316 WORKING_BACKEND |
| 317 }; |
| 318 |
| 319 class PasswordStoreXTest : public testing::TestWithParam<BackendType> { |
| 109 protected: | 320 protected: |
| 110 PasswordStoreDefaultTest() | 321 PasswordStoreXTest() |
| 111 : ui_thread_(ChromeThread::UI, &message_loop_), | 322 : ui_thread_(ChromeThread::UI, &message_loop_), |
| 112 db_thread_(ChromeThread::DB) { | 323 db_thread_(ChromeThread::DB) { |
| 113 } | 324 } |
| 114 | 325 |
| 115 virtual void SetUp() { | 326 virtual void SetUp() { |
| 116 ASSERT_TRUE(db_thread_.Start()); | 327 ASSERT_TRUE(db_thread_.Start()); |
| 117 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 328 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 118 | 329 |
| 119 profile_.reset(new TestingProfile()); | 330 profile_.reset(new TestingProfile()); |
| 120 | 331 |
| 121 login_db_.reset(new LoginDatabase()); | 332 login_db_.reset(new LoginDatabase()); |
| 122 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append( | 333 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append( |
| 123 FILE_PATH_LITERAL("login_test")))); | 334 FILE_PATH_LITERAL("login_test")))); |
| 124 | 335 |
| 125 wds_ = new WebDataService(); | 336 wds_ = new WebDataService(); |
| 126 ASSERT_TRUE(wds_->Init(temp_dir_.path())); | 337 ASSERT_TRUE(wds_->Init(temp_dir_.path())); |
| 127 } | 338 } |
| 128 | 339 |
| 129 virtual void TearDown() { | 340 virtual void TearDown() { |
| 130 wds_->Shutdown(); | 341 wds_->Shutdown(); |
| 131 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); | 342 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); |
| 132 MessageLoop::current()->Run(); | 343 MessageLoop::current()->Run(); |
| 133 db_thread_.Stop(); | 344 db_thread_.Stop(); |
| 134 } | 345 } |
| 135 | 346 |
| 347 PasswordStoreX::NativeBackend* GetBackend() { |
| 348 switch (GetParam()) { |
| 349 case FAILING_BACKEND: |
| 350 return new FailingBackend(); |
| 351 case WORKING_BACKEND: |
| 352 return new MockBackend(); |
| 353 default: |
| 354 return NULL; |
| 355 } |
| 356 } |
| 357 |
| 136 MessageLoopForUI message_loop_; | 358 MessageLoopForUI message_loop_; |
| 137 ChromeThread ui_thread_; | 359 ChromeThread ui_thread_; |
| 138 ChromeThread db_thread_; // PasswordStore, WDS schedule work on this thread. | 360 ChromeThread db_thread_; // PasswordStore, WDS schedule work on this thread. |
| 139 | 361 |
| 140 scoped_ptr<LoginDatabase> login_db_; | 362 scoped_ptr<LoginDatabase> login_db_; |
| 141 scoped_ptr<TestingProfile> profile_; | 363 scoped_ptr<TestingProfile> profile_; |
| 142 scoped_refptr<WebDataService> wds_; | 364 scoped_refptr<WebDataService> wds_; |
| 143 ScopedTempDir temp_dir_; | 365 ScopedTempDir temp_dir_; |
| 144 }; | 366 }; |
| 145 | 367 |
| 146 ACTION(STLDeleteElements0) { | 368 ACTION(STLDeleteElements0) { |
| 147 STLDeleteContainerPointers(arg0.begin(), arg0.end()); | 369 STLDeleteContainerPointers(arg0.begin(), arg0.end()); |
| 148 } | 370 } |
| 149 | 371 |
| 150 ACTION(QuitUIMessageLoop) { | 372 ACTION(QuitUIMessageLoop) { |
| 151 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 373 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 152 MessageLoop::current()->Quit(); | 374 MessageLoop::current()->Quit(); |
| 153 } | 375 } |
| 154 | 376 |
| 155 MATCHER(EmptyWDResult, "") { | 377 MATCHER(EmptyWDResult, "") { |
| 156 return static_cast<const WDResult<std::vector<PasswordForm*> >*>( | 378 return static_cast<const WDResult<std::vector<PasswordForm*> >*>( |
| 157 arg)->GetValue().empty(); | 379 arg)->GetValue().empty(); |
| 158 } | 380 } |
| 159 | 381 |
| 160 TEST_F(PasswordStoreDefaultTest, Migration) { | 382 TEST_P(PasswordStoreXTest, WDSMigration) { |
| 161 PasswordFormData autofillable_data[] = { | |
| 162 { PasswordForm::SCHEME_HTML, | |
| 163 "http://foo.example.com", | |
| 164 "http://foo.example.com/origin", | |
| 165 "http://foo.example.com/action", | |
| 166 L"submit_element", | |
| 167 L"username_element", | |
| 168 L"password_element", | |
| 169 L"username_value", | |
| 170 L"password_value", | |
| 171 true, false, 1 }, | |
| 172 { PasswordForm::SCHEME_HTML, | |
| 173 "http://bar.example.com", | |
| 174 "http://bar.example.com/origin", | |
| 175 "http://bar.example.com/action", | |
| 176 L"submit_element", | |
| 177 L"username_element", | |
| 178 L"password_element", | |
| 179 L"username_value", | |
| 180 L"password_value", | |
| 181 true, false, 2 }, | |
| 182 { PasswordForm::SCHEME_HTML, | |
| 183 "http://baz.example.com", | |
| 184 "http://baz.example.com/origin", | |
| 185 "http://baz.example.com/action", | |
| 186 L"submit_element", | |
| 187 L"username_element", | |
| 188 L"password_element", | |
| 189 L"username_value", | |
| 190 L"password_value", | |
| 191 true, false, 3 }, | |
| 192 }; | |
| 193 PasswordFormData blacklisted_data[] = { | |
| 194 { PasswordForm::SCHEME_HTML, | |
| 195 "http://blacklisted.example.com", | |
| 196 "http://blacklisted.example.com/origin", | |
| 197 "http://blacklisted.example.com/action", | |
| 198 L"submit_element", | |
| 199 L"username_element", | |
| 200 L"password_element", | |
| 201 NULL, | |
| 202 NULL, | |
| 203 false, false, 1 }, | |
| 204 { PasswordForm::SCHEME_HTML, | |
| 205 "http://blacklisted2.example.com", | |
| 206 "http://blacklisted2.example.com/origin", | |
| 207 "http://blacklisted2.example.com/action", | |
| 208 L"submit_element", | |
| 209 L"username_element", | |
| 210 L"password_element", | |
| 211 NULL, | |
| 212 NULL, | |
| 213 false, false, 2 }, | |
| 214 }; | |
| 215 | |
| 216 VectorOfForms expected_autofillable; | 383 VectorOfForms expected_autofillable; |
| 217 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(autofillable_data); ++i) { | 384 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_autofillable_data); ++i) { |
| 218 expected_autofillable.push_back( | 385 expected_autofillable.push_back( |
| 219 CreatePasswordFormFromData(autofillable_data[i])); | 386 CreatePasswordFormFromData(g_autofillable_data[i])); |
| 220 } | 387 } |
| 221 | 388 |
| 222 VectorOfForms expected_blacklisted; | 389 VectorOfForms expected_blacklisted; |
| 223 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(blacklisted_data); ++i) { | 390 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_blacklisted_data); ++i) { |
| 224 expected_blacklisted.push_back( | 391 expected_blacklisted.push_back( |
| 225 CreatePasswordFormFromData(blacklisted_data[i])); | 392 CreatePasswordFormFromData(g_blacklisted_data[i])); |
| 226 } | 393 } |
| 227 | 394 |
| 228 // Populate the WDS with logins that should be migrated. | 395 // Populate the WDS with logins that should be migrated. |
| 229 for (VectorOfForms::iterator it = expected_autofillable.begin(); | 396 for (VectorOfForms::iterator it = expected_autofillable.begin(); |
| 230 it != expected_autofillable.end(); ++it) { | 397 it != expected_autofillable.end(); ++it) { |
| 231 wds_->AddLogin(**it); | 398 wds_->AddLogin(**it); |
| 232 } | 399 } |
| 233 for (VectorOfForms::iterator it = expected_blacklisted.begin(); | 400 for (VectorOfForms::iterator it = expected_blacklisted.begin(); |
| 234 it != expected_blacklisted.end(); ++it) { | 401 it != expected_blacklisted.end(); ++it) { |
| 235 wds_->AddLogin(**it); | 402 wds_->AddLogin(**it); |
| 236 } | 403 } |
| 237 | 404 |
| 238 // The WDS schedules tasks to run on the DB thread so we schedule yet another | 405 // The WDS schedules tasks to run on the DB thread so we schedule yet another |
| 239 // task to notify us that it's safe to carry on with the test. | 406 // task to notify us that it's safe to carry on with the test. |
| 240 WaitableEvent done(false, false); | 407 WaitableEvent done(false, false); |
| 241 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 408 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 242 done.Wait(); | 409 done.Wait(); |
| 243 | 410 |
| 244 // Initializing the PasswordStore should trigger a migration. | 411 // Initializing the PasswordStore should trigger a migration. |
| 245 scoped_refptr<PasswordStoreDefault> store( | 412 scoped_refptr<PasswordStoreX> store( |
| 246 new PasswordStoreDefault(login_db_.release(), profile_.get(), wds_.get()))
; | 413 new PasswordStoreX(login_db_.release(), |
| 414 profile_.get(), |
| 415 wds_.get(), |
| 416 GetBackend())); |
| 247 store->Init(); | 417 store->Init(); |
| 248 | 418 |
| 249 // Check that the migration preference has not been initialized; | 419 // Check that the migration preference has not been initialized. |
| 250 ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference( | 420 ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference( |
| 251 prefs::kLoginDatabaseMigrated)); | 421 prefs::kLoginDatabaseMigrated)); |
| 252 | 422 |
| 253 // Again, the WDS schedules tasks to run on the DB thread, so schedule a task | 423 // Again, the WDS schedules tasks to run on the DB thread, so schedule a task |
| 254 // to signal us when it is safe to continue. | 424 // to signal us when it is safe to continue. |
| 255 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 425 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 256 done.Wait(); | 426 done.Wait(); |
| 257 | 427 |
| 258 // Let the WDS callbacks proceed so the logins can be migrated. | 428 // Let the WDS callbacks proceed so the logins can be migrated. |
| 259 MessageLoop::current()->RunAllPending(); | 429 MessageLoop::current()->RunAllPending(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 482 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 313 done.Wait(); | 483 done.Wait(); |
| 314 | 484 |
| 315 // Handle the callback from the WDS. | 485 // Handle the callback from the WDS. |
| 316 MessageLoop::current()->RunAllPending(); | 486 MessageLoop::current()->RunAllPending(); |
| 317 | 487 |
| 318 STLDeleteElements(&expected_autofillable); | 488 STLDeleteElements(&expected_autofillable); |
| 319 STLDeleteElements(&expected_blacklisted); | 489 STLDeleteElements(&expected_blacklisted); |
| 320 } | 490 } |
| 321 | 491 |
| 322 TEST_F(PasswordStoreDefaultTest, MigrationAlreadyDone) { | 492 TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) { |
| 323 PasswordFormData wds_data[] = { | 493 PasswordFormData wds_data[] = { |
| 324 { PasswordForm::SCHEME_HTML, | 494 { PasswordForm::SCHEME_HTML, |
| 325 "http://bar.example.com", | 495 "http://bar.example.com", |
| 326 "http://bar.example.com/origin", | 496 "http://bar.example.com/origin", |
| 327 "http://bar.example.com/action", | 497 "http://bar.example.com/action", |
| 328 L"submit_element", | 498 L"submit_element", |
| 329 L"username_element", | 499 L"username_element", |
| 330 L"password_element", | 500 L"password_element", |
| 331 L"username_value", | 501 L"username_value", |
| 332 L"password_value", | 502 L"password_value", |
| (...skipping 16 matching lines...) Expand all Loading... |
| 349 // task to notify us that it's safe to carry on with the test. | 519 // task to notify us that it's safe to carry on with the test. |
| 350 WaitableEvent done(false, false); | 520 WaitableEvent done(false, false); |
| 351 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 521 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 352 done.Wait(); | 522 done.Wait(); |
| 353 | 523 |
| 354 // Prentend that the migration has already taken place. | 524 // Prentend that the migration has already taken place. |
| 355 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, | 525 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, |
| 356 true); | 526 true); |
| 357 | 527 |
| 358 // Initializing the PasswordStore shouldn't trigger a migration. | 528 // Initializing the PasswordStore shouldn't trigger a migration. |
| 359 scoped_refptr<PasswordStoreDefault> store( | 529 scoped_refptr<PasswordStoreX> store( |
| 360 new PasswordStoreDefault(login_db_.release(), profile_.get(), | 530 new PasswordStoreX(login_db_.release(), |
| 361 wds_.get())); | 531 profile_.get(), |
| 532 wds_.get(), |
| 533 GetBackend())); |
| 362 store->Init(); | 534 store->Init(); |
| 363 | 535 |
| 364 MockPasswordStoreConsumer consumer; | 536 MockPasswordStoreConsumer consumer; |
| 365 // Make sure we quit the MessageLoop even if the test fails. | 537 // Make sure we quit the MessageLoop even if the test fails. |
| 366 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) | 538 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) |
| 367 .WillByDefault(QuitUIMessageLoop()); | 539 .WillByDefault(QuitUIMessageLoop()); |
| 368 | 540 |
| 369 // No forms should be migrated. | 541 // No forms should be migrated. |
| 370 VectorOfForms empty; | 542 VectorOfForms empty; |
| 371 EXPECT_CALL(consumer, | 543 EXPECT_CALL(consumer, |
| 372 OnPasswordStoreRequestDone(_, | 544 OnPasswordStoreRequestDone(_, |
| 373 ContainsAllPasswordForms(empty))) | 545 ContainsAllPasswordForms(empty))) |
| 374 .WillOnce(QuitUIMessageLoop()); | 546 .WillOnce(QuitUIMessageLoop()); |
| 375 | 547 |
| 376 store->GetAutofillableLogins(&consumer); | 548 store->GetAutofillableLogins(&consumer); |
| 377 MessageLoop::current()->Run(); | 549 MessageLoop::current()->Run(); |
| 378 | 550 |
| 379 STLDeleteElements(&unexpected_autofillable); | 551 STLDeleteElements(&unexpected_autofillable); |
| 380 } | 552 } |
| 381 | 553 |
| 382 TEST_F(PasswordStoreDefaultTest, Notifications) { | 554 TEST_P(PasswordStoreXTest, Notifications) { |
| 383 // Prentend that the migration has already taken place. | 555 // Pretend that the migration has already taken place. |
| 384 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, | 556 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, |
| 385 true); | 557 true); |
| 386 | 558 |
| 387 // Initializing the PasswordStore shouldn't trigger a migration. | 559 // Initializing the PasswordStore shouldn't trigger a migration. |
| 388 scoped_refptr<PasswordStoreDefault> store( | 560 scoped_refptr<PasswordStoreX> store( |
| 389 new PasswordStoreDefault(login_db_.release(), profile_.get(), | 561 new PasswordStoreX(login_db_.release(), |
| 390 wds_.get())); | 562 profile_.get(), |
| 563 wds_.get(), |
| 564 GetBackend())); |
| 391 store->Init(); | 565 store->Init(); |
| 392 | 566 |
| 393 PasswordFormData form_data = | 567 PasswordFormData form_data = |
| 394 { PasswordForm::SCHEME_HTML, | 568 { PasswordForm::SCHEME_HTML, |
| 395 "http://bar.example.com", | 569 "http://bar.example.com", |
| 396 "http://bar.example.com/origin", | 570 "http://bar.example.com/origin", |
| 397 "http://bar.example.com/action", | 571 "http://bar.example.com/action", |
| 398 L"submit_element", | 572 L"submit_element", |
| 399 L"username_element", | 573 L"username_element", |
| 400 L"password_element", | 574 L"password_element", |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 Pointee(ElementsAreArray( | 632 Pointee(ElementsAreArray( |
| 459 expected_delete_changes))))); | 633 expected_delete_changes))))); |
| 460 | 634 |
| 461 // Deleting the login should trigger a notification. | 635 // Deleting the login should trigger a notification. |
| 462 store->RemoveLogin(*form); | 636 store->RemoveLogin(*form); |
| 463 | 637 |
| 464 // Wait for PasswordStore to send the notification. | 638 // Wait for PasswordStore to send the notification. |
| 465 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); | 639 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 466 done.Wait(); | 640 done.Wait(); |
| 467 } | 641 } |
| 642 |
| 643 TEST_P(PasswordStoreXTest, NativeMigration) { |
| 644 VectorOfForms expected_autofillable; |
| 645 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_autofillable_data); ++i) { |
| 646 expected_autofillable.push_back( |
| 647 CreatePasswordFormFromData(g_autofillable_data[i])); |
| 648 } |
| 649 |
| 650 VectorOfForms expected_blacklisted; |
| 651 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_blacklisted_data); ++i) { |
| 652 expected_blacklisted.push_back( |
| 653 CreatePasswordFormFromData(g_blacklisted_data[i])); |
| 654 } |
| 655 |
| 656 LoginDatabase* login_db = login_db_.get(); |
| 657 |
| 658 // Populate the login DB with logins that should be migrated. |
| 659 for (VectorOfForms::iterator it = expected_autofillable.begin(); |
| 660 it != expected_autofillable.end(); ++it) { |
| 661 ChromeThread::PostTask(ChromeThread::DB, |
| 662 FROM_HERE, |
| 663 NewRunnableMethod(login_db, |
| 664 &LoginDatabase::AddLogin, |
| 665 **it)); |
| 666 } |
| 667 for (VectorOfForms::iterator it = expected_blacklisted.begin(); |
| 668 it != expected_blacklisted.end(); ++it) { |
| 669 ChromeThread::PostTask(ChromeThread::DB, |
| 670 FROM_HERE, |
| 671 NewRunnableMethod(login_db, |
| 672 &LoginDatabase::AddLogin, |
| 673 **it)); |
| 674 } |
| 675 |
| 676 // Schedule another task on the DB thread to notify us that it's safe to |
| 677 // carry on with the test. |
| 678 WaitableEvent done(false, false); |
| 679 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 680 done.Wait(); |
| 681 |
| 682 // Pretend that the WDS migration has already taken place. |
| 683 profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated, |
| 684 true); |
| 685 |
| 686 // Initializing the PasswordStore shouldn't trigger a native migration (yet). |
| 687 scoped_refptr<PasswordStoreX> store( |
| 688 new PasswordStoreX(login_db_.release(), |
| 689 profile_.get(), |
| 690 wds_.get(), |
| 691 GetBackend())); |
| 692 store->Init(); |
| 693 |
| 694 MockPasswordStoreConsumer consumer; |
| 695 |
| 696 // Make sure we quit the MessageLoop even if the test fails. |
| 697 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _)) |
| 698 .WillByDefault(QuitUIMessageLoop()); |
| 699 |
| 700 // The autofillable forms should have been migrated to the native backend. |
| 701 EXPECT_CALL(consumer, |
| 702 OnPasswordStoreRequestDone(_, |
| 703 ContainsAllPasswordForms(expected_autofillable))) |
| 704 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); |
| 705 |
| 706 store->GetAutofillableLogins(&consumer); |
| 707 MessageLoop::current()->Run(); |
| 708 |
| 709 // The blacklisted forms should have been migrated to the native backend. |
| 710 EXPECT_CALL(consumer, |
| 711 OnPasswordStoreRequestDone(_, |
| 712 ContainsAllPasswordForms(expected_blacklisted))) |
| 713 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop())); |
| 714 |
| 715 store->GetBlacklistLogins(&consumer); |
| 716 MessageLoop::current()->Run(); |
| 717 |
| 718 VectorOfForms empty; |
| 719 MockLoginDatabaseReturn ld_return; |
| 720 |
| 721 if (GetParam() == WORKING_BACKEND) { |
| 722 // No autofillable logins should be left in the login DB. |
| 723 EXPECT_CALL(ld_return, |
| 724 OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty))); |
| 725 } else { |
| 726 // The autofillable logins should still be in the login DB. |
| 727 EXPECT_CALL(ld_return, |
| 728 OnLoginDatabaseQueryDone( |
| 729 ContainsAllPasswordForms(expected_autofillable))) |
| 730 .WillOnce(WithArg<0>(STLDeleteElements0())); |
| 731 } |
| 732 |
| 733 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, |
| 734 new LoginDatabaseQueryTask(login_db, true, &ld_return)); |
| 735 |
| 736 // Wait for the login DB methods to execute on the DB thread. |
| 737 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 738 done.Wait(); |
| 739 |
| 740 if (GetParam() == WORKING_BACKEND) { |
| 741 // Likewise, no blacklisted logins should be left in the login DB. |
| 742 EXPECT_CALL(ld_return, |
| 743 OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty))); |
| 744 } else { |
| 745 // The blacklisted logins should still be in the login DB. |
| 746 EXPECT_CALL(ld_return, |
| 747 OnLoginDatabaseQueryDone( |
| 748 ContainsAllPasswordForms(expected_blacklisted))) |
| 749 .WillOnce(WithArg<0>(STLDeleteElements0())); |
| 750 } |
| 751 |
| 752 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, |
| 753 new LoginDatabaseQueryTask(login_db, false, &ld_return)); |
| 754 |
| 755 // Wait for the login DB methods to execute on the DB thread. |
| 756 ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done)); |
| 757 done.Wait(); |
| 758 |
| 759 STLDeleteElements(&expected_autofillable); |
| 760 STLDeleteElements(&expected_blacklisted); |
| 761 } |
| 762 |
| 763 INSTANTIATE_TEST_CASE_P(NoBackend, |
| 764 PasswordStoreXTest, |
| 765 testing::Values(NO_BACKEND)); |
| 766 INSTANTIATE_TEST_CASE_P(FailingBackend, |
| 767 PasswordStoreXTest, |
| 768 testing::Values(FAILING_BACKEND)); |
| 769 INSTANTIATE_TEST_CASE_P(WorkingBackend, |
| 770 PasswordStoreXTest, |
| 771 testing::Values(WORKING_BACKEND)); |
| OLD | NEW |