Index: chrome/browser/password_manager/native_backend_gnome_x_unittest.cc |
=================================================================== |
--- chrome/browser/password_manager/native_backend_gnome_x_unittest.cc (revision 0) |
+++ chrome/browser/password_manager/native_backend_gnome_x_unittest.cc (revision 0) |
@@ -0,0 +1,767 @@ |
+// Copyright (c) 2011 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 <stdarg.h> |
+ |
+#include "base/basictypes.h" |
+#include "base/stl_util-inl.h" |
+#include "base/string_util.h" |
+#include "base/time.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/password_manager/native_backend_gnome_x.h" |
+#include "chrome/browser/prefs/pref_service.h" |
+#include "chrome/common/pref_names.h" |
+#include "chrome/test/testing_profile.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using webkit_glue::PasswordForm; |
+ |
+namespace { |
+ |
+// What follows is a very simple implementation of the subset of the GNOME |
+// Keyring API that we actually use. It gets substituted for the real one by |
+// MockGnomeKeyringLoader, which hooks into the facility normally used to load |
+// the GNOME Keyring library at runtime to avoid a static dependency on it. |
+ |
+struct MockKeyringItem { |
+ MockKeyringItem() {} |
+ MockKeyringItem(const char* keyring, |
+ const std::string& display_name, |
+ const std::string& password) |
+ : keyring(keyring ? keyring : "login"), |
+ display_name(display_name), |
+ password(password) {} |
+ |
+ struct ItemAttribute { |
+ ItemAttribute() : type(UINT32), value_uint32(0) {} |
+ explicit ItemAttribute(uint32_t value) |
+ : type(UINT32), value_uint32(value) {} |
+ explicit ItemAttribute(const std::string& value) |
+ : type(STRING), value_string(value) {} |
+ |
+ bool Equals(const ItemAttribute& x) const { |
+ if (type != x.type) return false; |
+ return (type == STRING) ? value_string == x.value_string |
+ : value_uint32 == x.value_uint32; |
+ } |
+ |
+ enum { UINT32, STRING } type; |
+ uint32_t value_uint32; |
+ std::string value_string; |
+ }; |
+ |
+ typedef std::map<std::string, ItemAttribute> attribute_map; |
+ typedef std::vector<std::pair<std::string, ItemAttribute> > attribute_query; |
+ |
+ bool Matches(const attribute_query& query) const { |
+ // The real GNOME Keyring doesn't match empty queries. |
+ if (query.empty()) return false; |
+ for (size_t i = 0; i < query.size(); ++i) { |
+ attribute_map::const_iterator match = attributes.find(query[i].first); |
+ if (match == attributes.end()) return false; |
+ if (!match->second.Equals(query[i].second)) return false; |
+ } |
+ return true; |
+ } |
+ |
+ std::string keyring; |
+ std::string display_name; |
+ std::string password; |
+ |
+ attribute_map attributes; |
+}; |
+ |
+// The list of all keyring items we have stored. |
+std::vector<MockKeyringItem> mock_keyring_items; |
+bool mock_keyring_reject_local_ids = false; |
+ |
+bool IsStringAttribute(const GnomeKeyringPasswordSchema* schema, |
+ const std::string& name) { |
+ for (size_t i = 0; schema->attributes[i].name; ++i) |
+ if (name == schema->attributes[i].name) |
+ return schema->attributes[i].type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING; |
+ NOTREACHED() << "Requested type of nonexistent attribute"; |
+ return false; |
+} |
+ |
+gboolean mock_gnome_keyring_is_available() { |
+ return true; |
+} |
+ |
+gpointer mock_gnome_keyring_store_password( |
+ const GnomeKeyringPasswordSchema* schema, |
+ const gchar* keyring, |
+ const gchar* display_name, |
+ const gchar* password, |
+ GnomeKeyringOperationDoneCallback callback, |
+ gpointer data, |
+ GDestroyNotify destroy_data, |
+ ...) { |
+ mock_keyring_items.push_back( |
+ MockKeyringItem(keyring, display_name, password)); |
+ MockKeyringItem* item = &mock_keyring_items.back(); |
+ const std::string keyring_desc = keyring ? StringPrintf("keyring %s", keyring) |
+ : std::string("default keyring"); |
+ VLOG(1) << "Adding item with origin " << display_name |
+ << " to " << keyring_desc; |
+ va_list ap; |
+ va_start(ap, destroy_data); |
+ char* name; |
+ while ((name = va_arg(ap, gchar*))) { |
+ if (IsStringAttribute(schema, name)) { |
+ item->attributes[name] = |
+ MockKeyringItem::ItemAttribute(va_arg(ap, gchar*)); |
+ VLOG(1) << "Adding item attribute " << name |
+ << ", value '" << item->attributes[name].value_string << "'"; |
+ } else { |
+ item->attributes[name] = |
+ MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t)); |
+ VLOG(1) << "Adding item attribute " << name |
+ << ", value " << item->attributes[name].value_uint32; |
+ } |
+ } |
+ va_end(ap); |
+ // As a hack to ease testing migration, make it possible to reject the new |
+ // format for the app string. This way we can add them easily to migrate. |
+ if (mock_keyring_reject_local_ids) { |
+ MockKeyringItem::attribute_map::iterator it = |
+ item->attributes.find("application"); |
+ if (it != item->attributes.end() && |
+ it->second.type == MockKeyringItem::ItemAttribute::STRING && |
+ base::StringPiece(it->second.value_string).starts_with("chrome-")) { |
+ mock_keyring_items.pop_back(); |
+ // GnomeKeyringResult, data |
+ callback(GNOME_KEYRING_RESULT_IO_ERROR, data); |
+ return NULL; |
+ } |
+ } |
+ // GnomeKeyringResult, data |
+ callback(GNOME_KEYRING_RESULT_OK, data); |
+ return NULL; |
+} |
+ |
+gpointer mock_gnome_keyring_delete_password( |
+ const GnomeKeyringPasswordSchema* schema, |
+ GnomeKeyringOperationDoneCallback callback, |
+ gpointer data, |
+ GDestroyNotify destroy_data, |
+ ...) { |
+ MockKeyringItem::attribute_query query; |
+ va_list ap; |
+ va_start(ap, destroy_data); |
+ char* name; |
+ while ((name = va_arg(ap, gchar*))) { |
+ if (IsStringAttribute(schema, name)) { |
+ query.push_back(make_pair(std::string(name), |
+ MockKeyringItem::ItemAttribute(va_arg(ap, gchar*)))); |
+ VLOG(1) << "Querying with item attribute " << name |
+ << ", value '" << query.back().second.value_string << "'"; |
+ } else { |
+ query.push_back(make_pair(std::string(name), |
+ MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t)))); |
+ VLOG(1) << "Querying with item attribute " << name |
+ << ", value " << query.back().second.value_uint32; |
+ } |
+ } |
+ va_end(ap); |
+ bool deleted = false; |
+ for (size_t i = mock_keyring_items.size(); i > 0; --i) { |
+ const MockKeyringItem* item = &mock_keyring_items[i - 1]; |
+ if (item->Matches(query)) { |
+ VLOG(1) << "Deleting item with origin " << item->display_name; |
+ mock_keyring_items.erase(mock_keyring_items.begin() + (i - 1)); |
+ deleted = true; |
+ } |
+ } |
+ // GnomeKeyringResult, data |
+ callback(deleted ? GNOME_KEYRING_RESULT_OK |
+ : GNOME_KEYRING_RESULT_NO_MATCH, data); |
+ return NULL; |
+} |
+ |
+gpointer mock_gnome_keyring_find_itemsv( |
+ GnomeKeyringItemType type, |
+ GnomeKeyringOperationGetListCallback callback, |
+ gpointer data, |
+ GDestroyNotify destroy_data, |
+ ...) { |
+ MockKeyringItem::attribute_query query; |
+ va_list ap; |
+ va_start(ap, destroy_data); |
+ char* name; |
+ while ((name = va_arg(ap, gchar*))) { |
+ // Really a GnomeKeyringAttributeType, but promoted to int through ... |
+ if (va_arg(ap, int) == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) { |
+ query.push_back(make_pair(std::string(name), |
+ MockKeyringItem::ItemAttribute(va_arg(ap, gchar*)))); |
+ VLOG(1) << "Querying with item attribute " << name |
+ << ", value '" << query.back().second.value_string << "'"; |
+ } else { |
+ query.push_back(make_pair(std::string(name), |
+ MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t)))); |
+ VLOG(1) << "Querying with item attribute " << name |
+ << ", value " << query.back().second.value_uint32; |
+ } |
+ } |
+ va_end(ap); |
+ // Find matches and add them to a list of results. |
+ GList* results = NULL; |
+ for (size_t i = 0; i < mock_keyring_items.size(); ++i) { |
+ const MockKeyringItem* item = &mock_keyring_items[i]; |
+ if (item->Matches(query)) { |
+ GnomeKeyringFound* found = new GnomeKeyringFound; |
+ found->keyring = strdup(item->keyring.c_str()); |
+ found->item_id = i; |
+ found->attributes = gnome_keyring_attribute_list_new(); |
+ for (MockKeyringItem::attribute_map::const_iterator it = |
+ item->attributes.begin(); |
+ it != item->attributes.end(); |
+ ++it) { |
+ if (it->second.type == MockKeyringItem::ItemAttribute::STRING) { |
+ gnome_keyring_attribute_list_append_string( |
+ found->attributes, it->first.c_str(), |
+ it->second.value_string.c_str()); |
+ } else { |
+ gnome_keyring_attribute_list_append_uint32( |
+ found->attributes, it->first.c_str(), |
+ it->second.value_uint32); |
+ } |
+ } |
+ found->secret = strdup(item->password.c_str()); |
+ results = g_list_prepend(results, found); |
+ } |
+ } |
+ // GnomeKeyringResult, GList*, data |
+ callback(results ? GNOME_KEYRING_RESULT_OK |
+ : GNOME_KEYRING_RESULT_NO_MATCH, results, data); |
+ // Now free the list of results. |
+ GList* element = g_list_first(results); |
+ while (element) { |
+ GnomeKeyringFound* found = static_cast<GnomeKeyringFound*>(element->data); |
+ free(found->keyring); |
+ gnome_keyring_attribute_list_free(found->attributes); |
+ free(found->secret); |
+ element = g_list_next(element); |
+ } |
+ g_list_free(results); |
+ return NULL; |
+} |
+ |
+const gchar* mock_gnome_keyring_result_to_message(GnomeKeyringResult res) { |
+ return "mock keyring simulating failure"; |
+} |
+ |
+// Inherit to get access to protected fields. |
+class MockGnomeKeyringLoader : public GnomeKeyringLoader { |
+ public: |
+ static bool LoadMockGnomeKeyring() { |
+#define GNOME_KEYRING_ASSIGN_POINTER(name) \ |
+ gnome_keyring_##name = &mock_gnome_keyring_##name; |
+ GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_ASSIGN_POINTER) |
+#undef GNOME_KEYRING_ASSIGN_POINTER |
+ keyring_loaded = true; |
+ // Reset the state of the mock library. |
+ mock_keyring_items.clear(); |
+ mock_keyring_reject_local_ids = false; |
+ return true; |
+ } |
+}; |
+ |
+} // anonymous namespace |
+ |
+// NativeBackendGnome isn't reference counted, but in these unit tests that |
+// won't be a problem as it always outlives the threads we post tasks to. |
+template<> |
+struct RunnableMethodTraits<NativeBackendGnome> { |
+ void RetainCallee(NativeBackendGnome*) {} |
+ void ReleaseCallee(NativeBackendGnome*) {} |
+}; |
+ |
+class NativeBackendGnomeTest : public testing::Test { |
+ protected: |
+ NativeBackendGnomeTest() |
+ : ui_thread_(BrowserThread::UI, &message_loop_), |
+ db_thread_(BrowserThread::DB) { |
+ } |
+ |
+ virtual void SetUp() { |
+ ASSERT_TRUE(db_thread_.Start()); |
+ |
+ MockGnomeKeyringLoader::LoadMockGnomeKeyring(); |
+ profile_.reset(new TestingProfile()); |
+ |
+ form_google_.origin = GURL("http://www.google.com/"); |
+ form_google_.action = GURL("http://www.google.com/login"); |
+ form_google_.username_element = UTF8ToUTF16("user"); |
+ form_google_.username_value = UTF8ToUTF16("joeschmoe"); |
+ form_google_.password_element = UTF8ToUTF16("pass"); |
+ form_google_.password_value = UTF8ToUTF16("seekrit"); |
+ form_google_.submit_element = UTF8ToUTF16("submit"); |
+ form_google_.signon_realm = "Google"; |
+ |
+ form_isc_.origin = GURL("http://www.isc.org/"); |
+ form_isc_.action = GURL("http://www.isc.org/auth"); |
+ form_isc_.username_element = UTF8ToUTF16("id"); |
+ form_isc_.username_value = UTF8ToUTF16("janedoe"); |
+ form_isc_.password_element = UTF8ToUTF16("passwd"); |
+ form_isc_.password_value = UTF8ToUTF16("ihazabukkit"); |
+ form_isc_.submit_element = UTF8ToUTF16("login"); |
+ form_isc_.signon_realm = "ISC"; |
+ } |
+ |
+ virtual void TearDown() { |
+ MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); |
+ MessageLoop::current()->Run(); |
+ db_thread_.Stop(); |
+ } |
+ |
+ void RunBothThreads() { |
+ // First we post a message to the DB thread that will run after all other |
+ // messages that have been posted to the DB thread (we don't expect more |
+ // to be posted), which posts a message to the UI thread to quit the loop. |
+ // That way we can run both loops and be sure that the UI thread loop will |
+ // quit so we can get on with the rest of the test. |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableFunction(&PostQuitTask, &message_loop_)); |
+ MessageLoop::current()->Run(); |
+ } |
+ |
+ static void PostQuitTask(MessageLoop* loop) { |
+ loop->PostTask(FROM_HERE, new MessageLoop::QuitTask); |
+ } |
+ |
+ void CheckUint32Attribute(const MockKeyringItem* item, |
+ const std::string& attribute, |
+ uint32_t value) { |
+ MockKeyringItem::attribute_map::const_iterator it = |
+ item->attributes.find(attribute); |
+ EXPECT_NE(item->attributes.end(), it); |
+ if (it != item->attributes.end()) { |
+ EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type); |
+ EXPECT_EQ(value, it->second.value_uint32); |
+ } |
+ } |
+ |
+ void CheckStringAttribute(const MockKeyringItem* item, |
+ const std::string& attribute, |
+ const std::string& value) { |
+ MockKeyringItem::attribute_map::const_iterator it = |
+ item->attributes.find(attribute); |
+ EXPECT_NE(item->attributes.end(), it); |
+ if (it != item->attributes.end()) { |
+ EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type); |
+ EXPECT_EQ(value, it->second.value_string); |
+ } |
+ } |
+ |
+ void CheckMockKeyringItem(const MockKeyringItem* item, |
+ const PasswordForm& form, |
+ const std::string& app_string) { |
+ // We always add items to the login keyring. |
+ EXPECT_EQ("login", item->keyring); |
+ EXPECT_EQ(form.origin.spec(), item->display_name); |
+ EXPECT_EQ(UTF16ToUTF8(form.password_value), item->password); |
+ EXPECT_EQ(13u, item->attributes.size()); |
+ CheckStringAttribute(item, "origin_url", form.origin.spec()); |
+ CheckStringAttribute(item, "action_url", form.action.spec()); |
+ CheckStringAttribute(item, "username_element", |
+ UTF16ToUTF8(form.username_element)); |
+ CheckStringAttribute(item, "username_value", |
+ UTF16ToUTF8(form.username_value)); |
+ CheckStringAttribute(item, "password_element", |
+ UTF16ToUTF8(form.password_element)); |
+ CheckStringAttribute(item, "submit_element", |
+ UTF16ToUTF8(form.submit_element)); |
+ CheckStringAttribute(item, "signon_realm", form.signon_realm); |
+ CheckUint32Attribute(item, "ssl_valid", form.ssl_valid); |
+ CheckUint32Attribute(item, "preferred", form.preferred); |
+ // We don't check the date created. It varies. |
+ CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user); |
+ CheckUint32Attribute(item, "scheme", form.scheme); |
+ CheckStringAttribute(item, "application", app_string); |
+ } |
+ |
+ MessageLoopForUI message_loop_; |
+ BrowserThread ui_thread_; |
+ BrowserThread db_thread_; |
+ |
+ scoped_ptr<TestingProfile> profile_; |
+ |
+ // Provide some test forms to avoid having to set them up in each test. |
+ PasswordForm form_google_; |
+ PasswordForm form_isc_; |
+}; |
+ |
+TEST_F(NativeBackendGnomeTest, BasicAddLogin) { |
+ // Pretend that the migration has already taken place. |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true); |
+ |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); |
+} |
+ |
+TEST_F(NativeBackendGnomeTest, BasicListLogins) { |
+ // Pretend that the migration has already taken place. |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true); |
+ |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got something back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); |
+} |
+ |
+TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) { |
+ // Pretend that the migration has already taken place. |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true); |
+ |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::RemoveLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ |
+ EXPECT_EQ(0u, mock_keyring_items.size()); |
+} |
+ |
+TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) { |
+ // Pretend that the migration has already taken place. |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true); |
+ |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ // First add an unrelated login. |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); |
+ |
+ // Attempt to remove a login that doesn't exist. |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::RemoveLogin, |
+ form_isc_)); |
+ |
+ // Make sure we can still get the first form back. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got something back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); |
+} |
+ |
+TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) { |
+ // Pretend that the migration has already taken place. |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true); |
+ |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); |
+} |
+ |
+// TODO(mdm): add more basic (i.e. non-migration) tests here at some point. |
+ |
+TEST_F(NativeBackendGnomeTest, MigrateOneLogin) { |
+ // Reject attempts to migrate so we can populate the store. |
+ mock_keyring_reject_local_ids = true; |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ // Make sure we can get the form back even when migration is failing. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got something back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ } |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ |
+ // Now allow the migration. |
+ mock_keyring_reject_local_ids = false; |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ // This should not trigger migration because there will be no results. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetBlacklistLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Check that we got nothing back. |
+ EXPECT_EQ(0u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ } |
+ |
+ // Check that the keyring is unmodified. |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ |
+ // Check that we haven't set the persistent preference. |
+ EXPECT_FALSE( |
+ profile_->GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId)); |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ // Trigger the migration by looking something up. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got something back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ } |
+ |
+ EXPECT_EQ(2u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ if (mock_keyring_items.size() > 1) |
+ CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42"); |
+ |
+ // Check that we have set the persistent preference. |
+ EXPECT_TRUE( |
+ profile_->GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId)); |
+} |
+ |
+TEST_F(NativeBackendGnomeTest, MigrateToMultipleProfiles) { |
+ // Reject attempts to migrate so we can populate the store. |
+ mock_keyring_reject_local_ids = true; |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ } |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ |
+ // Now allow the migration. |
+ mock_keyring_reject_local_ids = false; |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ // Trigger the migration by looking something up. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got something back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ } |
+ |
+ EXPECT_EQ(2u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ if (mock_keyring_items.size() > 1) |
+ CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42"); |
+ |
+ // Check that we have set the persistent preference. |
+ EXPECT_TRUE( |
+ profile_->GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId)); |
+ |
+ // Normally we'd actually have a different profile. But in the test just reset |
+ // the profile's persistent pref; we pass in the local profile id anyway. |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false); |
+ |
+ { |
+ NativeBackendGnome backend(24, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ // Trigger the migration by looking something up. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got something back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ STLDeleteElements(&form_list); |
+ } |
+ |
+ EXPECT_EQ(3u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ if (mock_keyring_items.size() > 1) |
+ CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42"); |
+ if (mock_keyring_items.size() > 2) |
+ CheckMockKeyringItem(&mock_keyring_items[2], form_google_, "chrome-24"); |
+} |
+ |
+TEST_F(NativeBackendGnomeTest, NoMigrationWithPrefSet) { |
+ // Reject attempts to migrate so we can populate the store. |
+ mock_keyring_reject_local_ids = true; |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_google_)); |
+ |
+ RunBothThreads(); |
+ } |
+ |
+ EXPECT_EQ(1u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ |
+ // Now allow migration, but also pretend that the it has already taken place. |
+ mock_keyring_reject_local_ids = false; |
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true); |
+ |
+ { |
+ NativeBackendGnome backend(42, profile_->GetPrefs()); |
+ backend.Init(); |
+ |
+ // Trigger the migration by adding a new login. |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::AddLogin, |
+ form_isc_)); |
+ |
+ // Look up all logins; we expect only the one we added. |
+ std::vector<PasswordForm*> form_list; |
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, |
+ NewRunnableMethod(&backend, |
+ &NativeBackendGnome::GetAutofillableLogins, |
+ &form_list)); |
+ |
+ RunBothThreads(); |
+ |
+ // Quick check that we got the right thing back. |
+ EXPECT_EQ(1u, form_list.size()); |
+ if (form_list.size() > 0) |
+ EXPECT_EQ(form_isc_.signon_realm, form_list[0]->signon_realm); |
+ STLDeleteElements(&form_list); |
+ } |
+ |
+ EXPECT_EQ(2u, mock_keyring_items.size()); |
+ if (mock_keyring_items.size() > 0) |
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome"); |
+ if (mock_keyring_items.size() > 1) |
+ CheckMockKeyringItem(&mock_keyring_items[1], form_isc_, "chrome-42"); |
+} |
Property changes on: chrome/browser/password_manager/native_backend_gnome_x_unittest.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |