Add explicit |forceOnlineSignin| to user pod status
[chromium-blink-merge.git] / remoting / host / setup / me2me_native_messaging_host_unittest.cc
blobd66a4d92b14411cf6c0a8b8a1edd79685d78739e
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/native_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 = NULL;
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 virtual ~MockDaemonControllerDelegate();
140 // DaemonController::Delegate interface.
141 virtual DaemonController::State GetState() OVERRIDE;
142 virtual scoped_ptr<base::DictionaryValue> GetConfig() OVERRIDE;
143 virtual void SetConfigAndStart(
144 scoped_ptr<base::DictionaryValue> config,
145 bool consent,
146 const DaemonController::CompletionCallback& done) OVERRIDE;
147 virtual void UpdateConfig(
148 scoped_ptr<base::DictionaryValue> config,
149 const DaemonController::CompletionCallback& done) OVERRIDE;
150 virtual void Stop(const DaemonController::CompletionCallback& done) OVERRIDE;
151 virtual void SetWindow(void* window_handle) OVERRIDE;
152 virtual std::string GetVersion() OVERRIDE;
153 virtual DaemonController::UsageStatsConsent GetUsageStatsConsent() OVERRIDE;
155 private:
156 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate);
159 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
161 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
163 DaemonController::State MockDaemonControllerDelegate::GetState() {
164 return DaemonController::STATE_STARTED;
167 scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() {
168 return scoped_ptr<base::DictionaryValue>(new base::DictionaryValue());
171 void MockDaemonControllerDelegate::SetConfigAndStart(
172 scoped_ptr<base::DictionaryValue> config,
173 bool consent,
174 const DaemonController::CompletionCallback& done) {
176 // Verify parameters passed in.
177 if (consent && config && config->HasKey("start")) {
178 done.Run(DaemonController::RESULT_OK);
179 } else {
180 done.Run(DaemonController::RESULT_FAILED);
184 void MockDaemonControllerDelegate::UpdateConfig(
185 scoped_ptr<base::DictionaryValue> config,
186 const DaemonController::CompletionCallback& done) {
187 if (config && config->HasKey("update")) {
188 done.Run(DaemonController::RESULT_OK);
189 } else {
190 done.Run(DaemonController::RESULT_FAILED);
194 void MockDaemonControllerDelegate::Stop(
195 const DaemonController::CompletionCallback& done) {
196 done.Run(DaemonController::RESULT_OK);
199 void MockDaemonControllerDelegate::SetWindow(void* window_handle) {}
201 std::string MockDaemonControllerDelegate::GetVersion() {
202 // Unused - Me2MeNativeMessagingHost returns the compiled-in version string
203 // instead of calling this method.
204 NOTREACHED();
205 return std::string();
208 DaemonController::UsageStatsConsent
209 MockDaemonControllerDelegate::GetUsageStatsConsent() {
210 DaemonController::UsageStatsConsent consent;
211 consent.supported = true;
212 consent.allowed = true;
213 consent.set_by_policy = true;
214 return consent;
217 class Me2MeNativeMessagingHostTest : public testing::Test {
218 public:
219 Me2MeNativeMessagingHostTest();
220 virtual ~Me2MeNativeMessagingHostTest();
222 virtual void SetUp() OVERRIDE;
223 virtual void TearDown() OVERRIDE;
225 scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe();
227 void WriteMessageToInputPipe(const base::Value& message);
229 // The Host process should shut down when it receives a malformed request.
230 // This is tested by sending a known-good request, followed by |message|,
231 // followed by the known-good request again. The response file should only
232 // contain a single response from the first good request.
233 void TestBadRequest(const base::Value& message);
235 protected:
236 // Reference to the MockDaemonControllerDelegate, which is owned by
237 // |channel_|.
238 MockDaemonControllerDelegate* daemon_controller_delegate_;
240 private:
241 void StartHost();
242 void StopHost();
243 void ExitTest();
245 // Each test creates two unidirectional pipes: "input" and "output".
246 // Me2MeNativeMessagingHost reads from input_read_handle and writes to
247 // output_write_handle. The unittest supplies data to input_write_handle, and
248 // verifies output from output_read_handle.
250 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
251 base::PlatformFile input_write_handle_;
252 base::PlatformFile output_read_handle_;
254 // Message loop of the test thread.
255 scoped_ptr<base::MessageLoop> test_message_loop_;
256 scoped_ptr<base::RunLoop> test_run_loop_;
258 scoped_ptr<base::Thread> host_thread_;
259 scoped_ptr<base::RunLoop> host_run_loop_;
261 // Task runner of the host thread.
262 scoped_refptr<AutoThreadTaskRunner> host_task_runner_;
263 scoped_ptr<remoting::Me2MeNativeMessagingHost> host_;
265 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest);
268 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
270 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
272 void Me2MeNativeMessagingHostTest::SetUp() {
273 base::PlatformFile input_read_handle;
274 base::PlatformFile output_write_handle;
276 ASSERT_TRUE(MakePipe(&input_read_handle, &input_write_handle_));
277 ASSERT_TRUE(MakePipe(&output_read_handle_, &output_write_handle));
279 test_message_loop_.reset(new base::MessageLoop());
280 test_run_loop_.reset(new base::RunLoop());
282 // Run the host on a dedicated thread.
283 host_thread_.reset(new base::Thread("host_thread"));
284 host_thread_->Start();
286 // Arrange to run |test_message_loop_| until no components depend on it.
287 host_task_runner_ = new AutoThreadTaskRunner(
288 host_thread_->message_loop_proxy(),
289 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
290 base::Unretained(this)));
292 host_task_runner_->PostTask(
293 FROM_HERE,
294 base::Bind(&Me2MeNativeMessagingHostTest::StartHost,
295 base::Unretained(this)));
297 // Wait until the host finishes starting.
298 test_run_loop_->Run();
301 void Me2MeNativeMessagingHostTest::StartHost() {
302 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
304 base::PlatformFile input_read_handle;
305 base::PlatformFile output_write_handle;
307 ASSERT_TRUE(MakePipe(&input_read_handle, &input_write_handle_));
308 ASSERT_TRUE(MakePipe(&output_read_handle_, &output_write_handle));
310 daemon_controller_delegate_ = new MockDaemonControllerDelegate();
311 scoped_refptr<DaemonController> daemon_controller(
312 new DaemonController(
313 scoped_ptr<DaemonController::Delegate>(daemon_controller_delegate_)));
315 scoped_refptr<PairingRegistry> pairing_registry =
316 new SynchronousPairingRegistry(scoped_ptr<PairingRegistry::Delegate>(
317 new MockPairingRegistryDelegate()));
319 scoped_ptr<NativeMessagingChannel> channel(
320 new NativeMessagingChannel(input_read_handle, output_write_handle));
322 host_.reset(new Me2MeNativeMessagingHost(channel.Pass(),
323 daemon_controller,
324 pairing_registry,
325 scoped_ptr<remoting::OAuthClient>()));
326 host_->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost,
327 base::Unretained(this)));
329 // Notify the test that the host has finished starting up.
330 test_message_loop_->message_loop_proxy()->PostTask(
331 FROM_HERE, test_run_loop_->QuitClosure());
334 void Me2MeNativeMessagingHostTest::StopHost() {
335 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
337 host_.reset();
339 // Wait till all shutdown tasks have completed.
340 base::MessageLoop::current()->RunUntilIdle();
342 // Trigger a test shutdown via ExitTest().
343 host_task_runner_ = NULL;
346 void Me2MeNativeMessagingHostTest::ExitTest() {
347 if (!test_message_loop_->message_loop_proxy()->RunsTasksOnCurrentThread()) {
348 test_message_loop_->message_loop_proxy()->PostTask(
349 FROM_HERE,
350 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
351 base::Unretained(this)));
352 return;
354 test_run_loop_->Quit();
357 void Me2MeNativeMessagingHostTest::TearDown() {
358 // Closing the write-end of the input will send an EOF to the native
359 // messaging reader. This will trigger a host shutdown.
360 base::ClosePlatformFile(input_write_handle_);
362 // Start a new RunLoop and Wait until the host finishes shutting down.
363 test_run_loop_.reset(new base::RunLoop());
364 test_run_loop_->Run();
366 // Verify there are no more message in the output pipe.
367 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
368 EXPECT_FALSE(response);
370 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
371 // to it. So the only handle left to close is |output_read_handle_|.
372 base::ClosePlatformFile(output_read_handle_);
375 scoped_ptr<base::DictionaryValue>
376 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
377 uint32 length;
378 int read_result = base::ReadPlatformFileAtCurrentPos(
379 output_read_handle_, reinterpret_cast<char*>(&length), sizeof(length));
380 if (read_result != sizeof(length)) {
381 return scoped_ptr<base::DictionaryValue>();
384 std::string message_json(length, '\0');
385 read_result = base::ReadPlatformFileAtCurrentPos(
386 output_read_handle_, string_as_array(&message_json), length);
387 if (read_result != static_cast<int>(length)) {
388 return scoped_ptr<base::DictionaryValue>();
391 scoped_ptr<base::Value> message(base::JSONReader::Read(message_json));
392 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
393 return scoped_ptr<base::DictionaryValue>();
396 return scoped_ptr<base::DictionaryValue>(
397 static_cast<base::DictionaryValue*>(message.release()));
400 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
401 const base::Value& message) {
402 std::string message_json;
403 base::JSONWriter::Write(&message, &message_json);
405 uint32 length = message_json.length();
406 base::WritePlatformFileAtCurrentPos(input_write_handle_,
407 reinterpret_cast<char*>(&length),
408 sizeof(length));
409 base::WritePlatformFileAtCurrentPos(input_write_handle_, message_json.data(),
410 length);
413 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value& message) {
414 base::DictionaryValue good_message;
415 good_message.SetString("type", "hello");
417 // This test currently relies on synchronous processing of hello messages and
418 // message parameters verification.
419 WriteMessageToInputPipe(good_message);
420 WriteMessageToInputPipe(message);
421 WriteMessageToInputPipe(good_message);
423 // Read from output pipe, and verify responses.
424 scoped_ptr<base::DictionaryValue> response =
425 ReadMessageFromOutputPipe();
426 VerifyHelloResponse(response.Pass());
428 response = ReadMessageFromOutputPipe();
429 EXPECT_FALSE(response);
432 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
433 // Test all valid request-types.
434 TEST_F(Me2MeNativeMessagingHostTest, All) {
435 int next_id = 0;
436 base::DictionaryValue message;
437 message.SetInteger("id", next_id++);
438 message.SetString("type", "hello");
439 WriteMessageToInputPipe(message);
441 message.SetInteger("id", next_id++);
442 message.SetString("type", "getHostName");
443 WriteMessageToInputPipe(message);
445 message.SetInteger("id", next_id++);
446 message.SetString("type", "getPinHash");
447 message.SetString("hostId", "my_host");
448 message.SetString("pin", "1234");
449 WriteMessageToInputPipe(message);
451 message.Clear();
452 message.SetInteger("id", next_id++);
453 message.SetString("type", "generateKeyPair");
454 WriteMessageToInputPipe(message);
456 message.SetInteger("id", next_id++);
457 message.SetString("type", "getDaemonConfig");
458 WriteMessageToInputPipe(message);
460 message.SetInteger("id", next_id++);
461 message.SetString("type", "getUsageStatsConsent");
462 WriteMessageToInputPipe(message);
464 message.SetInteger("id", next_id++);
465 message.SetString("type", "stopDaemon");
466 WriteMessageToInputPipe(message);
468 message.SetInteger("id", next_id++);
469 message.SetString("type", "getDaemonState");
470 WriteMessageToInputPipe(message);
472 // Following messages require a "config" dictionary.
473 base::DictionaryValue config;
474 config.SetBoolean("update", true);
475 message.Set("config", config.DeepCopy());
476 message.SetInteger("id", next_id++);
477 message.SetString("type", "updateDaemonConfig");
478 WriteMessageToInputPipe(message);
480 config.Clear();
481 config.SetBoolean("start", true);
482 message.Set("config", config.DeepCopy());
483 message.SetBoolean("consent", true);
484 message.SetInteger("id", next_id++);
485 message.SetString("type", "startDaemon");
486 WriteMessageToInputPipe(message);
488 void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = {
489 &VerifyHelloResponse,
490 &VerifyGetHostNameResponse,
491 &VerifyGetPinHashResponse,
492 &VerifyGenerateKeyPairResponse,
493 &VerifyGetDaemonConfigResponse,
494 &VerifyGetUsageStatsConsentResponse,
495 &VerifyStopDaemonResponse,
496 &VerifyGetDaemonStateResponse,
497 &VerifyUpdateDaemonConfigResponse,
498 &VerifyStartDaemonResponse,
500 ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id));
502 // Read all responses from output pipe, and verify them.
503 for (int i = 0; i < next_id; ++i) {
504 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
506 // Make sure that id is available and is in the range.
507 int id;
508 ASSERT_TRUE(response->GetInteger("id", &id));
509 ASSERT_TRUE(0 <= id && id < next_id);
511 // Call the verification routine corresponding to the message id.
512 ASSERT_TRUE(verify_routines[id]);
513 verify_routines[id](response.Pass());
515 // Clear the pointer so that the routine cannot be called the second time.
516 verify_routines[id] = NULL;
520 // Verify that response ID matches request ID.
521 TEST_F(Me2MeNativeMessagingHostTest, Id) {
522 base::DictionaryValue message;
523 message.SetString("type", "hello");
524 WriteMessageToInputPipe(message);
525 message.SetString("id", "42");
526 WriteMessageToInputPipe(message);
528 scoped_ptr<base::DictionaryValue> response =
529 ReadMessageFromOutputPipe();
530 EXPECT_TRUE(response);
531 std::string value;
532 EXPECT_FALSE(response->GetString("id", &value));
534 response = ReadMessageFromOutputPipe();
535 EXPECT_TRUE(response);
536 EXPECT_TRUE(response->GetString("id", &value));
537 EXPECT_EQ("42", value);
540 // Verify non-Dictionary requests are rejected.
541 TEST_F(Me2MeNativeMessagingHostTest, WrongFormat) {
542 base::ListValue message;
543 TestBadRequest(message);
546 // Verify requests with no type are rejected.
547 TEST_F(Me2MeNativeMessagingHostTest, MissingType) {
548 base::DictionaryValue message;
549 TestBadRequest(message);
552 // Verify rejection if type is unrecognized.
553 TEST_F(Me2MeNativeMessagingHostTest, InvalidType) {
554 base::DictionaryValue message;
555 message.SetString("type", "xxx");
556 TestBadRequest(message);
559 // Verify rejection if getPinHash request has no hostId.
560 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoHostId) {
561 base::DictionaryValue message;
562 message.SetString("type", "getPinHash");
563 message.SetString("pin", "1234");
564 TestBadRequest(message);
567 // Verify rejection if getPinHash request has no pin.
568 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoPin) {
569 base::DictionaryValue message;
570 message.SetString("type", "getPinHash");
571 message.SetString("hostId", "my_host");
572 TestBadRequest(message);
575 // Verify rejection if updateDaemonConfig request has invalid config.
576 TEST_F(Me2MeNativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
577 base::DictionaryValue message;
578 message.SetString("type", "updateDaemonConfig");
579 message.SetString("config", "xxx");
580 TestBadRequest(message);
583 // Verify rejection if startDaemon request has invalid config.
584 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonInvalidConfig) {
585 base::DictionaryValue message;
586 message.SetString("type", "startDaemon");
587 message.SetString("config", "xxx");
588 message.SetBoolean("consent", true);
589 TestBadRequest(message);
592 // Verify rejection if startDaemon request has no "consent" parameter.
593 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonNoConsent) {
594 base::DictionaryValue message;
595 message.SetString("type", "startDaemon");
596 message.Set("config", base::DictionaryValue().DeepCopy());
597 TestBadRequest(message);
600 } // namespace remoting