From 18b147138e014805955bfcb5dc93e2191d6e2447 Mon Sep 17 00:00:00 2001 From: "albertb@chromium.org" Date: Thu, 14 Oct 2010 20:04:01 +0000 Subject: Integration tests for password sync. BUG=none TEST=self Review URL: http://codereview.chromium.org/3701007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62632 0039d316-1c4b-4281-b951-d872f2087c98 --- .../browser/password_manager/password_form_data.cc | 74 ++++++++++++ .../browser/password_manager/password_form_data.h | 57 ++-------- chrome/browser/password_manager/password_store.h | 1 + chrome/chrome_tests.gypi | 6 + chrome/test/live_sync/live_passwords_sync_test.h | 125 +++++++++++++++++++++ chrome/test/live_sync/live_sync_test.cc | 5 + .../many_client_live_passwords_sync_test.cc | 33 ++++++ .../multiple_client_live_passwords_sync_test.cc | 36 ++++++ .../single_client_live_passwords_sync_test.cc | 31 +++++ .../two_client_live_passwords_sync_test.cc | 65 +++++++++++ 10 files changed, 386 insertions(+), 47 deletions(-) create mode 100644 chrome/test/live_sync/live_passwords_sync_test.h create mode 100644 chrome/test/live_sync/many_client_live_passwords_sync_test.cc create mode 100644 chrome/test/live_sync/multiple_client_live_passwords_sync_test.cc create mode 100644 chrome/test/live_sync/single_client_live_passwords_sync_test.cc create mode 100644 chrome/test/live_sync/two_client_live_passwords_sync_test.cc (limited to 'chrome') diff --git a/chrome/browser/password_manager/password_form_data.cc b/chrome/browser/password_manager/password_form_data.cc index ef9391d..b428d9a 100644 --- a/chrome/browser/password_manager/password_form_data.cc +++ b/chrome/browser/password_manager/password_form_data.cc @@ -36,3 +36,77 @@ PasswordForm* CreatePasswordFormFromData( } return form; } + +bool operator==(const PasswordForm& lhs, const PasswordForm& rhs) { + return (lhs.scheme == rhs.scheme && + lhs.signon_realm == rhs.signon_realm && + lhs.origin == rhs.origin && + lhs.action == rhs.action && + lhs.submit_element == rhs.submit_element && + lhs.username_element == rhs.username_element && + lhs.password_element == rhs.password_element && + lhs.username_value == rhs.username_value && + lhs.password_value == rhs.password_value && + lhs.blacklisted_by_user == rhs.blacklisted_by_user && + lhs.preferred == rhs.preferred && + lhs.ssl_valid == rhs.ssl_valid && + lhs.date_created == rhs.date_created); +} + +std::ostream& operator<<(std::ostream& os, const PasswordForm& form) { + return os << "scheme: " << form.scheme << std::endl + << "signon_realm: " << form.signon_realm << std::endl + << "origin: " << form.origin << std::endl + << "action: " << form.action << std::endl + << "submit_element: " << form.submit_element << std::endl + << "username_elem: " << form.username_element << std::endl + << "password_elem: " << form.password_element << std::endl + << "username_value: " << form.username_value << std::endl + << "password_value: " << form.password_value << std::endl + << "blacklisted: " << form.blacklisted_by_user << std::endl + << "preferred: " << form.preferred << std::endl + << "ssl_valid: " << form.ssl_valid << std::endl + << "date_created: " << form.date_created.ToDoubleT(); +} + +typedef std::set SetOfForms; + +bool ContainsSamePasswordFormsPtr( + const std::vector& first, + const std::vector& second) { + if (first.size() != second.size()) + return false; + SetOfForms expectations(first.begin(), first.end()); + for (unsigned int i = 0; i < second.size(); ++i) { + const PasswordForm* actual = second[i]; + bool found_match = false; + for (SetOfForms::iterator it = expectations.begin(); + it != expectations.end(); ++it) { + const PasswordForm* expected = *it; + if (*expected == *actual) { + found_match = true; + expectations.erase(it); + break; + } + } + if (!found_match) { + LOG(ERROR) << "No match for:" << std::endl << *actual; + return false; + } + } + return true; +} + +bool ContainsSamePasswordForms( + std::vector& first, + std::vector& second) { + std::vector first_ptr; + for (unsigned int i = 0; i < first.size(); ++i) { + first_ptr.push_back(&first[i]); + } + std::vector second_ptr; + for (unsigned int i = 0; i < second.size(); ++i) { + second_ptr.push_back(&second[i]); + } + return ContainsSamePasswordFormsPtr(first_ptr, second_ptr); +} diff --git a/chrome/browser/password_manager/password_form_data.h b/chrome/browser/password_manager/password_form_data.h index 838c3ce..8b3d248 100644 --- a/chrome/browser/password_manager/password_form_data.h +++ b/chrome/browser/password_manager/password_form_data.h @@ -31,57 +31,20 @@ struct PasswordFormData { webkit_glue::PasswordForm* CreatePasswordFormFromData( const PasswordFormData& form_data); -typedef std::set SetOfForms; +// Checks whether two vectors of PasswordForms contain equivalent elements, +// regardless of order. +bool ContainsSamePasswordFormsPtr( + const std::vector& first, + const std::vector& second); + +bool ContainsSamePasswordForms( + std::vector& first, + std::vector& second); // This gmock matcher is used to check that the |arg| contains exactly the same // PasswordForms as |forms|, regardless of order. MATCHER_P(ContainsAllPasswordForms, forms, "") { - if (forms.size() != arg.size()) - return false; - SetOfForms expectations(forms.begin(), forms.end()); - for (unsigned int i = 0; i < arg.size(); ++i) { - webkit_glue::PasswordForm* actual = arg[i]; - bool found_match = false; - for (SetOfForms::iterator it = expectations.begin(); - it != expectations.end(); ++it) { - webkit_glue::PasswordForm* expected = *it; - if (expected->scheme == actual->scheme && - expected->signon_realm == actual->signon_realm && - expected->origin == actual->origin && - expected->action == actual->action && - expected->submit_element == actual->submit_element && - expected->username_element == actual->username_element && - expected->password_element == actual->password_element && - expected->username_value == actual->username_value && - expected->password_value == actual->password_value && - expected->blacklisted_by_user == actual->blacklisted_by_user && - expected->preferred == actual->preferred && - expected->ssl_valid == actual->ssl_valid && - expected->date_created == actual->date_created) { - found_match = true; - expectations.erase(it); - break; - } - } - if (!found_match) { - LOG(ERROR) << "No match for:" << std::endl - << "scheme: " << actual->scheme << std::endl - << "signon_realm: " << actual->signon_realm << std::endl - << "origin: " << actual->origin << std::endl - << "action: " << actual->action << std::endl - << "submit_element: " << actual->submit_element << std::endl - << "username_elem: " << actual->username_element << std::endl - << "password_elem: " << actual->password_element << std::endl - << "username_value: " << actual->username_value << std::endl - << "password_value: " << actual->password_value << std::endl - << "blacklisted: " << actual->blacklisted_by_user << std::endl - << "preferred: " << actual->preferred << std::endl - << "ssl_valid: " << actual->ssl_valid << std::endl - << "date_created: " << actual->date_created.ToDoubleT(); - return false; - } - } - return true; + return ContainsSamePasswordFormsPtr(forms, arg); } #endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_FORM_DATA_H_ diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h index 6b6efa8..6b538d9 100644 --- a/chrome/browser/password_manager/password_store.h +++ b/chrome/browser/password_manager/password_store.h @@ -83,6 +83,7 @@ class PasswordStore : public base::RefCountedThreadSafe { friend class browser_sync::PasswordDataTypeController; friend class browser_sync::PasswordModelAssociator; friend class browser_sync::PasswordModelWorker; + friend class LivePasswordsSyncTest; virtual ~PasswordStore() {} diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 8707cdb..a9a8fc2 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2636,6 +2636,7 @@ 'app/chrome_dll_version.rc.version', 'browser/autofill/autofill_common_test.cc', 'browser/autofill/autofill_common_test.h', + 'browser/password_manager/password_form_data.cc', 'test/bookmark_load_observer.h', 'test/in_process_browser_test.cc', 'test/in_process_browser_test.h', @@ -2646,20 +2647,25 @@ 'test/live_sync/bookmark_model_verifier.h', 'test/live_sync/live_autofill_sync_test.h', 'test/live_sync/live_bookmarks_sync_test.h', + 'test/live_sync/live_passwords_sync_test.h', 'test/live_sync/live_preferences_sync_test.h', 'test/live_sync/live_sync_test.cc', 'test/live_sync/live_sync_test.h', 'test/live_sync/many_client_live_bookmarks_sync_test.cc', + 'test/live_sync/many_client_live_passwords_sync_test.cc', 'test/live_sync/many_client_live_preferences_sync_test.cc', 'test/live_sync/multiple_client_live_bookmarks_sync_test.cc', + 'test/live_sync/multiple_client_live_passwords_sync_test.cc', 'test/live_sync/multiple_client_live_preferences_sync_test.cc', 'test/live_sync/profile_sync_service_test_harness.cc', 'test/live_sync/profile_sync_service_test_harness.h', 'test/live_sync/single_client_live_bookmarks_sync_test.cc', + 'test/live_sync/single_client_live_passwords_sync_test.cc', 'test/live_sync/single_client_live_preferences_sync_test.cc', 'test/live_sync/two_client_live_autofill_sync_test.cc', 'test/live_sync/two_client_live_bookmarks_sync_test.cc', 'test/live_sync/two_client_live_preferences_sync_test.cc', + 'test/live_sync/two_client_live_passwords_sync_test.cc', 'test/test_notification_tracker.cc', 'test/test_notification_tracker.h', 'test/testing_browser_process.h', diff --git a/chrome/test/live_sync/live_passwords_sync_test.h b/chrome/test/live_sync/live_passwords_sync_test.h new file mode 100644 index 0000000..019b146 --- /dev/null +++ b/chrome/test/live_sync/live_passwords_sync_test.h @@ -0,0 +1,125 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_TEST_LIVE_SYNC_LIVE_PASSWORDS_SYNC_TEST_H_ +#define CHROME_TEST_LIVE_SYNC_LIVE_PASSWORDS_SYNC_TEST_H_ +#pragma once + +#include + +#include "chrome/browser/profile.h" +#include "chrome/browser/password_manager/password_store.h" +#include "chrome/test/live_sync/live_sync_test.h" +#include "chrome/test/ui_test_utils.h" +#include "chrome/test/signaling_task.h" +#include "webkit/glue/password_form.h" + +class LivePasswordsSyncTest : public LiveSyncTest { + public: + explicit LivePasswordsSyncTest(TestType test_type) + : LiveSyncTest(test_type) {} + + virtual ~LivePasswordsSyncTest() {} + + // Adds the login held in |form| to the password store |store|. Even though + // logins are normally added asynchronously, this method will block until the + // login is added. + void AddLogin(PasswordStore* store, const webkit_glue::PasswordForm& form) { + EXPECT_TRUE(store); + + store->AddLogin(form); + + base::WaitableEvent login_added(false, false); + store->ScheduleTask(new SignalingTask(&login_added)); + login_added.Wait(); + } + + // Searches |store| for all logins matching |form|, the results are added to + // |matches|. Note that the caller is responsible for deleting the forms added + // to |matches|. + void GetLogins(PasswordStore* store, + const webkit_glue::PasswordForm& form, + std::vector& matches) { + EXPECT_TRUE(store); + + PasswordStoreConsumerHelper consumer(matches); + store->GetLogins(form, &consumer); + ui_test_utils::RunMessageLoop(); + } + + PasswordStore* GetPasswordStore(int index) { + return GetProfile(index)->GetPasswordStore(Profile::IMPLICIT_ACCESS); + } + + PasswordStore* GetVerififerPasswordStore() { + return verifier()->GetPasswordStore(Profile::IMPLICIT_ACCESS); + } + + private: + class PasswordStoreConsumerHelper : public PasswordStoreConsumer { + public: + explicit PasswordStoreConsumerHelper( + std::vector& result) + : PasswordStoreConsumer(), result_(result) {} + + virtual void OnPasswordStoreRequestDone( + int handle, const std::vector& result) { + result_.clear(); + for (std::vector::const_iterator it = + result.begin(); it != result.end(); ++it) { + // Make a copy of the form since it gets deallocated after the caller of + // this method returns. + result_.push_back(**it); + } + MessageLoopForUI::current()->Quit(); + } + + private: + std::vector& result_; + + DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper); + }; + + DISALLOW_COPY_AND_ASSIGN(LivePasswordsSyncTest); +}; + +class SingleClientLivePasswordsSyncTest : public LivePasswordsSyncTest { + public: + SingleClientLivePasswordsSyncTest() + : LivePasswordsSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientLivePasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientLivePasswordsSyncTest); +}; + +class TwoClientLivePasswordsSyncTest : public LivePasswordsSyncTest { + public: + TwoClientLivePasswordsSyncTest() : LivePasswordsSyncTest(TWO_CLIENT) {} + virtual ~TwoClientLivePasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientLivePasswordsSyncTest); +}; + +class MultipleClientLivePasswordsSyncTest : public LivePasswordsSyncTest { + public: + MultipleClientLivePasswordsSyncTest() + : LivePasswordsSyncTest(MULTIPLE_CLIENT) {} + virtual ~MultipleClientLivePasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MultipleClientLivePasswordsSyncTest); +}; + +class ManyClientLivePasswordsSyncTest : public LivePasswordsSyncTest { + public: + ManyClientLivePasswordsSyncTest() : LivePasswordsSyncTest(MANY_CLIENT) {} + virtual ~ManyClientLivePasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ManyClientLivePasswordsSyncTest); +}; + +#endif // CHROME_TEST_LIVE_SYNC_LIVE_PASSWORDS_SYNC_TEST_H_ diff --git a/chrome/test/live_sync/live_sync_test.cc b/chrome/test/live_sync/live_sync_test.cc index ba55dd4..6fd16cb 100644 --- a/chrome/test/live_sync/live_sync_test.cc +++ b/chrome/test/live_sync/live_sync_test.cc @@ -118,6 +118,11 @@ void LiveSyncTest::SetUp() { cl->AppendSwitch(switches::kSyncUseSslTcp); } + // TODO(sync): Remove this once passwords sync is enabled by default. + if (!cl->HasSwitch(switches::kEnableSyncPasswords)) { + cl->AppendSwitch(switches::kEnableSyncPasswords); + } + // Mock the Mac Keychain service. The real Keychain can block on user input. #if defined(OS_MACOSX) Encryptor::UseMockKeychain(true); diff --git a/chrome/test/live_sync/many_client_live_passwords_sync_test.cc b/chrome/test/live_sync/many_client_live_passwords_sync_test.cc new file mode 100644 index 0000000..b279883 --- /dev/null +++ b/chrome/test/live_sync/many_client_live_passwords_sync_test.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/test/live_sync/live_passwords_sync_test.h" + +using webkit_glue::PasswordForm; + +IN_PROC_BROWSER_TEST_F(ManyClientLivePasswordsSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + PasswordForm form; + form.origin = GURL("http://www.google.com/"); + form.username_value = ASCIIToUTF16("username"); + form.password_value = ASCIIToUTF16("password"); + + AddLogin(GetVerififerPasswordStore(), form); + AddLogin(GetPasswordStore(0), form); + + EXPECT_TRUE(GetClient(0)->AwaitGroupSyncCycleCompletion(clients())); + + std::vector expected; + GetLogins(GetVerififerPasswordStore(), form, expected); + EXPECT_EQ(1U, expected.size()); + + for (int i = 0; i < num_clients(); ++i) { + std::vector actual; + GetLogins(GetPasswordStore(i), form, actual); + + EXPECT_TRUE(ContainsSamePasswordForms(expected, actual)); + } +} diff --git a/chrome/test/live_sync/multiple_client_live_passwords_sync_test.cc b/chrome/test/live_sync/multiple_client_live_passwords_sync_test.cc new file mode 100644 index 0000000..c277446 --- /dev/null +++ b/chrome/test/live_sync/multiple_client_live_passwords_sync_test.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/stringprintf.h" +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/test/live_sync/live_passwords_sync_test.h" + +using webkit_glue::PasswordForm; + +IN_PROC_BROWSER_TEST_F(MultipleClientLivePasswordsSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + for (int i = 0; i < num_clients(); ++i) { + PasswordForm form; + form.origin = GURL(StringPrintf("http://www.google.com/%d", i)); + form.username_value = ASCIIToUTF16(StringPrintf("username%d", i)); + form.password_value = ASCIIToUTF16(StringPrintf("password%d", i)); + + AddLogin(GetPasswordStore(i), form); + } + + EXPECT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients())); + + PasswordForm form; // Don't set any fields, so that all logins match. + std::vector expected; + GetLogins(GetPasswordStore(0), form, expected); + EXPECT_EQ((size_t) num_clients(), expected.size()); + + for (int i = 1; i < num_clients(); ++i) { + std::vector actual; + GetLogins(GetPasswordStore(i), form, actual); + + EXPECT_TRUE(ContainsSamePasswordForms(expected, actual)); + } +} diff --git a/chrome/test/live_sync/single_client_live_passwords_sync_test.cc b/chrome/test/live_sync/single_client_live_passwords_sync_test.cc new file mode 100644 index 0000000..ea5b183 --- /dev/null +++ b/chrome/test/live_sync/single_client_live_passwords_sync_test.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/test/live_sync/live_passwords_sync_test.h" + +using webkit_glue::PasswordForm; + +IN_PROC_BROWSER_TEST_F(SingleClientLivePasswordsSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + PasswordForm form; + form.origin = GURL("http://www.google.com/"); + form.username_value = ASCIIToUTF16("username"); + form.password_value = ASCIIToUTF16("password"); + + AddLogin(GetVerififerPasswordStore(), form); + AddLogin(GetPasswordStore(0), form); + + EXPECT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for passwords change.")); + + std::vector expected; + GetLogins(GetVerififerPasswordStore(), form, expected); + EXPECT_EQ(1U, expected.size()); + + std::vector actual; + GetLogins(GetPasswordStore(0), form, actual); + EXPECT_TRUE(ContainsSamePasswordForms(expected, actual)); +} diff --git a/chrome/test/live_sync/two_client_live_passwords_sync_test.cc b/chrome/test/live_sync/two_client_live_passwords_sync_test.cc new file mode 100644 index 0000000..6114bdd --- /dev/null +++ b/chrome/test/live_sync/two_client_live_passwords_sync_test.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/test/live_sync/live_passwords_sync_test.h" + +using webkit_glue::PasswordForm; + +IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Add) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + PasswordForm form; + form.origin = GURL("http://www.google.com/"); + form.username_value = ASCIIToUTF16("username"); + form.password_value = ASCIIToUTF16("password"); + + AddLogin(GetVerififerPasswordStore(), form); + AddLogin(GetPasswordStore(0), form); + + EXPECT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + std::vector expected; + GetLogins(GetVerififerPasswordStore(), form, expected); + EXPECT_EQ(1U, expected.size()); + + std::vector actual_zero; + GetLogins(GetPasswordStore(0), form, actual_zero); + EXPECT_TRUE(ContainsSamePasswordForms(expected, actual_zero)); + + std::vector actual_one; + GetLogins(GetPasswordStore(1), form, actual_one); + EXPECT_TRUE(ContainsSamePasswordForms(expected, actual_one)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Race) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + PasswordForm form; + form.origin = GURL("http://www.google.com/"); + + PasswordForm form_zero; + form_zero.origin = GURL("http://www.google.com/"); + form_zero.username_value = ASCIIToUTF16("username"); + form_zero.password_value = ASCIIToUTF16("zero"); + AddLogin(GetPasswordStore(0), form_zero); + + PasswordForm form_one; + form_one.origin = GURL("http://www.google.com/"); + form_one.username_value = ASCIIToUTF16("username"); + form_one.password_value = ASCIIToUTF16("one"); + AddLogin(GetPasswordStore(1), form_one); + + EXPECT_TRUE(ProfileSyncServiceTestHarness::AwaitQuiescence(clients())); + + std::vector actual_zero; + GetLogins(GetPasswordStore(0), form, actual_zero); + EXPECT_EQ(1U, actual_zero.size()); + + std::vector actual_one; + GetLogins(GetPasswordStore(1), form, actual_one); + EXPECT_EQ(1U, actual_one.size()); + + EXPECT_TRUE(ContainsSamePasswordForms(actual_zero, actual_one)); +} -- cgit v1.1