MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / utility / importer / firefox_importer_unittest_utils_mac.cc
blob2ae60eaaadb35b53910baace90dea717c8e8eca3
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/utility/importer/firefox_importer_unittest_utils.h"
7 #include "base/base_switches.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_file.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/posix/global_descriptors.h"
15 #include "base/process/kill.h"
16 #include "base/process/launch.h"
17 #include "base/test/test_timeouts.h"
18 #include "chrome/common/importer/firefox_importer_utils.h"
19 #include "ipc/ipc_channel.h"
20 #include "ipc/ipc_descriptors.h"
21 #include "ipc/ipc_listener.h"
22 #include "ipc/ipc_message.h"
23 #include "ipc/ipc_multiprocess_test.h"
24 #include "testing/multiprocess_func_list.h"
26 #define IPC_MESSAGE_IMPL
27 #include "chrome/utility/importer/firefox_importer_unittest_messages_internal.h"
29 namespace {
31 // Name of IPC Channel to use for Server<-> Child Communications.
32 const char kTestChannelID[] = "T1";
34 // Launch the child process:
35 // |nss_path| - path to the NSS directory holding the decryption libraries.
36 // |channel| - IPC Channel to use for communication.
37 // |handle| - On return, the process handle to use to communicate with the
38 // child.
39 bool LaunchNSSDecrypterChildProcess(const base::FilePath& nss_path,
40 IPC::Channel* channel, base::ProcessHandle* handle) {
41 CommandLine cl(*CommandLine::ForCurrentProcess());
42 cl.AppendSwitchASCII(switches::kTestChildProcess, "NSSDecrypterChildProcess");
44 // Set env variable needed for FF encryption libs to load.
45 // See "chrome/utility/importer/nss_decryptor_mac.mm" for an explanation of
46 // why we need this.
47 base::LaunchOptions options;
48 options.environ["DYLD_FALLBACK_LIBRARY_PATH"] = nss_path.value();
50 base::ScopedFD ipcfd(channel->TakeClientFileDescriptor());
51 if (!ipcfd.is_valid())
52 return false;
54 base::FileHandleMappingVector fds_to_map;
55 fds_to_map.push_back(std::pair<int,int>(ipcfd.get(),
56 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
58 options.fds_to_remap = &fds_to_map;
59 return base::LaunchProcess(cl.argv(), options, handle);
62 } // namespace
64 //----------------------- Server --------------------
66 // Class to communicate on the server side of the IPC Channel.
67 // Method calls are sent over IPC and replies are read back into class
68 // variables.
69 // This class needs to be called on a single thread.
70 class FFDecryptorServerChannelListener : public IPC::Listener {
71 public:
72 FFDecryptorServerChannelListener()
73 : got_result(false), sender_(NULL) {}
75 void SetSender(IPC::Sender* sender) {
76 sender_ = sender;
79 void OnInitDecryptorResponse(bool result) {
80 DCHECK(!got_result);
81 result_bool = result;
82 got_result = true;
83 base::MessageLoop::current()->Quit();
86 void OnDecryptedTextResponse(const base::string16& decrypted_text) {
87 DCHECK(!got_result);
88 result_string = decrypted_text;
89 got_result = true;
90 base::MessageLoop::current()->Quit();
93 void OnParseSignonsResponse(
94 const std::vector<autofill::PasswordForm>& parsed_vector) {
95 DCHECK(!got_result);
96 result_vector = parsed_vector;
97 got_result = true;
98 base::MessageLoop::current()->Quit();
101 void QuitClient() {
102 if (sender_)
103 sender_->Send(new Msg_Decryptor_Quit());
106 bool OnMessageReceived(const IPC::Message& msg) override {
107 bool handled = true;
108 IPC_BEGIN_MESSAGE_MAP(FFDecryptorServerChannelListener, msg)
109 IPC_MESSAGE_HANDLER(Msg_Decryptor_InitReturnCode, OnInitDecryptorResponse)
110 IPC_MESSAGE_HANDLER(Msg_Decryptor_Response, OnDecryptedTextResponse)
111 IPC_MESSAGE_HANDLER(Msg_ParseSignons_Response, OnParseSignonsResponse)
112 IPC_MESSAGE_UNHANDLED(handled = false)
113 IPC_END_MESSAGE_MAP()
114 return handled;
117 // If an error occured, just kill the message Loop.
118 void OnChannelError() override {
119 got_result = false;
120 base::MessageLoop::current()->Quit();
123 // Results of IPC calls.
124 base::string16 result_string;
125 std::vector<autofill::PasswordForm> result_vector;
126 bool result_bool;
127 // True if IPC call succeeded and data in above variables is valid.
128 bool got_result;
130 private:
131 IPC::Sender* sender_; // weak
134 FFUnitTestDecryptorProxy::FFUnitTestDecryptorProxy()
135 : child_process_(0) {
138 bool FFUnitTestDecryptorProxy::Setup(const base::FilePath& nss_path) {
139 // Create a new message loop and spawn the child process.
140 message_loop_.reset(new base::MessageLoopForIO());
142 listener_.reset(new FFDecryptorServerChannelListener());
143 channel_ = IPC::Channel::CreateServer(kTestChannelID, listener_.get());
144 CHECK(channel_->Connect());
145 listener_->SetSender(channel_.get());
147 // Spawn child and set up sync IPC connection.
148 bool ret = LaunchNSSDecrypterChildProcess(nss_path,
149 channel_.get(),
150 &child_process_);
151 return ret && (child_process_ != 0);
154 FFUnitTestDecryptorProxy::~FFUnitTestDecryptorProxy() {
155 listener_->QuitClient();
156 channel_->Close();
158 if (child_process_) {
159 base::WaitForSingleProcess(child_process_, base::TimeDelta::FromSeconds(5));
160 base::CloseProcessHandle(child_process_);
164 // A message_loop task that quits the message loop when invoked, setting cancel
165 // causes the task to do nothing when invoked.
166 class CancellableQuitMsgLoop : public base::RefCounted<CancellableQuitMsgLoop> {
167 public:
168 CancellableQuitMsgLoop() : cancelled_(false) {}
169 void QuitNow() {
170 if (!cancelled_)
171 base::MessageLoop::current()->Quit();
173 bool cancelled_;
175 private:
176 friend class base::RefCounted<CancellableQuitMsgLoop>;
177 ~CancellableQuitMsgLoop() {}
180 // Spin until either a client response arrives or a timeout occurs.
181 bool FFUnitTestDecryptorProxy::WaitForClientResponse() {
182 // What we're trying to do here is to wait for an RPC message to go over the
183 // wire and the client to reply. If the client does not reply by a given
184 // timeout we kill the message loop.
185 // The way we do this is to post a CancellableQuitMsgLoop for 3 seconds in
186 // the future and cancel it if an RPC message comes back earlier.
187 // This relies on the IPC listener class to quit the message loop itself when
188 // a message comes in.
189 scoped_refptr<CancellableQuitMsgLoop> quit_task(
190 new CancellableQuitMsgLoop());
191 base::MessageLoop::current()->PostDelayedTask(
192 FROM_HERE,
193 base::Bind(&CancellableQuitMsgLoop::QuitNow, quit_task.get()),
194 TestTimeouts::action_max_timeout());
196 message_loop_->Run();
197 bool ret = !quit_task->cancelled_;
198 quit_task->cancelled_ = false;
199 return ret;
202 bool FFUnitTestDecryptorProxy::DecryptorInit(const base::FilePath& dll_path,
203 const base::FilePath& db_path) {
204 channel_->Send(new Msg_Decryptor_Init(dll_path, db_path));
205 bool ok = WaitForClientResponse();
206 if (ok && listener_->got_result) {
207 listener_->got_result = false;
208 return listener_->result_bool;
210 return false;
213 base::string16 FFUnitTestDecryptorProxy::Decrypt(const std::string& crypt) {
214 channel_->Send(new Msg_Decrypt(crypt));
215 bool ok = WaitForClientResponse();
216 if (ok && listener_->got_result) {
217 listener_->got_result = false;
218 return listener_->result_string;
220 return base::string16();
223 std::vector<autofill::PasswordForm> FFUnitTestDecryptorProxy::ParseSignons(
224 const base::FilePath& signons_path) {
225 channel_->Send(new Msg_ParseSignons(signons_path));
226 bool ok = WaitForClientResponse();
227 if (ok && listener_->got_result) {
228 listener_->got_result = false;
229 return listener_->result_vector;
231 return std::vector<autofill::PasswordForm>();
234 //---------------------------- Child Process -----------------------
236 // Class to listen on the client side of the ipc channel, it calls through
237 // to the NSSDecryptor and sends back a reply.
238 class FFDecryptorClientChannelListener : public IPC::Listener {
239 public:
240 FFDecryptorClientChannelListener()
241 : sender_(NULL) {}
243 void SetSender(IPC::Sender* sender) {
244 sender_ = sender;
247 void OnDecryptor_Init(base::FilePath dll_path, base::FilePath db_path) {
248 bool ret = decryptor_.Init(dll_path, db_path);
249 sender_->Send(new Msg_Decryptor_InitReturnCode(ret));
252 void OnDecrypt(std::string crypt) {
253 base::string16 unencrypted_str = decryptor_.Decrypt(crypt);
254 sender_->Send(new Msg_Decryptor_Response(unencrypted_str));
257 void OnParseSignons(base::FilePath signons_path) {
258 std::vector<autofill::PasswordForm> forms;
259 decryptor_.ReadAndParseSignons(signons_path, &forms);
260 sender_->Send(new Msg_ParseSignons_Response(forms));
263 void OnQuitRequest() {
264 base::MessageLoop::current()->Quit();
267 bool OnMessageReceived(const IPC::Message& msg) override {
268 bool handled = true;
269 IPC_BEGIN_MESSAGE_MAP(FFDecryptorClientChannelListener, msg)
270 IPC_MESSAGE_HANDLER(Msg_Decryptor_Init, OnDecryptor_Init)
271 IPC_MESSAGE_HANDLER(Msg_Decrypt, OnDecrypt)
272 IPC_MESSAGE_HANDLER(Msg_ParseSignons, OnParseSignons)
273 IPC_MESSAGE_HANDLER(Msg_Decryptor_Quit, OnQuitRequest)
274 IPC_MESSAGE_UNHANDLED(handled = false)
275 IPC_END_MESSAGE_MAP()
276 return handled;
279 void OnChannelError() override { base::MessageLoop::current()->Quit(); }
281 private:
282 NSSDecryptor decryptor_;
283 IPC::Sender* sender_;
286 // Entry function in child process.
287 MULTIPROCESS_IPC_TEST_MAIN(NSSDecrypterChildProcess) {
288 base::MessageLoopForIO main_message_loop;
289 FFDecryptorClientChannelListener listener;
291 scoped_ptr<IPC::Channel> channel = IPC::Channel::CreateClient(
292 kTestChannelID, &listener);
293 CHECK(channel->Connect());
294 listener.SetSender(channel.get());
296 // run message loop
297 base::MessageLoop::current()->Run();
299 return 0;