This source file includes following definitions.
- LaunchNSSDecrypterChildProcess
- sender_
- SetSender
- OnInitDecryptorResponse
- OnDecryptedTextResonse
- QuitClient
- OnMessageReceived
- OnChannelError
- Setup
- QuitNow
- WaitForClientResponse
- DecryptorInit
- SetSender
- OnDecryptor_Init
- OnDecrypt
- OnQuitRequest
- OnMessageReceived
- OnChannelError
- MULTIPROCESS_IPC_TEST_MAIN
#include "chrome/utility/importer/firefox_importer_unittest_utils.h"
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/global_descriptors.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/test/test_timeouts.h"
#include "chrome/common/importer/firefox_importer_utils.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_multiprocess_test.h"
#include "ipc/ipc_switches.h"
#include "testing/multiprocess_func_list.h"
#define IPC_MESSAGE_IMPL
#include "chrome/utility/importer/firefox_importer_unittest_messages_internal.h"
namespace {
const char kTestChannelID[] = "T1";
bool LaunchNSSDecrypterChildProcess(const base::FilePath& nss_path,
IPC::Channel* channel, base::ProcessHandle* handle) {
CommandLine cl(*CommandLine::ForCurrentProcess());
cl.AppendSwitchASCII(switches::kTestChildProcess, "NSSDecrypterChildProcess");
base::LaunchOptions options;
options.environ["DYLD_FALLBACK_LIBRARY_PATH"] = nss_path.value();
base::ScopedFD ipcfd(channel->TakeClientFileDescriptor());
if (!ipcfd.is_valid())
return false;
base::FileHandleMappingVector fds_to_map;
fds_to_map.push_back(std::pair<int,int>(ipcfd.get(),
kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDebugChildren);
options.fds_to_remap = &fds_to_map;
options.wait = debug_on_start;
return base::LaunchProcess(cl.argv(), options, handle);
}
}
class FFDecryptorServerChannelListener : public IPC::Listener {
public:
FFDecryptorServerChannelListener()
: got_result(false), sender_(NULL) {}
void SetSender(IPC::Sender* sender) {
sender_ = sender;
}
void OnInitDecryptorResponse(bool result) {
DCHECK(!got_result);
result_bool = result;
got_result = true;
base::MessageLoop::current()->Quit();
}
void OnDecryptedTextResonse(const base::string16& decrypted_text) {
DCHECK(!got_result);
result_string = decrypted_text;
got_result = true;
base::MessageLoop::current()->Quit();
}
void QuitClient() {
if (sender_)
sender_->Send(new Msg_Decryptor_Quit());
}
virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(FFDecryptorServerChannelListener, msg)
IPC_MESSAGE_HANDLER(Msg_Decryptor_InitReturnCode, OnInitDecryptorResponse)
IPC_MESSAGE_HANDLER(Msg_Decryptor_Response, OnDecryptedTextResonse)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
virtual void OnChannelError() OVERRIDE {
got_result = false;
base::MessageLoop::current()->Quit();
}
base::string16 result_string;
bool result_bool;
bool got_result;
private:
IPC::Sender* sender_;
};
FFUnitTestDecryptorProxy::FFUnitTestDecryptorProxy()
: child_process_(0) {
}
bool FFUnitTestDecryptorProxy::Setup(const base::FilePath& nss_path) {
message_loop_.reset(new base::MessageLoopForIO());
listener_.reset(new FFDecryptorServerChannelListener());
channel_.reset(new IPC::Channel(kTestChannelID,
IPC::Channel::MODE_SERVER,
listener_.get()));
CHECK(channel_->Connect());
listener_->SetSender(channel_.get());
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_, base::TimeDelta::FromSeconds(5));
base::CloseProcessHandle(child_process_);
}
}
class CancellableQuitMsgLoop : public base::RefCounted<CancellableQuitMsgLoop> {
public:
CancellableQuitMsgLoop() : cancelled_(false) {}
void QuitNow() {
if (!cancelled_)
base::MessageLoop::current()->Quit();
}
bool cancelled_;
private:
friend class base::RefCounted<CancellableQuitMsgLoop>;
~CancellableQuitMsgLoop() {}
};
bool FFUnitTestDecryptorProxy::WaitForClientResponse() {
scoped_refptr<CancellableQuitMsgLoop> quit_task(
new CancellableQuitMsgLoop());
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&CancellableQuitMsgLoop::QuitNow, quit_task.get()),
TestTimeouts::action_max_timeout());
message_loop_->Run();
bool ret = !quit_task->cancelled_;
quit_task->cancelled_ = false;
return ret;
}
bool FFUnitTestDecryptorProxy::DecryptorInit(const base::FilePath& dll_path,
const base::FilePath& 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;
}
base::string16 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 base::string16();
}
class FFDecryptorClientChannelListener : public IPC::Listener {
public:
FFDecryptorClientChannelListener()
: sender_(NULL) {}
void SetSender(IPC::Sender* sender) {
sender_ = sender;
}
void OnDecryptor_Init(base::FilePath dll_path, base::FilePath db_path) {
bool ret = decryptor_.Init(dll_path, db_path);
sender_->Send(new Msg_Decryptor_InitReturnCode(ret));
}
void OnDecrypt(std::string crypt) {
base::string16 unencrypted_str = decryptor_.Decrypt(crypt);
sender_->Send(new Msg_Decryptor_Response(unencrypted_str));
}
void OnQuitRequest() {
base::MessageLoop::current()->Quit();
}
virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
bool handled = true;
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_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
virtual void OnChannelError() OVERRIDE {
base::MessageLoop::current()->Quit();
}
private:
NSSDecryptor decryptor_;
IPC::Sender* sender_;
};
MULTIPROCESS_IPC_TEST_MAIN(NSSDecrypterChildProcess) {
base::MessageLoopForIO main_message_loop;
FFDecryptorClientChannelListener listener;
IPC::Channel channel(kTestChannelID, IPC::Channel::MODE_CLIENT, &listener);
CHECK(channel.Connect());
listener.SetSender(&channel);
base::MessageLoop::current()->Run();
return 0;
}