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

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: everything works Created 9 years, 1 month 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
Index: chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
===================================================================
--- chrome/browser/password_manager/native_backend_gnome_x_unittest.cc (revision 108068)
+++ 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"
@@ -11,6 +12,9 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/native_backend_gnome_x.h"
+#include "chrome/browser/password_manager/proxy/chrome_keyring_proxy.h"
+#include "chrome/browser/password_manager/proxy/chrome_keyring_proxy_client.h"
+#include "chrome/browser/password_manager/proxy/keyring_loader.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
@@ -25,6 +29,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() {}
@@ -272,20 +279,69 @@
}
};
+// 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 TestChromeKeyringProxy : public ChromeKeyringProxy {
+ public:
+ explicit TestChromeKeyringProxy(int fd)
+ : ChromeKeyringProxy(fd, CreateOutput(fd)) {}
+ ~TestChromeKeyringProxy() { fclose(output_); }
+
+ private:
+ // This is a bit of a hack. We need to do this before calling the constructor
+ // for ChromeKeyringProxy, 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 TestChromeKeyringProxyClient : public ChromeKeyringProxyClient {
+ public:
+ using ChromeKeyringProxyClient::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());
+ base::Thread::Options options(MessageLoop::TYPE_IO, 0);
+ ASSERT_TRUE(file_thread_.StartWithOptions(options));
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 TestChromeKeyringProxy(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");
@@ -308,10 +364,25 @@
virtual void TearDown() {
MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
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();
}
- void RunBothThreads() {
+ void InitNativeBackend(NativeBackendGnome* backend) {
+ int fd = dup(proxy_fd_);
+ ASSERT_GE(fd, 0);
+ TestChromeKeyringProxyClient* client = new TestChromeKeyringProxyClient;
+ 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.
@@ -380,9 +451,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<TestChromeKeyringProxy> proxy_;
+ // This is the file descriptor connected to the proxy, suitable for dup()ing
+ // and using to construct TestChromeKeyringProxyClients.
+ int proxy_fd_;
+
// Provide some test forms to avoid having to set them up in each test.
PasswordForm form_google_;
PasswordForm form_isc_;
@@ -393,14 +472,14 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -412,7 +491,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
@@ -425,7 +504,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -441,14 +520,14 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -459,7 +538,7 @@
&NativeBackendGnome::RemoveLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(0u, mock_keyring_items.size());
}
@@ -469,7 +548,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// First add an unrelated login.
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
@@ -477,7 +556,7 @@
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -496,7 +575,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -512,7 +591,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
@@ -523,7 +602,7 @@
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
@@ -535,7 +614,7 @@
profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
@@ -553,7 +632,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got two results back.
EXPECT_EQ(2u, form_list.size());
@@ -572,7 +651,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
@@ -586,7 +665,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -602,7 +681,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;
@@ -611,7 +690,7 @@
&NativeBackendGnome::GetBlacklistLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Check that we got nothing back.
EXPECT_EQ(0u, form_list.size());
@@ -629,7 +708,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -638,7 +717,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -662,14 +741,14 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
}
EXPECT_EQ(1u, mock_keyring_items.size());
@@ -681,7 +760,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -690,7 +769,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -713,7 +792,7 @@
{
NativeBackendGnome backend(24, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -722,7 +801,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -744,14 +823,14 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
}
EXPECT_EQ(1u, mock_keyring_items.size());
@@ -764,7 +843,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by adding a new login.
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
@@ -779,7 +858,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got the right thing back.
EXPECT_EQ(1u, form_list.size());
@@ -801,14 +880,14 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
base::IgnoreReturn<bool>(base::Bind(
&NativeBackendGnome::AddLogin,
base::Unretained(&backend), form_google_)));
- RunBothThreads();
+ RunAllThreads();
}
EXPECT_EQ(1u, mock_keyring_items.size());
@@ -820,7 +899,7 @@
{
NativeBackendGnome backend(42, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -829,7 +908,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -852,7 +931,7 @@
{
NativeBackendGnome backend(24, profile_.GetPrefs());
- backend.Init();
+ InitNativeBackend(&backend);
// Trigger the migration by looking something up.
std::vector<PasswordForm*> form_list;
@@ -861,7 +940,7 @@
&NativeBackendGnome::GetAutofillableLogins,
base::Unretained(&backend), &form_list)));
- RunBothThreads();
+ RunAllThreads();
// Quick check that we got something back.
EXPECT_EQ(1u, form_list.size());
@@ -882,7 +961,7 @@
&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());

Powered by Google App Engine
This is Rietveld 408576698