Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / host / setup / me2me_native_messaging_host_unittest.cc
blobe973d7d178a169a79560ce578a9d5d14e8869724
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
3 // found in the LICENSE file.
5 #include "remoting/host/setup/me2me_native_messaging_host.h"
7 #include "base/basictypes.h"
8 #include "base/compiler_specific.h"
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/stl_util.h"
14 #include "base/strings/stringize_macros.h"
15 #include "base/values.h"
16 #include "google_apis/gaia/gaia_oauth_client.h"
17 #include "net/base/file_stream.h"
18 #include "net/base/net_util.h"
19 #include "remoting/base/auto_thread_task_runner.h"
20 #include "remoting/host/native_messaging/log_message_handler.h"
21 #include "remoting/host/native_messaging/pipe_messaging_channel.h"
22 #include "remoting/host/pin_hash.h"
23 #include "remoting/host/setup/mock_oauth_client.h"
24 #include "remoting/host/setup/test_util.h"
25 #include "remoting/protocol/pairing_registry.h"
26 #include "remoting/protocol/protocol_mock_objects.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using remoting::protocol::MockPairingRegistryDelegate;
30 using remoting::protocol::PairingRegistry;
31 using remoting::protocol::SynchronousPairingRegistry;
33 namespace {
35 void VerifyHelloResponse(scoped_ptr<base::DictionaryValue> response) {
36 ASSERT_TRUE(response);
37 std::string value;
38 EXPECT_TRUE(response->GetString("type", &value));
39 EXPECT_EQ("helloResponse", value);
40 EXPECT_TRUE(response->GetString("version", &value));
42 // The check below will compile but fail if VERSION isn't defined (STRINGIZE
43 // silently converts undefined values).
44 #ifndef VERSION
45 #error VERSION must be defined
46 #endif
47 EXPECT_EQ(STRINGIZE(VERSION), value);
50 void VerifyGetHostNameResponse(scoped_ptr<base::DictionaryValue> response) {
51 ASSERT_TRUE(response);
52 std::string value;
53 EXPECT_TRUE(response->GetString("type", &value));
54 EXPECT_EQ("getHostNameResponse", value);
55 EXPECT_TRUE(response->GetString("hostname", &value));
56 EXPECT_EQ(net::GetHostName(), value);
59 void VerifyGetPinHashResponse(scoped_ptr<base::DictionaryValue> response) {
60 ASSERT_TRUE(response);
61 std::string value;
62 EXPECT_TRUE(response->GetString("type", &value));
63 EXPECT_EQ("getPinHashResponse", value);
64 EXPECT_TRUE(response->GetString("hash", &value));
65 EXPECT_EQ(remoting::MakeHostPinHash("my_host", "1234"), value);
68 void VerifyGenerateKeyPairResponse(scoped_ptr<base::DictionaryValue> response) {
69 ASSERT_TRUE(response);
70 std::string value;
71 EXPECT_TRUE(response->GetString("type", &value));
72 EXPECT_EQ("generateKeyPairResponse", value);
73 EXPECT_TRUE(response->GetString("privateKey", &value));
74 EXPECT_TRUE(response->GetString("publicKey", &value));
77 void VerifyGetDaemonConfigResponse(scoped_ptr<base::DictionaryValue> response) {
78 ASSERT_TRUE(response);
79 std::string value;
80 EXPECT_TRUE(response->GetString("type", &value));
81 EXPECT_EQ("getDaemonConfigResponse", value);
82 const base::DictionaryValue* config = nullptr;
83 EXPECT_TRUE(response->GetDictionary("config", &config));
84 EXPECT_TRUE(base::DictionaryValue().Equals(config));
87 void VerifyGetUsageStatsConsentResponse(
88 scoped_ptr<base::DictionaryValue> response) {
89 ASSERT_TRUE(response);
90 std::string value;
91 EXPECT_TRUE(response->GetString("type", &value));
92 EXPECT_EQ("getUsageStatsConsentResponse", value);
93 bool supported, allowed, set_by_policy;
94 EXPECT_TRUE(response->GetBoolean("supported", &supported));
95 EXPECT_TRUE(response->GetBoolean("allowed", &allowed));
96 EXPECT_TRUE(response->GetBoolean("setByPolicy", &set_by_policy));
97 EXPECT_TRUE(supported);
98 EXPECT_TRUE(allowed);
99 EXPECT_TRUE(set_by_policy);
102 void VerifyStopDaemonResponse(scoped_ptr<base::DictionaryValue> response) {
103 ASSERT_TRUE(response);
104 std::string value;
105 EXPECT_TRUE(response->GetString("type", &value));
106 EXPECT_EQ("stopDaemonResponse", value);
107 EXPECT_TRUE(response->GetString("result", &value));
108 EXPECT_EQ("OK", value);
111 void VerifyGetDaemonStateResponse(scoped_ptr<base::DictionaryValue> response) {
112 ASSERT_TRUE(response);
113 std::string value;
114 EXPECT_TRUE(response->GetString("type", &value));
115 EXPECT_EQ("getDaemonStateResponse", value);
116 EXPECT_TRUE(response->GetString("state", &value));
117 EXPECT_EQ("STARTED", value);
120 void VerifyUpdateDaemonConfigResponse(
121 scoped_ptr<base::DictionaryValue> response) {
122 ASSERT_TRUE(response);
123 std::string value;
124 EXPECT_TRUE(response->GetString("type", &value));
125 EXPECT_EQ("updateDaemonConfigResponse", value);
126 EXPECT_TRUE(response->GetString("result", &value));
127 EXPECT_EQ("OK", value);
130 void VerifyStartDaemonResponse(scoped_ptr<base::DictionaryValue> response) {
131 ASSERT_TRUE(response);
132 std::string value;
133 EXPECT_TRUE(response->GetString("type", &value));
134 EXPECT_EQ("startDaemonResponse", value);
135 EXPECT_TRUE(response->GetString("result", &value));
136 EXPECT_EQ("OK", value);
139 void VerifyGetCredentialsFromAuthCodeResponse(
140 scoped_ptr<base::DictionaryValue> response) {
141 ASSERT_TRUE(response);
142 std::string value;
143 EXPECT_TRUE(response->GetString("type", &value));
144 EXPECT_EQ("getCredentialsFromAuthCodeResponse", value);
145 EXPECT_TRUE(response->GetString("userEmail", &value));
146 EXPECT_EQ("fake_user_email", value);
147 EXPECT_TRUE(response->GetString("refreshToken", &value));
148 EXPECT_EQ("fake_refresh_token", value);
151 } // namespace
153 namespace remoting {
155 class MockDaemonControllerDelegate : public DaemonController::Delegate {
156 public:
157 MockDaemonControllerDelegate();
158 ~MockDaemonControllerDelegate() override;
160 // DaemonController::Delegate interface.
161 DaemonController::State GetState() override;
162 scoped_ptr<base::DictionaryValue> GetConfig() override;
163 void SetConfigAndStart(
164 scoped_ptr<base::DictionaryValue> config,
165 bool consent,
166 const DaemonController::CompletionCallback& done) override;
167 void UpdateConfig(scoped_ptr<base::DictionaryValue> config,
168 const DaemonController::CompletionCallback& done) override;
169 void Stop(const DaemonController::CompletionCallback& done) override;
170 DaemonController::UsageStatsConsent GetUsageStatsConsent() override;
172 private:
173 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate);
176 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
178 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
180 DaemonController::State MockDaemonControllerDelegate::GetState() {
181 return DaemonController::STATE_STARTED;
184 scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() {
185 return make_scoped_ptr(new base::DictionaryValue());
188 void MockDaemonControllerDelegate::SetConfigAndStart(
189 scoped_ptr<base::DictionaryValue> config,
190 bool consent,
191 const DaemonController::CompletionCallback& done) {
193 // Verify parameters passed in.
194 if (consent && config && config->HasKey("start")) {
195 done.Run(DaemonController::RESULT_OK);
196 } else {
197 done.Run(DaemonController::RESULT_FAILED);
201 void MockDaemonControllerDelegate::UpdateConfig(
202 scoped_ptr<base::DictionaryValue> config,
203 const DaemonController::CompletionCallback& done) {
204 if (config && config->HasKey("update")) {
205 done.Run(DaemonController::RESULT_OK);
206 } else {
207 done.Run(DaemonController::RESULT_FAILED);
211 void MockDaemonControllerDelegate::Stop(
212 const DaemonController::CompletionCallback& done) {
213 done.Run(DaemonController::RESULT_OK);
216 DaemonController::UsageStatsConsent
217 MockDaemonControllerDelegate::GetUsageStatsConsent() {
218 DaemonController::UsageStatsConsent consent;
219 consent.supported = true;
220 consent.allowed = true;
221 consent.set_by_policy = true;
222 return consent;
225 class Me2MeNativeMessagingHostTest : public testing::Test {
226 public:
227 Me2MeNativeMessagingHostTest();
228 ~Me2MeNativeMessagingHostTest() override;
230 void SetUp() override;
231 void TearDown() override;
233 scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe();
235 void WriteMessageToInputPipe(const base::Value& message);
237 // The Host process should shut down when it receives a malformed request.
238 // This is tested by sending a known-good request, followed by |message|,
239 // followed by the known-good request again. The response file should only
240 // contain a single response from the first good request.
241 void TestBadRequest(const base::Value& message);
243 protected:
244 // Reference to the MockDaemonControllerDelegate, which is owned by
245 // |channel_|.
246 MockDaemonControllerDelegate* daemon_controller_delegate_;
248 private:
249 void StartHost();
250 void StopHost();
251 void ExitTest();
253 // Each test creates two unidirectional pipes: "input" and "output".
254 // Me2MeNativeMessagingHost reads from input_read_handle and writes to
255 // output_write_file. The unittest supplies data to input_write_handle, and
256 // verifies output from output_read_handle.
258 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
259 base::File input_write_file_;
260 base::File output_read_file_;
262 // Message loop of the test thread.
263 scoped_ptr<base::MessageLoop> test_message_loop_;
264 scoped_ptr<base::RunLoop> test_run_loop_;
266 scoped_ptr<base::Thread> host_thread_;
267 scoped_ptr<base::RunLoop> host_run_loop_;
269 // Task runner of the host thread.
270 scoped_refptr<AutoThreadTaskRunner> host_task_runner_;
271 scoped_ptr<remoting::Me2MeNativeMessagingHost> host_;
273 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest);
276 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
278 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
280 void Me2MeNativeMessagingHostTest::SetUp() {
281 base::File input_read_file;
282 base::File output_write_file;
284 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
285 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
287 test_message_loop_.reset(new base::MessageLoop());
288 test_run_loop_.reset(new base::RunLoop());
290 // Run the host on a dedicated thread.
291 host_thread_.reset(new base::Thread("host_thread"));
292 host_thread_->Start();
294 // Arrange to run |test_message_loop_| until no components depend on it.
295 host_task_runner_ = new AutoThreadTaskRunner(
296 host_thread_->task_runner(),
297 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
298 base::Unretained(this)));
300 host_task_runner_->PostTask(
301 FROM_HERE,
302 base::Bind(&Me2MeNativeMessagingHostTest::StartHost,
303 base::Unretained(this)));
305 // Wait until the host finishes starting.
306 test_run_loop_->Run();
309 void Me2MeNativeMessagingHostTest::StartHost() {
310 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
312 base::File input_read_file;
313 base::File output_write_file;
315 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
316 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
318 daemon_controller_delegate_ = new MockDaemonControllerDelegate();
319 scoped_refptr<DaemonController> daemon_controller(
320 new DaemonController(make_scoped_ptr(daemon_controller_delegate_)));
322 scoped_refptr<PairingRegistry> pairing_registry =
323 new SynchronousPairingRegistry(
324 make_scoped_ptr(new MockPairingRegistryDelegate()));
326 scoped_ptr<extensions::NativeMessagingChannel> channel(
327 new PipeMessagingChannel(input_read_file.Pass(),
328 output_write_file.Pass()));
330 scoped_ptr<OAuthClient> oauth_client(
331 new MockOAuthClient("fake_user_email", "fake_refresh_token"));
333 host_.reset(new Me2MeNativeMessagingHost(false, 0, channel.Pass(),
334 daemon_controller, pairing_registry,
335 oauth_client.Pass()));
336 host_->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost,
337 base::Unretained(this)));
339 // Notify the test that the host has finished starting up.
340 test_message_loop_->task_runner()->PostTask(
341 FROM_HERE, test_run_loop_->QuitClosure());
344 void Me2MeNativeMessagingHostTest::StopHost() {
345 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
347 host_.reset();
349 // Wait till all shutdown tasks have completed.
350 base::RunLoop().RunUntilIdle();
352 // Trigger a test shutdown via ExitTest().
353 host_task_runner_ = nullptr;
356 void Me2MeNativeMessagingHostTest::ExitTest() {
357 if (!test_message_loop_->task_runner()->RunsTasksOnCurrentThread()) {
358 test_message_loop_->task_runner()->PostTask(
359 FROM_HERE,
360 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
361 base::Unretained(this)));
362 return;
364 test_run_loop_->Quit();
367 void Me2MeNativeMessagingHostTest::TearDown() {
368 // Closing the write-end of the input will send an EOF to the native
369 // messaging reader. This will trigger a host shutdown.
370 input_write_file_.Close();
372 // Start a new RunLoop and Wait until the host finishes shutting down.
373 test_run_loop_.reset(new base::RunLoop());
374 test_run_loop_->Run();
376 // Verify there are no more message in the output pipe.
377 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
378 EXPECT_FALSE(response);
380 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
381 // to it. So the only handle left to close is |output_read_file_|.
382 output_read_file_.Close();
385 scoped_ptr<base::DictionaryValue>
386 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
387 while (true) {
388 uint32 length;
389 int read_result = output_read_file_.ReadAtCurrentPos(
390 reinterpret_cast<char*>(&length), sizeof(length));
391 if (read_result != sizeof(length)) {
392 return nullptr;
395 std::string message_json(length, '\0');
396 read_result = output_read_file_.ReadAtCurrentPos(
397 string_as_array(&message_json), length);
398 if (read_result != static_cast<int>(length)) {
399 return nullptr;
402 scoped_ptr<base::Value> message = base::JSONReader::Read(message_json);
403 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
404 return nullptr;
407 scoped_ptr<base::DictionaryValue> result = make_scoped_ptr(
408 static_cast<base::DictionaryValue*>(message.release()));
409 std::string type;
410 // If this is a debug message log, ignore it, otherwise return it.
411 if (!result->GetString("type", &type) ||
412 type != LogMessageHandler::kDebugMessageTypeName) {
413 return result;
418 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
419 const base::Value& message) {
420 std::string message_json;
421 base::JSONWriter::Write(message, &message_json);
423 uint32 length = message_json.length();
424 input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
425 sizeof(length));
426 input_write_file_.WriteAtCurrentPos(message_json.data(), length);
429 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value& message) {
430 base::DictionaryValue good_message;
431 good_message.SetString("type", "hello");
433 // This test currently relies on synchronous processing of hello messages and
434 // message parameters verification.
435 WriteMessageToInputPipe(good_message);
436 WriteMessageToInputPipe(message);
437 WriteMessageToInputPipe(good_message);
439 // Read from output pipe, and verify responses.
440 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
441 VerifyHelloResponse(response.Pass());
443 response = ReadMessageFromOutputPipe();
444 EXPECT_FALSE(response);
447 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
448 // Test all valid request-types.
449 TEST_F(Me2MeNativeMessagingHostTest, All) {
450 int next_id = 0;
451 base::DictionaryValue message;
452 message.SetInteger("id", next_id++);
453 message.SetString("type", "hello");
454 WriteMessageToInputPipe(message);
456 message.SetInteger("id", next_id++);
457 message.SetString("type", "getHostName");
458 WriteMessageToInputPipe(message);
460 message.SetInteger("id", next_id++);
461 message.SetString("type", "getPinHash");
462 message.SetString("hostId", "my_host");
463 message.SetString("pin", "1234");
464 WriteMessageToInputPipe(message);
466 message.Clear();
467 message.SetInteger("id", next_id++);
468 message.SetString("type", "generateKeyPair");
469 WriteMessageToInputPipe(message);
471 message.SetInteger("id", next_id++);
472 message.SetString("type", "getDaemonConfig");
473 WriteMessageToInputPipe(message);
475 message.SetInteger("id", next_id++);
476 message.SetString("type", "getUsageStatsConsent");
477 WriteMessageToInputPipe(message);
479 message.SetInteger("id", next_id++);
480 message.SetString("type", "stopDaemon");
481 WriteMessageToInputPipe(message);
483 message.SetInteger("id", next_id++);
484 message.SetString("type", "getDaemonState");
485 WriteMessageToInputPipe(message);
487 // Following messages require a "config" dictionary.
488 base::DictionaryValue config;
489 config.SetBoolean("update", true);
490 message.Set("config", config.DeepCopy());
491 message.SetInteger("id", next_id++);
492 message.SetString("type", "updateDaemonConfig");
493 WriteMessageToInputPipe(message);
495 config.Clear();
496 config.SetBoolean("start", true);
497 message.Set("config", config.DeepCopy());
498 message.SetBoolean("consent", true);
499 message.SetInteger("id", next_id++);
500 message.SetString("type", "startDaemon");
501 WriteMessageToInputPipe(message);
503 message.SetInteger("id", next_id++);
504 message.SetString("type", "getCredentialsFromAuthCode");
505 message.SetString("authorizationCode", "fake_auth_code");
506 WriteMessageToInputPipe(message);
508 void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = {
509 &VerifyHelloResponse,
510 &VerifyGetHostNameResponse,
511 &VerifyGetPinHashResponse,
512 &VerifyGenerateKeyPairResponse,
513 &VerifyGetDaemonConfigResponse,
514 &VerifyGetUsageStatsConsentResponse,
515 &VerifyStopDaemonResponse,
516 &VerifyGetDaemonStateResponse,
517 &VerifyUpdateDaemonConfigResponse,
518 &VerifyStartDaemonResponse,
519 &VerifyGetCredentialsFromAuthCodeResponse,
521 ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id));
523 // Read all responses from output pipe, and verify them.
524 for (int i = 0; i < next_id; ++i) {
525 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
527 // Make sure that id is available and is in the range.
528 int id;
529 ASSERT_TRUE(response->GetInteger("id", &id));
530 ASSERT_TRUE(0 <= id && id < next_id);
532 // Call the verification routine corresponding to the message id.
533 ASSERT_TRUE(verify_routines[id]);
534 verify_routines[id](response.Pass());
536 // Clear the pointer so that the routine cannot be called the second time.
537 verify_routines[id] = nullptr;
541 // Verify that response ID matches request ID.
542 TEST_F(Me2MeNativeMessagingHostTest, Id) {
543 base::DictionaryValue message;
544 message.SetString("type", "hello");
545 WriteMessageToInputPipe(message);
546 message.SetString("id", "42");
547 WriteMessageToInputPipe(message);
549 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
550 EXPECT_TRUE(response);
551 std::string value;
552 EXPECT_FALSE(response->GetString("id", &value));
554 response = ReadMessageFromOutputPipe();
555 EXPECT_TRUE(response);
556 EXPECT_TRUE(response->GetString("id", &value));
557 EXPECT_EQ("42", value);
560 // Verify non-Dictionary requests are rejected.
561 TEST_F(Me2MeNativeMessagingHostTest, WrongFormat) {
562 base::ListValue message;
563 TestBadRequest(message);
566 // Verify requests with no type are rejected.
567 TEST_F(Me2MeNativeMessagingHostTest, MissingType) {
568 base::DictionaryValue message;
569 TestBadRequest(message);
572 // Verify rejection if type is unrecognized.
573 TEST_F(Me2MeNativeMessagingHostTest, InvalidType) {
574 base::DictionaryValue message;
575 message.SetString("type", "xxx");
576 TestBadRequest(message);
579 // Verify rejection if getPinHash request has no hostId.
580 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoHostId) {
581 base::DictionaryValue message;
582 message.SetString("type", "getPinHash");
583 message.SetString("pin", "1234");
584 TestBadRequest(message);
587 // Verify rejection if getPinHash request has no pin.
588 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoPin) {
589 base::DictionaryValue message;
590 message.SetString("type", "getPinHash");
591 message.SetString("hostId", "my_host");
592 TestBadRequest(message);
595 // Verify rejection if updateDaemonConfig request has invalid config.
596 TEST_F(Me2MeNativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
597 base::DictionaryValue message;
598 message.SetString("type", "updateDaemonConfig");
599 message.SetString("config", "xxx");
600 TestBadRequest(message);
603 // Verify rejection if startDaemon request has invalid config.
604 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonInvalidConfig) {
605 base::DictionaryValue message;
606 message.SetString("type", "startDaemon");
607 message.SetString("config", "xxx");
608 message.SetBoolean("consent", true);
609 TestBadRequest(message);
612 // Verify rejection if startDaemon request has no "consent" parameter.
613 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonNoConsent) {
614 base::DictionaryValue message;
615 message.SetString("type", "startDaemon");
616 message.Set("config", base::DictionaryValue().DeepCopy());
617 TestBadRequest(message);
620 // Verify rejection if getCredentialsFromAuthCode has no auth code.
621 TEST_F(Me2MeNativeMessagingHostTest, GetCredentialsFromAuthCodeNoAuthCode) {
622 base::DictionaryValue message;
623 message.SetString("type", "getCredentialsFromAuthCode");
624 TestBadRequest(message);
627 } // namespace remoting