Revert of Remove OneClickSigninHelper since it is no longer used. (patchset #5 id...
[chromium-blink-merge.git] / remoting / host / setup / me2me_native_messaging_host_unittest.cc
blobe48f3aabb4bbc140c3ed03eae5071f25c672a673
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/pipe_messaging_channel.h"
21 #include "remoting/host/pin_hash.h"
22 #include "remoting/host/setup/test_util.h"
23 #include "remoting/protocol/pairing_registry.h"
24 #include "remoting/protocol/protocol_mock_objects.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using remoting::protocol::MockPairingRegistryDelegate;
28 using remoting::protocol::PairingRegistry;
29 using remoting::protocol::SynchronousPairingRegistry;
31 namespace {
33 void VerifyHelloResponse(scoped_ptr<base::DictionaryValue> response) {
34 ASSERT_TRUE(response);
35 std::string value;
36 EXPECT_TRUE(response->GetString("type", &value));
37 EXPECT_EQ("helloResponse", value);
38 EXPECT_TRUE(response->GetString("version", &value));
39 EXPECT_EQ(STRINGIZE(VERSION), value);
42 void VerifyGetHostNameResponse(scoped_ptr<base::DictionaryValue> response) {
43 ASSERT_TRUE(response);
44 std::string value;
45 EXPECT_TRUE(response->GetString("type", &value));
46 EXPECT_EQ("getHostNameResponse", value);
47 EXPECT_TRUE(response->GetString("hostname", &value));
48 EXPECT_EQ(net::GetHostName(), value);
51 void VerifyGetPinHashResponse(scoped_ptr<base::DictionaryValue> response) {
52 ASSERT_TRUE(response);
53 std::string value;
54 EXPECT_TRUE(response->GetString("type", &value));
55 EXPECT_EQ("getPinHashResponse", value);
56 EXPECT_TRUE(response->GetString("hash", &value));
57 EXPECT_EQ(remoting::MakeHostPinHash("my_host", "1234"), value);
60 void VerifyGenerateKeyPairResponse(scoped_ptr<base::DictionaryValue> response) {
61 ASSERT_TRUE(response);
62 std::string value;
63 EXPECT_TRUE(response->GetString("type", &value));
64 EXPECT_EQ("generateKeyPairResponse", value);
65 EXPECT_TRUE(response->GetString("privateKey", &value));
66 EXPECT_TRUE(response->GetString("publicKey", &value));
69 void VerifyGetDaemonConfigResponse(scoped_ptr<base::DictionaryValue> response) {
70 ASSERT_TRUE(response);
71 std::string value;
72 EXPECT_TRUE(response->GetString("type", &value));
73 EXPECT_EQ("getDaemonConfigResponse", value);
74 const base::DictionaryValue* config = nullptr;
75 EXPECT_TRUE(response->GetDictionary("config", &config));
76 EXPECT_TRUE(base::DictionaryValue().Equals(config));
79 void VerifyGetUsageStatsConsentResponse(
80 scoped_ptr<base::DictionaryValue> response) {
81 ASSERT_TRUE(response);
82 std::string value;
83 EXPECT_TRUE(response->GetString("type", &value));
84 EXPECT_EQ("getUsageStatsConsentResponse", value);
85 bool supported, allowed, set_by_policy;
86 EXPECT_TRUE(response->GetBoolean("supported", &supported));
87 EXPECT_TRUE(response->GetBoolean("allowed", &allowed));
88 EXPECT_TRUE(response->GetBoolean("setByPolicy", &set_by_policy));
89 EXPECT_TRUE(supported);
90 EXPECT_TRUE(allowed);
91 EXPECT_TRUE(set_by_policy);
94 void VerifyStopDaemonResponse(scoped_ptr<base::DictionaryValue> response) {
95 ASSERT_TRUE(response);
96 std::string value;
97 EXPECT_TRUE(response->GetString("type", &value));
98 EXPECT_EQ("stopDaemonResponse", value);
99 EXPECT_TRUE(response->GetString("result", &value));
100 EXPECT_EQ("OK", value);
103 void VerifyGetDaemonStateResponse(scoped_ptr<base::DictionaryValue> response) {
104 ASSERT_TRUE(response);
105 std::string value;
106 EXPECT_TRUE(response->GetString("type", &value));
107 EXPECT_EQ("getDaemonStateResponse", value);
108 EXPECT_TRUE(response->GetString("state", &value));
109 EXPECT_EQ("STARTED", value);
112 void VerifyUpdateDaemonConfigResponse(
113 scoped_ptr<base::DictionaryValue> response) {
114 ASSERT_TRUE(response);
115 std::string value;
116 EXPECT_TRUE(response->GetString("type", &value));
117 EXPECT_EQ("updateDaemonConfigResponse", value);
118 EXPECT_TRUE(response->GetString("result", &value));
119 EXPECT_EQ("OK", value);
122 void VerifyStartDaemonResponse(scoped_ptr<base::DictionaryValue> response) {
123 ASSERT_TRUE(response);
124 std::string value;
125 EXPECT_TRUE(response->GetString("type", &value));
126 EXPECT_EQ("startDaemonResponse", value);
127 EXPECT_TRUE(response->GetString("result", &value));
128 EXPECT_EQ("OK", value);
131 } // namespace
133 namespace remoting {
135 class MockDaemonControllerDelegate : public DaemonController::Delegate {
136 public:
137 MockDaemonControllerDelegate();
138 ~MockDaemonControllerDelegate() override;
140 // DaemonController::Delegate interface.
141 DaemonController::State GetState() override;
142 scoped_ptr<base::DictionaryValue> GetConfig() override;
143 void SetConfigAndStart(
144 scoped_ptr<base::DictionaryValue> config,
145 bool consent,
146 const DaemonController::CompletionCallback& done) override;
147 void UpdateConfig(scoped_ptr<base::DictionaryValue> config,
148 const DaemonController::CompletionCallback& done) override;
149 void Stop(const DaemonController::CompletionCallback& done) override;
150 DaemonController::UsageStatsConsent GetUsageStatsConsent() override;
152 private:
153 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate);
156 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
158 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
160 DaemonController::State MockDaemonControllerDelegate::GetState() {
161 return DaemonController::STATE_STARTED;
164 scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() {
165 return make_scoped_ptr(new base::DictionaryValue());
168 void MockDaemonControllerDelegate::SetConfigAndStart(
169 scoped_ptr<base::DictionaryValue> config,
170 bool consent,
171 const DaemonController::CompletionCallback& done) {
173 // Verify parameters passed in.
174 if (consent && config && config->HasKey("start")) {
175 done.Run(DaemonController::RESULT_OK);
176 } else {
177 done.Run(DaemonController::RESULT_FAILED);
181 void MockDaemonControllerDelegate::UpdateConfig(
182 scoped_ptr<base::DictionaryValue> config,
183 const DaemonController::CompletionCallback& done) {
184 if (config && config->HasKey("update")) {
185 done.Run(DaemonController::RESULT_OK);
186 } else {
187 done.Run(DaemonController::RESULT_FAILED);
191 void MockDaemonControllerDelegate::Stop(
192 const DaemonController::CompletionCallback& done) {
193 done.Run(DaemonController::RESULT_OK);
196 DaemonController::UsageStatsConsent
197 MockDaemonControllerDelegate::GetUsageStatsConsent() {
198 DaemonController::UsageStatsConsent consent;
199 consent.supported = true;
200 consent.allowed = true;
201 consent.set_by_policy = true;
202 return consent;
205 class Me2MeNativeMessagingHostTest : public testing::Test {
206 public:
207 Me2MeNativeMessagingHostTest();
208 ~Me2MeNativeMessagingHostTest() override;
210 void SetUp() override;
211 void TearDown() override;
213 scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe();
215 void WriteMessageToInputPipe(const base::Value& message);
217 // The Host process should shut down when it receives a malformed request.
218 // This is tested by sending a known-good request, followed by |message|,
219 // followed by the known-good request again. The response file should only
220 // contain a single response from the first good request.
221 void TestBadRequest(const base::Value& message);
223 protected:
224 // Reference to the MockDaemonControllerDelegate, which is owned by
225 // |channel_|.
226 MockDaemonControllerDelegate* daemon_controller_delegate_;
228 private:
229 void StartHost();
230 void StopHost();
231 void ExitTest();
233 // Each test creates two unidirectional pipes: "input" and "output".
234 // Me2MeNativeMessagingHost reads from input_read_handle and writes to
235 // output_write_file. The unittest supplies data to input_write_handle, and
236 // verifies output from output_read_handle.
238 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
239 base::File input_write_file_;
240 base::File output_read_file_;
242 // Message loop of the test thread.
243 scoped_ptr<base::MessageLoop> test_message_loop_;
244 scoped_ptr<base::RunLoop> test_run_loop_;
246 scoped_ptr<base::Thread> host_thread_;
247 scoped_ptr<base::RunLoop> host_run_loop_;
249 // Task runner of the host thread.
250 scoped_refptr<AutoThreadTaskRunner> host_task_runner_;
251 scoped_ptr<remoting::Me2MeNativeMessagingHost> host_;
253 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest);
256 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
258 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
260 void Me2MeNativeMessagingHostTest::SetUp() {
261 base::File input_read_file;
262 base::File output_write_file;
264 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
265 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
267 test_message_loop_.reset(new base::MessageLoop());
268 test_run_loop_.reset(new base::RunLoop());
270 // Run the host on a dedicated thread.
271 host_thread_.reset(new base::Thread("host_thread"));
272 host_thread_->Start();
274 // Arrange to run |test_message_loop_| until no components depend on it.
275 host_task_runner_ = new AutoThreadTaskRunner(
276 host_thread_->message_loop_proxy(),
277 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
278 base::Unretained(this)));
280 host_task_runner_->PostTask(
281 FROM_HERE,
282 base::Bind(&Me2MeNativeMessagingHostTest::StartHost,
283 base::Unretained(this)));
285 // Wait until the host finishes starting.
286 test_run_loop_->Run();
289 void Me2MeNativeMessagingHostTest::StartHost() {
290 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
292 base::File input_read_file;
293 base::File output_write_file;
295 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
296 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
298 daemon_controller_delegate_ = new MockDaemonControllerDelegate();
299 scoped_refptr<DaemonController> daemon_controller(
300 new DaemonController(make_scoped_ptr(daemon_controller_delegate_)));
302 scoped_refptr<PairingRegistry> pairing_registry =
303 new SynchronousPairingRegistry(
304 make_scoped_ptr(new MockPairingRegistryDelegate()));
306 scoped_ptr<extensions::NativeMessagingChannel> channel(
307 new PipeMessagingChannel(input_read_file.Pass(),
308 output_write_file.Pass()));
310 host_.reset(new Me2MeNativeMessagingHost(
311 false, 0, channel.Pass(), daemon_controller, pairing_registry, nullptr));
312 host_->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost,
313 base::Unretained(this)));
315 // Notify the test that the host has finished starting up.
316 test_message_loop_->message_loop_proxy()->PostTask(
317 FROM_HERE, test_run_loop_->QuitClosure());
320 void Me2MeNativeMessagingHostTest::StopHost() {
321 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
323 host_.reset();
325 // Wait till all shutdown tasks have completed.
326 base::RunLoop().RunUntilIdle();
328 // Trigger a test shutdown via ExitTest().
329 host_task_runner_ = nullptr;
332 void Me2MeNativeMessagingHostTest::ExitTest() {
333 if (!test_message_loop_->message_loop_proxy()->RunsTasksOnCurrentThread()) {
334 test_message_loop_->message_loop_proxy()->PostTask(
335 FROM_HERE,
336 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
337 base::Unretained(this)));
338 return;
340 test_run_loop_->Quit();
343 void Me2MeNativeMessagingHostTest::TearDown() {
344 // Closing the write-end of the input will send an EOF to the native
345 // messaging reader. This will trigger a host shutdown.
346 input_write_file_.Close();
348 // Start a new RunLoop and Wait until the host finishes shutting down.
349 test_run_loop_.reset(new base::RunLoop());
350 test_run_loop_->Run();
352 // Verify there are no more message in the output pipe.
353 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
354 EXPECT_FALSE(response);
356 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
357 // to it. So the only handle left to close is |output_read_file_|.
358 output_read_file_.Close();
361 scoped_ptr<base::DictionaryValue>
362 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
363 uint32 length;
364 int read_result = output_read_file_.ReadAtCurrentPos(
365 reinterpret_cast<char*>(&length), sizeof(length));
366 if (read_result != sizeof(length)) {
367 return nullptr;
370 std::string message_json(length, '\0');
371 read_result = output_read_file_.ReadAtCurrentPos(
372 string_as_array(&message_json), length);
373 if (read_result != static_cast<int>(length)) {
374 return nullptr;
377 scoped_ptr<base::Value> message(base::JSONReader::Read(message_json));
378 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
379 return nullptr;
382 return make_scoped_ptr(
383 static_cast<base::DictionaryValue*>(message.release()));
386 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
387 const base::Value& message) {
388 std::string message_json;
389 base::JSONWriter::Write(&message, &message_json);
391 uint32 length = message_json.length();
392 input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
393 sizeof(length));
394 input_write_file_.WriteAtCurrentPos(message_json.data(), length);
397 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value& message) {
398 base::DictionaryValue good_message;
399 good_message.SetString("type", "hello");
401 // This test currently relies on synchronous processing of hello messages and
402 // message parameters verification.
403 WriteMessageToInputPipe(good_message);
404 WriteMessageToInputPipe(message);
405 WriteMessageToInputPipe(good_message);
407 // Read from output pipe, and verify responses.
408 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
409 VerifyHelloResponse(response.Pass());
411 response = ReadMessageFromOutputPipe();
412 EXPECT_FALSE(response);
415 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
416 // Test all valid request-types.
417 TEST_F(Me2MeNativeMessagingHostTest, All) {
418 int next_id = 0;
419 base::DictionaryValue message;
420 message.SetInteger("id", next_id++);
421 message.SetString("type", "hello");
422 WriteMessageToInputPipe(message);
424 message.SetInteger("id", next_id++);
425 message.SetString("type", "getHostName");
426 WriteMessageToInputPipe(message);
428 message.SetInteger("id", next_id++);
429 message.SetString("type", "getPinHash");
430 message.SetString("hostId", "my_host");
431 message.SetString("pin", "1234");
432 WriteMessageToInputPipe(message);
434 message.Clear();
435 message.SetInteger("id", next_id++);
436 message.SetString("type", "generateKeyPair");
437 WriteMessageToInputPipe(message);
439 message.SetInteger("id", next_id++);
440 message.SetString("type", "getDaemonConfig");
441 WriteMessageToInputPipe(message);
443 message.SetInteger("id", next_id++);
444 message.SetString("type", "getUsageStatsConsent");
445 WriteMessageToInputPipe(message);
447 message.SetInteger("id", next_id++);
448 message.SetString("type", "stopDaemon");
449 WriteMessageToInputPipe(message);
451 message.SetInteger("id", next_id++);
452 message.SetString("type", "getDaemonState");
453 WriteMessageToInputPipe(message);
455 // Following messages require a "config" dictionary.
456 base::DictionaryValue config;
457 config.SetBoolean("update", true);
458 message.Set("config", config.DeepCopy());
459 message.SetInteger("id", next_id++);
460 message.SetString("type", "updateDaemonConfig");
461 WriteMessageToInputPipe(message);
463 config.Clear();
464 config.SetBoolean("start", true);
465 message.Set("config", config.DeepCopy());
466 message.SetBoolean("consent", true);
467 message.SetInteger("id", next_id++);
468 message.SetString("type", "startDaemon");
469 WriteMessageToInputPipe(message);
471 void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = {
472 &VerifyHelloResponse,
473 &VerifyGetHostNameResponse,
474 &VerifyGetPinHashResponse,
475 &VerifyGenerateKeyPairResponse,
476 &VerifyGetDaemonConfigResponse,
477 &VerifyGetUsageStatsConsentResponse,
478 &VerifyStopDaemonResponse,
479 &VerifyGetDaemonStateResponse,
480 &VerifyUpdateDaemonConfigResponse,
481 &VerifyStartDaemonResponse,
483 ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id));
485 // Read all responses from output pipe, and verify them.
486 for (int i = 0; i < next_id; ++i) {
487 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
489 // Make sure that id is available and is in the range.
490 int id;
491 ASSERT_TRUE(response->GetInteger("id", &id));
492 ASSERT_TRUE(0 <= id && id < next_id);
494 // Call the verification routine corresponding to the message id.
495 ASSERT_TRUE(verify_routines[id]);
496 verify_routines[id](response.Pass());
498 // Clear the pointer so that the routine cannot be called the second time.
499 verify_routines[id] = nullptr;
503 // Verify that response ID matches request ID.
504 TEST_F(Me2MeNativeMessagingHostTest, Id) {
505 base::DictionaryValue message;
506 message.SetString("type", "hello");
507 WriteMessageToInputPipe(message);
508 message.SetString("id", "42");
509 WriteMessageToInputPipe(message);
511 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
512 EXPECT_TRUE(response);
513 std::string value;
514 EXPECT_FALSE(response->GetString("id", &value));
516 response = ReadMessageFromOutputPipe();
517 EXPECT_TRUE(response);
518 EXPECT_TRUE(response->GetString("id", &value));
519 EXPECT_EQ("42", value);
522 // Verify non-Dictionary requests are rejected.
523 TEST_F(Me2MeNativeMessagingHostTest, WrongFormat) {
524 base::ListValue message;
525 TestBadRequest(message);
528 // Verify requests with no type are rejected.
529 TEST_F(Me2MeNativeMessagingHostTest, MissingType) {
530 base::DictionaryValue message;
531 TestBadRequest(message);
534 // Verify rejection if type is unrecognized.
535 TEST_F(Me2MeNativeMessagingHostTest, InvalidType) {
536 base::DictionaryValue message;
537 message.SetString("type", "xxx");
538 TestBadRequest(message);
541 // Verify rejection if getPinHash request has no hostId.
542 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoHostId) {
543 base::DictionaryValue message;
544 message.SetString("type", "getPinHash");
545 message.SetString("pin", "1234");
546 TestBadRequest(message);
549 // Verify rejection if getPinHash request has no pin.
550 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoPin) {
551 base::DictionaryValue message;
552 message.SetString("type", "getPinHash");
553 message.SetString("hostId", "my_host");
554 TestBadRequest(message);
557 // Verify rejection if updateDaemonConfig request has invalid config.
558 TEST_F(Me2MeNativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
559 base::DictionaryValue message;
560 message.SetString("type", "updateDaemonConfig");
561 message.SetString("config", "xxx");
562 TestBadRequest(message);
565 // Verify rejection if startDaemon request has invalid config.
566 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonInvalidConfig) {
567 base::DictionaryValue message;
568 message.SetString("type", "startDaemon");
569 message.SetString("config", "xxx");
570 message.SetBoolean("consent", true);
571 TestBadRequest(message);
574 // Verify rejection if startDaemon request has no "consent" parameter.
575 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonNoConsent) {
576 base::DictionaryValue message;
577 message.SetString("type", "startDaemon");
578 message.Set("config", base::DictionaryValue().DeepCopy());
579 TestBadRequest(message);
582 } // namespace remoting