| 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
|
|
|
|
|