Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Unified Diff: chrome/browser/password_manager/native_backend_gnome_x_unittest.cc

Issue 8509038: Linux: split GNOME Keyring integration into a separate process. Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: merge Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/password_manager/native_backend_gnome_x.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
===================================================================
--- chrome/browser/password_manager/native_backend_gnome_x_unittest.cc (revision 119287)
+++ chrome/browser/password_manager/native_backend_gnome_x_unittest.cc (working copy)
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <stdarg.h>
+#include <sys/socket.h>
#include "base/basictypes.h"
#include "base/stl_util.h"
@@ -10,6 +11,9 @@
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/password_manager/keyring_proxy/gnome_keyring_loader.h"
+#include "chrome/browser/password_manager/keyring_proxy/keyring_proxy.h"
+#include "chrome/browser/password_manager/keyring_proxy/keyring_proxy_client.h"
#include "chrome/browser/password_manager/native_backend_gnome_x.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
@@ -26,6 +30,9 @@
// 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.
+// We also use some special glue code to link directly with the main keyring
+// proxy code and thus call into the mock implementation in this process,
+// rather than in a separate proxy process. (See below.)
struct MockKeyringItem {
MockKeyringItem() {}
@@ -258,7 +265,7 @@
}
// Inherit to get access to protected fields.
-class MockGnomeKeyringLoader : public GnomeKeyringLoader {
+class MockGnomeKeyringLoader : public keyring_proxy::GnomeKeyringLoader {
public:
static bool LoadMockGnomeKeyring() {
#define GNOME_KEYRING_ASSIGN_POINTER(name) \
@@ -271,22 +278,71 @@
mock_keyring_reject_local_ids = false;
return true;
}
+
+ static void ResetGnomeKeyring() { keyring_loaded = false; }
};
+// Now that we can inject a mock GNOME Keyring API, we need to glue the keyring
+// proxy client directly to the proxy code, which is linked into the unit test
+// directly. We do this by creating a socket and giving one end to each, but we
+// need some slightly adapted proxy and proxy client classes to make that work.
+
+class TestKeyringProxy : public keyring_proxy::KeyringProxy {
+ public:
+ explicit TestKeyringProxy(int fd) : KeyringProxy(fd, CreateOutput(fd)) {}
+ ~TestKeyringProxy() { fclose(output_); }
+
+ private:
+ // This is a bit of a hack. We need to do this before calling the constructor
+ // for KeyringProxy, since it needs a FILE*. So we have a member method that
+ // fills in output_ for us before the body of our constructor even runs. It's
+ // safe since there's nothing virtual involved.
+ FILE* CreateOutput(int fd) {
+ int dup_fd = dup(fd);
+ CHECK_GE(dup_fd, 0);
+ output_ = fdopen(dup_fd, "r+");
+ CHECK(output_);
+ return output_;
+ }
+
+ FILE* output_;
+};
+
+class TestKeyringProxyClient : public keyring_proxy::KeyringProxyClient {
+ public:
+ using KeyringProxyClient::ConnectForTesting;
+};
+
+class TestNativeBackendGnome : public NativeBackendGnome {
+ public:
+ using NativeBackendGnome::InitForTesting;
+};
+
} // anonymous namespace
class NativeBackendGnomeTest : public testing::Test {
protected:
NativeBackendGnomeTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
- db_thread_(BrowserThread::DB) {
+ db_thread_(BrowserThread::DB),
+ file_thread_(BrowserThread::FILE) {
}
virtual void SetUp() {
ASSERT_TRUE(db_thread_.Start());
+ ASSERT_TRUE(file_thread_.StartIOThread());
MockGnomeKeyringLoader::LoadMockGnomeKeyring();
+ int fds[2];
+ ASSERT_TRUE(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) >= 0);
+ // Give one side to the proxy itself, which is linked into the unit test.
+ // We won't call its Run() method, but its events will run from the UI
+ // thread's GMainContext automatically. Its Stop() method won't work.
+ proxy_.reset(new TestKeyringProxy(fds[0]));
+ // Save the other side for test proxy clients.
+ proxy_fd_ = fds[1];
+
form_google_.origin = GURL("http://www.google.com/");
form_google_.action = GURL("http://www.google.com/login");
form_google_.username_element = UTF8ToUTF16("user");
@@ -309,10 +365,28 @@
virtual void TearDown() {
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
+ // It is important to close this file descriptor only after finishing
+ // running the UI thread's message loop, or else it will get into an
+ // infinite loop due to the proxy's Stop() method not working with the
+ // way we've linked it directly with the unit test.
+ close(proxy_fd_);
+ file_thread_.Stop();
db_thread_.Stop();
+ // Reset keyring_loaded to false in case other tests use it. We don't want
+ // them to use our mock library accidentally.
+ MockGnomeKeyringLoader::ResetGnomeKeyring();
}
- void RunBothThreads() {
+ void InitNativeBackend(NativeBackendGnome* backend) {
+ int fd = dup(proxy_fd_);
+ ASSERT_GE(fd, 0);
+ TestKeyringProxyClient* client = new TestKeyringProxyClient;
+ client->ConnectForTesting(fd, true);
+ // The cast is safe because all it does is change protection.
+ static_cast<TestNativeBackendGnome*>(backend)->InitForTesting(client);
+ }
+
+ void RunAllThreads() {
// 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.
@@ -381,9 +455,17 @@
MessageLoopForUI message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread db_thread_;
+ content::TestBrowserThread file_thread_;
TestingProfile profile_;
+ // By its very existence, the test proxy integrates with the UI thread's
+ // message loop (via GMainContext). We don't need to access it explicitly.
+ scoped_ptr<TestKeyringProxy> proxy_;
+ // This is the file descriptor connected to the proxy, suitable for dup()ing
+ // and using to construct TestKeyringProxyClients.
+ int proxy_fd_;
+
// Provide some test forms to avoid having to set them up in each test.
PasswordForm form_google_;
PasswordForm form_isc_;
@@ -394,14 +476,14 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -413,7 +495,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
@@ -427,7 +509,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -443,14 +525,14 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -461,7 +543,7 @@
base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(0u, mock_keyring_items.size());
}
@@ -471,7 +553,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// First add an unrelated login.
BrowserThread::PostTask(
@@ -479,7 +561,7 @@
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -499,7 +581,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -515,7 +597,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
@@ -526,7 +608,7 @@
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -538,7 +620,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
@@ -558,7 +640,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got two results back.
EXPECT_EQ(2u, form_list.size());
@@ -577,7 +659,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
@@ -591,7 +673,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -607,7 +689,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// This should not trigger migration because there will be no results.
std::vector<PasswordForm*> form_list;
@@ -616,7 +698,7 @@
base::Bind(base::IgnoreResult(&NativeBackendGnome::GetBlacklistLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Check that we got nothing back.
EXPECT_EQ(0u, form_list.size());
@@ -634,7 +716,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -644,7 +726,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -668,14 +750,14 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
}
EXPECT_EQ(1u, mock_keyring_items.size());
@@ -687,7 +769,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -697,7 +779,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -720,7 +802,7 @@
{
NativeBackendGnome backend(24, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -730,7 +812,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -752,14 +834,14 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
}
EXPECT_EQ(1u, mock_keyring_items.size());
@@ -772,7 +854,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by adding a new login.
BrowserThread::PostTask(
@@ -788,7 +870,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got the right thing back.
EXPECT_EQ(1u, form_list.size());
@@ -810,14 +892,14 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(
BrowserThread::DB, FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
}
EXPECT_EQ(1u, mock_keyring_items.size());
@@ -829,7 +911,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -839,7 +921,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -862,7 +944,7 @@
{
NativeBackendGnome backend(24, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -872,7 +954,7 @@
base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
base::Unretained(&backend), &form_list));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -893,7 +975,7 @@
base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
base::Unretained(&backend), form_google_));
- RunBothThreads();
+ RunAllThreads();
// The other two copies of the password in different profiles should remain.
EXPECT_EQ(2u, mock_keyring_items.size());
« no previous file with comments | « chrome/browser/password_manager/native_backend_gnome_x.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698