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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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.
4
5 #include "chrome/browser/importer/firefox_importer_unittest_utils.h"
6
7 #include "base/command_line.h"
8 #include "base/debug_on_start.h"
9 #include "base/file_path.h"
10 #include "base/message_loop.h"
11 #include "chrome/browser/importer/firefox_importer_utils.h"
12 #include "ipc/ipc_channel.h"
13 #include "ipc/ipc_descriptors.h"
14 #include "ipc/ipc_message.h"
15 #include "ipc/ipc_message_utils.h"
16 #include "ipc/ipc_switches.h"
17 #include "testing/multiprocess_func_list.h"
18
19 // Definition of IPC Messages used for this test.
20 #define MESSAGES_INTERNAL_FILE \
21 "chrome/browser/importer/firefox_importer_unittest_messages_internal.h"
22 #include "ipc/ipc_message_macros.h"
23
24 namespace {
25
26 // Name of IPC Channel to use for Server<-> Child Communications.
27 const char kTestChannelID[] = "T1";
28
29 // Launch the child process:
30 // |nss_path| - path to the NSS directory holding the decryption libraries.
31 // |channel| - IPC Channel to use for communication.
32 // |handle| - On return, the process handle to use to communicate with the
33 // child.
34 bool LaunchNSSDecrypterChildProcess(const std::wstring& nss_path,
35 const IPC::Channel& channel, base::ProcessHandle* handle) {
36 CommandLine cl(*CommandLine::ForCurrentProcess());
37 cl.AppendSwitchWithValue(L"client", L"NSSDecrypterChildProcess");
38
39 FilePath ff_dylib_dir = FilePath::FromWStringHack(nss_path);
40 // Set env variable needed for FF encryption libs to load.
41 // See "chrome/browser/importer/nss_decryptor_mac.mm" for an explanation of
42 // why we need this.
43 base::environment_vector env;
44 std::pair<const char*,const char*> dyld_override;
45 dyld_override.first = "DYLD_FALLBACK_LIBRARY_PATH";
46 dyld_override.second = ff_dylib_dir.value().c_str();
47 env.push_back(dyld_override);
48
49 base::file_handle_mapping_vector fds_to_map;
50 const int ipcfd = channel.GetClientFileDescriptor();
51 if (ipcfd > -1) {
52 fds_to_map.push_back(std::pair<int,int>(ipcfd, kPrimaryIPCChannel + 3));
53 } else {
54 return false;
55 }
56
57 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
58 switches::kDebugChildren);
59 return base::LaunchApp(cl.argv(), env, fds_to_map, debug_on_start,
60 handle);
61 }
62
63 } // namespace
64
65 //----------------------- Server --------------------
66
67 // Class to communicate on the server side of the IPC Channel.
68 // Method calls are sent over IPC and replies are read back into class
69 // variables.
70 // This class needs to be called on a single thread.
71 class FFDecryptorServerChannelListener : public IPC::Channel::Listener {
72 public:
73 FFDecryptorServerChannelListener()
74 : got_result(false), sender_(NULL) {}
75
76 void SetSender(IPC::Message::Sender* sender) {
77 sender_ = sender;
78 }
79
80 void OnInitDecryptorResponse(bool result) {
81 DCHECK(!got_result);
82 result_bool = result;
83 got_result = true;
84 MessageLoop::current()->Quit();
85 }
86
87 void OnDecryptedTextResonse(std::wstring decrypted_text) {
88 DCHECK(!got_result);
89 result_string = decrypted_text;
90 got_result = true;
91 MessageLoop::current()->Quit();
92 }
93
94 void QuitClient() {
95 if (sender_)
96 sender_->Send(new Msg_Decryptor_Quit());
97 }
98
99 virtual void OnMessageReceived(const IPC::Message& msg) {
100 IPC_BEGIN_MESSAGE_MAP(FFDecryptorServerChannelListener, msg)
101 IPC_MESSAGE_HANDLER(Msg_Decryptor_InitReturnCode, OnInitDecryptorResponse)
102 IPC_MESSAGE_HANDLER(Msg_Decryptor_Response, OnDecryptedTextResonse)
103 IPC_END_MESSAGE_MAP()
104 }
105
106 // If an error occured, just kill the message Loop.
107 virtual void OnChannelError() {
108 got_result = false;
109 MessageLoop::current()->Quit();
110 }
111
112 // Results of IPC calls.
113 std::wstring result_string;
114 bool result_bool;
115 // True if IPC call succeeded and data in above variables is valid.
116 bool got_result;
117
118 private:
119 IPC::Message::Sender* sender_; // weak
120 };
121
122 FFUnitTestDecryptorProxy::FFUnitTestDecryptorProxy()
123 : child_process_(0) {
124 }
125
126 bool FFUnitTestDecryptorProxy::Setup(std::wstring& nss_path) {
127 // Create a new message loop and spawn the child process.
128 message_loop_.reset(new MessageLoopForIO());
129
130 listener_.reset(new FFDecryptorServerChannelListener());
131 channel_.reset(new IPC::Channel(kTestChannelID,
132 IPC::Channel::MODE_SERVER,
133 listener_.get()));
134 channel_->Connect();
135 listener_->SetSender(channel_.get());
136
137 // Spawn child and set up sync IPC connection.
138 bool ret = LaunchNSSDecrypterChildProcess(nss_path,
139 *(channel_.get()),
140 &child_process_);
141 return ret && (child_process_ != 0);
142 }
143
144 FFUnitTestDecryptorProxy::~FFUnitTestDecryptorProxy() {
145 listener_->QuitClient();
146 channel_->Close();
147
148 if (child_process_) {
149 base::WaitForSingleProcess(child_process_, 5000);
150 base::CloseProcessHandle(child_process_);
151 }
152 }
153
154 // A message_loop task that quits the message loop when invoked, setting cancel
155 // causes the task to do nothing when invoked.
156 class CancellableQuitMsgLoop : public base::RefCounted<CancellableQuitMsgLoop> {
157 public:
158 CancellableQuitMsgLoop() : cancelled_(false) {}
159 void QuitNow() {
160 if (!cancelled_)
161 MessageLoop::current()->Quit();
162 }
163 bool cancelled_;
164 };
165
166 // Spin until either a client response arrives or a timeout occurs.
167 bool FFUnitTestDecryptorProxy::WaitForClientResponse() {
168 const int64 kLoopTimeoutMS = 10 * 1000; // 10 seconds.
169
170 // What we're trying to do here is to wait for an RPC message to go over the
171 // wire and the client to reply. If the client does not replyy by a given
172 // timeout we kill the message loop.
173 // The way we do this is to post a CancellableQuitMsgLoop for 3 seconds in
174 // the future and cancel it if an RPC message comes back earlier.
175 // This relies on the IPC listener class to quit the message loop itself when
176 // a message comes in.
177 scoped_refptr<CancellableQuitMsgLoop> quit_task =
178 new CancellableQuitMsgLoop();
179 MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
180 quit_task.get(), &CancellableQuitMsgLoop::QuitNow), kLoopTimeoutMS);
181
182 message_loop_->Run();
183 bool ret = !quit_task->cancelled_;
184 quit_task->cancelled_ = false;
185 return ret;
186 }
187
188 bool FFUnitTestDecryptorProxy::DecryptorInit(const std::wstring& dll_path,
189 const std::wstring& db_path) {
190 channel_->Send(new Msg_Decryptor_Init(dll_path, db_path));
191 bool ok = WaitForClientResponse();
192 if (ok && listener_->got_result) {
193 listener_->got_result = false;
194 return listener_->result_bool;
195 }
196 return false;
197 }
198
199 std::wstring FFUnitTestDecryptorProxy::Decrypt(const std::string& crypt) {
200 channel_->Send(new Msg_Decrypt(crypt));
201 bool ok = WaitForClientResponse();
202 if (ok && listener_->got_result) {
203 listener_->got_result = false;
204 return listener_->result_string;
205 }
206 return L"";
207 }
208
209 //---------------------------- Child Process -----------------------
210
211 // Class to listen on the client side of the ipc channel, it calls through
212 // to the NSSDecryptor and sends back a reply.
213 class FFDecryptorClientChannelListener : public IPC::Channel::Listener {
214 public:
215 FFDecryptorClientChannelListener()
216 : sender_(NULL) {}
217
218 void SetSender(IPC::Message::Sender* sender) {
219 sender_ = sender;
220 }
221
222 void OnDecryptor_Init(std::wstring dll_path, std::wstring db_path) {
223 bool ret = decryptor_.Init(dll_path, db_path);
224 sender_->Send(new Msg_Decryptor_InitReturnCode(ret));
225 }
226
227 void OnDecrypt(std::string crypt) {
228 std::wstring unencrypted_str = decryptor_.Decrypt(crypt);
229 sender_->Send(new Msg_Decryptor_Response(unencrypted_str));
230 }
231
232 void OnQuitRequest() {
233 MessageLoop::current()->Quit();
234 }
235
236 virtual void OnMessageReceived(const IPC::Message& msg) {
237 IPC_BEGIN_MESSAGE_MAP(FFDecryptorClientChannelListener, msg)
238 IPC_MESSAGE_HANDLER(Msg_Decryptor_Init, OnDecryptor_Init)
239 IPC_MESSAGE_HANDLER(Msg_Decrypt, OnDecrypt)
240 IPC_MESSAGE_HANDLER(Msg_Decryptor_Quit, OnQuitRequest)
241 IPC_END_MESSAGE_MAP()
242 }
243
244 virtual void OnChannelError() {
245 MessageLoop::current()->Quit();
246 }
247
248 private:
249 NSSDecryptor decryptor_;
250 IPC::Message::Sender* sender_;
251 };
252
253 // Entry function in child process.
254 MULTIPROCESS_TEST_MAIN(NSSDecrypterChildProcess) {
255 MessageLoopForIO main_message_loop;
256 FFDecryptorClientChannelListener listener;
257
258 IPC::Channel channel(kTestChannelID, IPC::Channel::MODE_CLIENT, &listener);
259 channel.Connect();
260 listener.SetSender(&channel);
261
262 // run message loop
263 MessageLoop::current()->Run();
264
265 return 0;
266 }
OLDNEW
« 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