OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/it2me/it2me_native_messaging_host.h" | 5 #include "remoting/host/it2me/it2me_native_messaging_host.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 void VerifyDisconnectResponses(int request_id); | 180 void VerifyDisconnectResponses(int request_id); |
181 | 181 |
182 // The Host process should shut down when it receives a malformed request. | 182 // The Host process should shut down when it receives a malformed request. |
183 // This is tested by sending a known-good request, followed by |message|, | 183 // This is tested by sending a known-good request, followed by |message|, |
184 // followed by the known-good request again. The response file should only | 184 // followed by the known-good request again. The response file should only |
185 // contain a single response from the first good request. | 185 // contain a single response from the first good request. |
186 void TestBadRequest(const base::Value& message, bool expect_error_response); | 186 void TestBadRequest(const base::Value& message, bool expect_error_response); |
187 void TestConnect(); | 187 void TestConnect(); |
188 | 188 |
189 private: | 189 private: |
190 void StartHost(base::PlatformFile input, base::PlatformFile output); | 190 void StartHost(); |
191 void StopHost(); | 191 void StopHost(); |
192 void ExitTest(); | 192 void ExitTest(); |
193 | 193 |
194 // Each test creates two unidirectional pipes: "input" and "output". | 194 // Each test creates two unidirectional pipes: "input" and "output". |
195 // NativeMessagingHost reads from input_read_handle and writes to | 195 // NativeMessagingHost reads from input_read_handle and writes to |
196 // output_write_handle. The unittest supplies data to input_write_handle, and | 196 // output_write_handle. The unittest supplies data to input_write_handle, and |
197 // verifies output from output_read_handle. | 197 // verifies output from output_read_handle. |
198 // | 198 // |
199 // unittest -> [input] -> NativeMessagingHost -> [output] -> unittest | 199 // unittest -> [input] -> NativeMessagingHost -> [output] -> unittest |
200 base::PlatformFile input_write_handle_; | 200 base::PlatformFile input_write_handle_; |
201 base::PlatformFile output_read_handle_; | 201 base::PlatformFile output_read_handle_; |
202 | 202 |
203 // Message loop of the test thread. | 203 // Message loop of the test thread. |
204 scoped_ptr<base::MessageLoop> test_message_loop_; | 204 scoped_ptr<base::MessageLoop> test_message_loop_; |
205 scoped_ptr<base::RunLoop> test_run_loop_; | 205 scoped_ptr<base::RunLoop> test_run_loop_; |
206 | 206 |
207 scoped_ptr<base::Thread> host_thread_; | 207 scoped_ptr<base::Thread> host_thread_; |
208 scoped_ptr<base::RunLoop> host_run_loop_; | 208 scoped_ptr<base::RunLoop> host_run_loop_; |
209 | 209 |
210 // Task runner of the host thread. | 210 // Task runner of the host thread. |
211 scoped_refptr<AutoThreadTaskRunner> host_task_runner_; | 211 scoped_refptr<AutoThreadTaskRunner> host_task_runner_; |
212 scoped_ptr<remoting::NativeMessagingChannel> channel_; | 212 scoped_ptr<remoting::It2MeNativeMessagingHost> host_; |
213 | 213 |
214 DISALLOW_COPY_AND_ASSIGN(It2MeNativeMessagingHostTest); | 214 DISALLOW_COPY_AND_ASSIGN(It2MeNativeMessagingHostTest); |
215 }; | 215 }; |
216 | 216 |
217 void It2MeNativeMessagingHostTest::SetUp() { | 217 void It2MeNativeMessagingHostTest::SetUp() { |
218 base::PlatformFile input_read_handle; | |
219 base::PlatformFile output_write_handle; | |
220 | |
221 ASSERT_TRUE(MakePipe(&input_read_handle, &input_write_handle_)); | |
222 ASSERT_TRUE(MakePipe(&output_read_handle_, &output_write_handle)); | |
223 | |
224 test_message_loop_.reset(new base::MessageLoop()); | 218 test_message_loop_.reset(new base::MessageLoop()); |
225 test_run_loop_.reset(new base::RunLoop()); | 219 test_run_loop_.reset(new base::RunLoop()); |
226 | 220 |
227 // Run the host on a dedicated thread. | 221 // Run the host on a dedicated thread. |
228 host_thread_.reset(new base::Thread("host_thread")); | 222 host_thread_.reset(new base::Thread("host_thread")); |
229 host_thread_->Start(); | 223 host_thread_->Start(); |
230 | 224 |
231 host_task_runner_ = new AutoThreadTaskRunner( | 225 host_task_runner_ = new AutoThreadTaskRunner( |
232 host_thread_->message_loop_proxy(), | 226 host_thread_->message_loop_proxy(), |
233 base::Bind(&It2MeNativeMessagingHostTest::ExitTest, | 227 base::Bind(&It2MeNativeMessagingHostTest::ExitTest, |
234 base::Unretained(this))); | 228 base::Unretained(this))); |
235 | 229 |
236 host_task_runner_->PostTask( | 230 host_task_runner_->PostTask( |
237 FROM_HERE, | 231 FROM_HERE, |
238 base::Bind(&It2MeNativeMessagingHostTest::StartHost, | 232 base::Bind(&It2MeNativeMessagingHostTest::StartHost, |
239 base::Unretained(this), | 233 base::Unretained(this))); |
240 input_read_handle, | |
241 output_write_handle)); | |
242 | 234 |
243 // Wait until the host finishes starting. | 235 // Wait until the host finishes starting. |
244 test_run_loop_->Run(); | 236 test_run_loop_->Run(); |
245 } | 237 } |
246 | 238 |
247 void It2MeNativeMessagingHostTest::TearDown() { | 239 void It2MeNativeMessagingHostTest::TearDown() { |
248 // Closing the write-end of the input will send an EOF to the native | 240 // Closing the write-end of the input will send an EOF to the native |
249 // messaging reader. This will trigger a host shutdown. | 241 // messaging reader. This will trigger a host shutdown. |
250 base::ClosePlatformFile(input_write_handle_); | 242 base::ClosePlatformFile(input_write_handle_); |
251 | 243 |
252 // Start a new RunLoop and Wait until the host finishes shutting down. | 244 // Start a new RunLoop and Wait until the host finishes shutting down. |
253 test_run_loop_.reset(new base::RunLoop()); | 245 test_run_loop_.reset(new base::RunLoop()); |
254 test_run_loop_->Run(); | 246 test_run_loop_->Run(); |
255 | 247 |
256 // Verify there are no more message in the output pipe. | 248 // Verify there are no more message in the output pipe. |
257 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); | 249 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); |
258 EXPECT_FALSE(response); | 250 EXPECT_FALSE(response); |
259 | 251 |
260 // The It2MeNativeMessagingHost dtor closes the handles that are passed to it. | 252 // The It2MeNativeMessagingHost dtor closes the handles that are passed to it. |
261 // So the only handle left to close is |output_read_handle_|. | 253 // So the only handle left to close is |output_read_handle_|. |
262 base::ClosePlatformFile(output_read_handle_); | 254 base::ClosePlatformFile(output_read_handle_); |
263 } | 255 } |
264 | 256 |
265 scoped_ptr<base::DictionaryValue> | 257 scoped_ptr<base::DictionaryValue> |
266 It2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() { | 258 It2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() { |
267 uint32 length; | 259 uint32 length; |
268 int read_result = base::ReadPlatformFileAtCurrentPos( | 260 int read_result = base::ReadPlatformFileAtCurrentPos( |
269 output_read_handle_, reinterpret_cast<char*>(&length), sizeof(length)); | 261 output_read_handle_, reinterpret_cast<char*>(&length), sizeof(length)); |
270 if (read_result != sizeof(length)) { | 262 if (read_result != sizeof(length)) { |
271 LOG(ERROR) << "Invalid message header."; | 263 // The output pipe has been closed, return an empty message. |
272 return scoped_ptr<base::DictionaryValue>(); | 264 return scoped_ptr<base::DictionaryValue>(); |
273 } | 265 } |
274 | 266 |
275 std::string message_json(length, '\0'); | 267 std::string message_json(length, '\0'); |
276 read_result = base::ReadPlatformFileAtCurrentPos( | 268 read_result = base::ReadPlatformFileAtCurrentPos( |
277 output_read_handle_, string_as_array(&message_json), length); | 269 output_read_handle_, string_as_array(&message_json), length); |
278 if (read_result != static_cast<int>(length)) { | 270 if (read_result != static_cast<int>(length)) { |
279 LOG(ERROR) << "Message size (" << read_result | 271 LOG(ERROR) << "Message size (" << read_result |
280 << ") doesn't match the header (" << length << ")."; | 272 << ") doesn't match the header (" << length << ")."; |
281 return scoped_ptr<base::DictionaryValue>(); | 273 return scoped_ptr<base::DictionaryValue>(); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
421 | 413 |
422 VerifyHelloResponse(1); | 414 VerifyHelloResponse(1); |
423 | 415 |
424 if (expect_error_response) | 416 if (expect_error_response) |
425 VerifyErrorResponse(); | 417 VerifyErrorResponse(); |
426 | 418 |
427 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); | 419 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); |
428 EXPECT_FALSE(response); | 420 EXPECT_FALSE(response); |
429 } | 421 } |
430 | 422 |
431 void It2MeNativeMessagingHostTest::StartHost(base::PlatformFile input, | 423 void It2MeNativeMessagingHostTest::StartHost() { |
432 base::PlatformFile output) { | |
433 DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); | 424 DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); |
434 | 425 |
426 base::PlatformFile input_read_handle; | |
427 base::PlatformFile output_write_handle; | |
428 | |
429 ASSERT_TRUE(MakePipe(&input_read_handle, &input_write_handle_)); | |
Sergey Ulanov
2013/12/12 23:55:16
FWIW, not required for this CL: now that dependenc
| |
430 ASSERT_TRUE(MakePipe(&output_read_handle_, &output_write_handle)); | |
431 | |
435 // Creating a native messaging host with a mock It2MeHostFactory. | 432 // Creating a native messaging host with a mock It2MeHostFactory. |
436 scoped_ptr<It2MeHostFactory> factory(new MockIt2MeHostFactory()); | 433 scoped_ptr<It2MeHostFactory> factory(new MockIt2MeHostFactory()); |
437 scoped_ptr<NativeMessagingChannel::Delegate> host( | |
438 new It2MeNativeMessagingHost(host_task_runner_, factory.Pass())); | |
439 | 434 |
440 // Set up and start the native messaging channel. | 435 scoped_ptr<NativeMessagingChannel> channel( |
441 channel_.reset(new NativeMessagingChannel(host.Pass(), input, output)); | 436 new NativeMessagingChannel(input_read_handle, output_write_handle)); |
442 channel_->Start(base::Bind(&It2MeNativeMessagingHostTest::StopHost, | 437 |
443 base::Unretained(this))); | 438 host_.reset( |
439 new It2MeNativeMessagingHost( | |
440 host_task_runner_, channel.Pass(), factory.Pass())); | |
441 host_->Start(base::Bind(&It2MeNativeMessagingHostTest::StopHost, | |
442 base::Unretained(this))); | |
444 | 443 |
445 // Notify the test that the host has finished starting up. | 444 // Notify the test that the host has finished starting up. |
446 test_message_loop_->message_loop_proxy()->PostTask( | 445 test_message_loop_->message_loop_proxy()->PostTask( |
447 FROM_HERE, test_run_loop_->QuitClosure()); | 446 FROM_HERE, test_run_loop_->QuitClosure()); |
448 } | 447 } |
449 | 448 |
450 void It2MeNativeMessagingHostTest::StopHost() { | 449 void It2MeNativeMessagingHostTest::StopHost() { |
451 DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); | 450 DCHECK(host_task_runner_->RunsTasksOnCurrentThread()); |
452 | 451 |
453 // The NativeMessagingChannel dtor will destroy the reader, the writer, | 452 host_.reset(); |
454 // and the delegate (the native messaging host). | |
455 channel_.reset(); | |
456 | 453 |
457 // Wait till all shutdown tasks have completed. | 454 // Wait till all shutdown tasks have completed. |
458 base::MessageLoop::current()->RunUntilIdle(); | 455 base::MessageLoop::current()->RunUntilIdle(); |
459 | 456 |
460 // Trigger a test shutdown via ExitTest(). | 457 // Trigger a test shutdown via ExitTest(). |
461 host_task_runner_ = NULL; | 458 host_task_runner_ = NULL; |
462 } | 459 } |
463 | 460 |
464 void It2MeNativeMessagingHostTest::ExitTest() { | 461 void It2MeNativeMessagingHostTest::ExitTest() { |
465 if (!test_message_loop_->message_loop_proxy()->RunsTasksOnCurrentThread()) { | 462 if (!test_message_loop_->message_loop_proxy()->RunsTasksOnCurrentThread()) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
548 } | 545 } |
549 | 546 |
550 // Verify rejection if type is unrecognized. | 547 // Verify rejection if type is unrecognized. |
551 TEST_F(It2MeNativeMessagingHostTest, InvalidType) { | 548 TEST_F(It2MeNativeMessagingHostTest, InvalidType) { |
552 base::DictionaryValue message; | 549 base::DictionaryValue message; |
553 message.SetString("type", "xxx"); | 550 message.SetString("type", "xxx"); |
554 TestBadRequest(message, true); | 551 TestBadRequest(message, true); |
555 } | 552 } |
556 | 553 |
557 } // namespace remoting | 554 } // namespace remoting |
OLD | NEW |