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

Unified Diff: chrome/browser/importer/firefox_importer_unittest_utils_mac.cc

Issue 174259: Recommit "Bring up Firefox Password Import Unittest on OS X." (Closed)
Patch Set: Created 11 years, 4 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
Index: chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
diff --git a/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d44b3369ad4ae2b5420102a7b75fa99f5f0e306d
--- /dev/null
+++ b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2009 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/importer/firefox_importer_unittest_utils.h"
+
+#include "base/command_line.h"
+#include "base/debug_on_start.h"
+#include "base/file_path.h"
+#include "base/message_loop.h"
+#include "chrome/browser/importer/firefox_importer_utils.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_descriptors.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_switches.h"
+#include "testing/multiprocess_func_list.h"
+
+// Definition of IPC Messages used for this test.
+#define MESSAGES_INTERNAL_FILE \
+ "chrome/browser/importer/firefox_importer_unittest_messages_internal.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace {
+
+// Name of IPC Channel to use for Server<-> Child Communications.
+const char kTestChannelID[] = "T1";
+
+// Launch the child process:
+// |nss_path| - path to the NSS directory holding the decryption libraries.
+// |channel| - IPC Channel to use for communication.
+// |handle| - On return, the process handle to use to communicate with the
+// child.
+bool LaunchNSSDecrypterChildProcess(const std::wstring& nss_path,
+ const IPC::Channel& channel, base::ProcessHandle* handle) {
+ CommandLine cl(*CommandLine::ForCurrentProcess());
+ cl.AppendSwitchWithValue(L"client", L"NSSDecrypterChildProcess");
+
+ FilePath ff_dylib_dir = FilePath::FromWStringHack(nss_path);
+ // Set env variable needed for FF encryption libs to load.
+ // See "chrome/browser/importer/nss_decryptor_mac.mm" for an explanation of
+ // why we need this.
+ base::environment_vector env;
+ std::pair<const char*,const char*> dyld_override;
+ dyld_override.first = "DYLD_FALLBACK_LIBRARY_PATH";
+ dyld_override.second = ff_dylib_dir.value().c_str();
+ env.push_back(dyld_override);
+
+ base::file_handle_mapping_vector fds_to_map;
+ const int ipcfd = channel.GetClientFileDescriptor();
+ if (ipcfd > -1) {
+ fds_to_map.push_back(std::pair<int,int>(ipcfd, kPrimaryIPCChannel + 3));
+ } else {
+ return false;
+ }
+
+ bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDebugChildren);
+ return base::LaunchApp(cl.argv(), env, fds_to_map, debug_on_start,
+ handle);
+}
+
+} // namespace
+
+//----------------------- Server --------------------
+
+// Class to communicate on the server side of the IPC Channel.
+// Method calls are sent over IPC and replies are read back into class
+// variables.
+// This class needs to be called on a single thread.
+class FFDecryptorServerChannelListener : public IPC::Channel::Listener {
+ public:
+ FFDecryptorServerChannelListener()
+ : got_result(false), sender_(NULL) {}
+
+ void SetSender(IPC::Message::Sender* sender) {
+ sender_ = sender;
+ }
+
+ void OnInitDecryptorResponse(bool result) {
+ DCHECK(!got_result);
+ result_bool = result;
+ got_result = true;
+ MessageLoop::current()->Quit();
+ }
+
+ void OnDecryptedTextResonse(std::wstring decrypted_text) {
+ DCHECK(!got_result);
+ result_string = decrypted_text;
+ got_result = true;
+ MessageLoop::current()->Quit();
+ }
+
+ void QuitClient() {
+ if (sender_)
+ sender_->Send(new Msg_Decryptor_Quit());
+ }
+
+ virtual void OnMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(FFDecryptorServerChannelListener, msg)
+ IPC_MESSAGE_HANDLER(Msg_Decryptor_InitReturnCode, OnInitDecryptorResponse)
+ IPC_MESSAGE_HANDLER(Msg_Decryptor_Response, OnDecryptedTextResonse)
+ IPC_END_MESSAGE_MAP()
+ }
+
+ // If an error occured, just kill the message Loop.
+ virtual void OnChannelError() {
+ got_result = false;
+ MessageLoop::current()->Quit();
+ }
+
+ // Results of IPC calls.
+ std::wstring result_string;
+ bool result_bool;
+ // True if IPC call succeeded and data in above variables is valid.
+ bool got_result;
+
+ private:
+ IPC::Message::Sender* sender_; // weak
+};
+
+FFUnitTestDecryptorProxy::FFUnitTestDecryptorProxy()
+ : child_process_(0) {
+}
+
+bool FFUnitTestDecryptorProxy::Setup(std::wstring& nss_path) {
+ // Create a new message loop and spawn the child process.
+ message_loop_.reset(new MessageLoopForIO());
+
+ listener_.reset(new FFDecryptorServerChannelListener());
+ channel_.reset(new IPC::Channel(kTestChannelID,
+ IPC::Channel::MODE_SERVER,
+ listener_.get()));
+ channel_->Connect();
+ listener_->SetSender(channel_.get());
+
+ // Spawn child and set up sync IPC connection.
+ bool ret = LaunchNSSDecrypterChildProcess(nss_path,
+ *(channel_.get()),
+ &child_process_);
+ return ret && (child_process_ != 0);
+}
+
+FFUnitTestDecryptorProxy::~FFUnitTestDecryptorProxy() {
+ listener_->QuitClient();
+ channel_->Close();
+
+ if (child_process_) {
+ base::WaitForSingleProcess(child_process_, 5000);
+ base::CloseProcessHandle(child_process_);
+ }
+}
+
+// A message_loop task that quits the message loop when invoked, setting cancel
+// causes the task to do nothing when invoked.
+class CancellableQuitMsgLoop : public base::RefCounted<CancellableQuitMsgLoop> {
+ public:
+ CancellableQuitMsgLoop() : cancelled_(false) {}
+ void QuitNow() {
+ if (!cancelled_)
+ MessageLoop::current()->Quit();
+ }
+ bool cancelled_;
+};
+
+// Spin until either a client response arrives or a timeout occurs.
+bool FFUnitTestDecryptorProxy::WaitForClientResponse() {
+ const int64 kLoopTimeoutMS = 10 * 1000; // 10 seconds.
+
+ // What we're trying to do here is to wait for an RPC message to go over the
+ // wire and the client to reply. If the client does not replyy by a given
+ // timeout we kill the message loop.
+ // The way we do this is to post a CancellableQuitMsgLoop for 3 seconds in
+ // the future and cancel it if an RPC message comes back earlier.
+ // This relies on the IPC listener class to quit the message loop itself when
+ // a message comes in.
+ scoped_refptr<CancellableQuitMsgLoop> quit_task =
+ new CancellableQuitMsgLoop();
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+ quit_task.get(), &CancellableQuitMsgLoop::QuitNow), kLoopTimeoutMS);
+
+ message_loop_->Run();
+ bool ret = !quit_task->cancelled_;
+ quit_task->cancelled_ = false;
+ return ret;
+}
+
+bool FFUnitTestDecryptorProxy::DecryptorInit(const std::wstring& dll_path,
+ const std::wstring& db_path) {
+ channel_->Send(new Msg_Decryptor_Init(dll_path, db_path));
+ bool ok = WaitForClientResponse();
+ if (ok && listener_->got_result) {
+ listener_->got_result = false;
+ return listener_->result_bool;
+ }
+ return false;
+}
+
+std::wstring FFUnitTestDecryptorProxy::Decrypt(const std::string& crypt) {
+ channel_->Send(new Msg_Decrypt(crypt));
+ bool ok = WaitForClientResponse();
+ if (ok && listener_->got_result) {
+ listener_->got_result = false;
+ return listener_->result_string;
+ }
+ return L"";
+}
+
+//---------------------------- Child Process -----------------------
+
+// Class to listen on the client side of the ipc channel, it calls through
+// to the NSSDecryptor and sends back a reply.
+class FFDecryptorClientChannelListener : public IPC::Channel::Listener {
+ public:
+ FFDecryptorClientChannelListener()
+ : sender_(NULL) {}
+
+ void SetSender(IPC::Message::Sender* sender) {
+ sender_ = sender;
+ }
+
+ void OnDecryptor_Init(std::wstring dll_path, std::wstring db_path) {
+ bool ret = decryptor_.Init(dll_path, db_path);
+ sender_->Send(new Msg_Decryptor_InitReturnCode(ret));
+ }
+
+ void OnDecrypt(std::string crypt) {
+ std::wstring unencrypted_str = decryptor_.Decrypt(crypt);
+ sender_->Send(new Msg_Decryptor_Response(unencrypted_str));
+ }
+
+ void OnQuitRequest() {
+ MessageLoop::current()->Quit();
+ }
+
+ virtual void OnMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(FFDecryptorClientChannelListener, msg)
+ IPC_MESSAGE_HANDLER(Msg_Decryptor_Init, OnDecryptor_Init)
+ IPC_MESSAGE_HANDLER(Msg_Decrypt, OnDecrypt)
+ IPC_MESSAGE_HANDLER(Msg_Decryptor_Quit, OnQuitRequest)
+ IPC_END_MESSAGE_MAP()
+ }
+
+ virtual void OnChannelError() {
+ MessageLoop::current()->Quit();
+ }
+
+ private:
+ NSSDecryptor decryptor_;
+ IPC::Message::Sender* sender_;
+};
+
+// Entry function in child process.
+MULTIPROCESS_TEST_MAIN(NSSDecrypterChildProcess) {
+ MessageLoopForIO main_message_loop;
+ FFDecryptorClientChannelListener listener;
+
+ IPC::Channel channel(kTestChannelID, IPC::Channel::MODE_CLIENT, &listener);
+ channel.Connect();
+ listener.SetSender(&channel);
+
+ // run message loop
+ MessageLoop::current()->Run();
+
+ return 0;
+}
« no previous file with comments | « chrome/browser/importer/firefox_importer_unittest_utils.h ('k') | chrome/browser/importer/firefox_importer_utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698