Clean up extension confirmation prompts and make them consistent between Views and...
[chromium-blink-merge.git] / remoting / host / setup / me2me_native_messaging_host_unittest.cc
blob922f9965c0ba68053b59e9a6dca10f3cead28c31
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/mock_oauth_client.h"
23 #include "remoting/host/setup/test_util.h"
24 #include "remoting/protocol/pairing_registry.h"
25 #include "remoting/protocol/protocol_mock_objects.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 using remoting::protocol::MockPairingRegistryDelegate;
29 using remoting::protocol::PairingRegistry;
30 using remoting::protocol::SynchronousPairingRegistry;
32 namespace {
34 void VerifyHelloResponse(scoped_ptr<base::DictionaryValue> response) {
35 ASSERT_TRUE(response);
36 std::string value;
37 EXPECT_TRUE(response->GetString("type", &value));
38 EXPECT_EQ("helloResponse", value);
39 EXPECT_TRUE(response->GetString("version", &value));
41 // The check below will compile but fail if VERSION isn't defined (STRINGIZE
42 // silently converts undefined values).
43 #ifndef VERSION
44 #error VERSION must be defined
45 #endif
46 EXPECT_EQ(STRINGIZE(VERSION), value);
49 void VerifyGetHostNameResponse(scoped_ptr<base::DictionaryValue> response) {
50 ASSERT_TRUE(response);
51 std::string value;
52 EXPECT_TRUE(response->GetString("type", &value));
53 EXPECT_EQ("getHostNameResponse", value);
54 EXPECT_TRUE(response->GetString("hostname", &value));
55 EXPECT_EQ(net::GetHostName(), value);
58 void VerifyGetPinHashResponse(scoped_ptr<base::DictionaryValue> response) {
59 ASSERT_TRUE(response);
60 std::string value;
61 EXPECT_TRUE(response->GetString("type", &value));
62 EXPECT_EQ("getPinHashResponse", value);
63 EXPECT_TRUE(response->GetString("hash", &value));
64 EXPECT_EQ(remoting::MakeHostPinHash("my_host", "1234"), value);
67 void VerifyGenerateKeyPairResponse(scoped_ptr<base::DictionaryValue> response) {
68 ASSERT_TRUE(response);
69 std::string value;
70 EXPECT_TRUE(response->GetString("type", &value));
71 EXPECT_EQ("generateKeyPairResponse", value);
72 EXPECT_TRUE(response->GetString("privateKey", &value));
73 EXPECT_TRUE(response->GetString("publicKey", &value));
76 void VerifyGetDaemonConfigResponse(scoped_ptr<base::DictionaryValue> response) {
77 ASSERT_TRUE(response);
78 std::string value;
79 EXPECT_TRUE(response->GetString("type", &value));
80 EXPECT_EQ("getDaemonConfigResponse", value);
81 const base::DictionaryValue* config = nullptr;
82 EXPECT_TRUE(response->GetDictionary("config", &config));
83 EXPECT_TRUE(base::DictionaryValue().Equals(config));
86 void VerifyGetUsageStatsConsentResponse(
87 scoped_ptr<base::DictionaryValue> response) {
88 ASSERT_TRUE(response);
89 std::string value;
90 EXPECT_TRUE(response->GetString("type", &value));
91 EXPECT_EQ("getUsageStatsConsentResponse", value);
92 bool supported, allowed, set_by_policy;
93 EXPECT_TRUE(response->GetBoolean("supported", &supported));
94 EXPECT_TRUE(response->GetBoolean("allowed", &allowed));
95 EXPECT_TRUE(response->GetBoolean("setByPolicy", &set_by_policy));
96 EXPECT_TRUE(supported);
97 EXPECT_TRUE(allowed);
98 EXPECT_TRUE(set_by_policy);
101 void VerifyStopDaemonResponse(scoped_ptr<base::DictionaryValue> response) {
102 ASSERT_TRUE(response);
103 std::string value;
104 EXPECT_TRUE(response->GetString("type", &value));
105 EXPECT_EQ("stopDaemonResponse", value);
106 EXPECT_TRUE(response->GetString("result", &value));
107 EXPECT_EQ("OK", value);
110 void VerifyGetDaemonStateResponse(scoped_ptr<base::DictionaryValue> response) {
111 ASSERT_TRUE(response);
112 std::string value;
113 EXPECT_TRUE(response->GetString("type", &value));
114 EXPECT_EQ("getDaemonStateResponse", value);
115 EXPECT_TRUE(response->GetString("state", &value));
116 EXPECT_EQ("STARTED", value);
119 void VerifyUpdateDaemonConfigResponse(
120 scoped_ptr<base::DictionaryValue> response) {
121 ASSERT_TRUE(response);
122 std::string value;
123 EXPECT_TRUE(response->GetString("type", &value));
124 EXPECT_EQ("updateDaemonConfigResponse", value);
125 EXPECT_TRUE(response->GetString("result", &value));
126 EXPECT_EQ("OK", value);
129 void VerifyStartDaemonResponse(scoped_ptr<base::DictionaryValue> response) {
130 ASSERT_TRUE(response);
131 std::string value;
132 EXPECT_TRUE(response->GetString("type", &value));
133 EXPECT_EQ("startDaemonResponse", value);
134 EXPECT_TRUE(response->GetString("result", &value));
135 EXPECT_EQ("OK", value);
138 void VerifyGetCredentialsFromAuthCodeResponse(
139 scoped_ptr<base::DictionaryValue> response) {
140 ASSERT_TRUE(response);
141 std::string value;
142 EXPECT_TRUE(response->GetString("type", &value));
143 EXPECT_EQ("getCredentialsFromAuthCodeResponse", value);
144 EXPECT_TRUE(response->GetString("userEmail", &value));
145 EXPECT_EQ("fake_user_email", value);
146 EXPECT_TRUE(response->GetString("refreshToken", &value));
147 EXPECT_EQ("fake_refresh_token", value);
150 } // namespace
152 namespace remoting {
154 class MockDaemonControllerDelegate : public DaemonController::Delegate {
155 public:
156 MockDaemonControllerDelegate();
157 ~MockDaemonControllerDelegate() override;
159 // DaemonController::Delegate interface.
160 DaemonController::State GetState() override;
161 scoped_ptr<base::DictionaryValue> GetConfig() override;
162 void SetConfigAndStart(
163 scoped_ptr<base::DictionaryValue> config,
164 bool consent,
165 const DaemonController::CompletionCallback& done) override;
166 void UpdateConfig(scoped_ptr<base::DictionaryValue> config,
167 const DaemonController::CompletionCallback& done) override;
168 void Stop(const DaemonController::CompletionCallback& done) override;
169 DaemonController::UsageStatsConsent GetUsageStatsConsent() override;
171 private:
172 DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate);
175 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
177 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
179 DaemonController::State MockDaemonControllerDelegate::GetState() {
180 return DaemonController::STATE_STARTED;
183 scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() {
184 return make_scoped_ptr(new base::DictionaryValue());
187 void MockDaemonControllerDelegate::SetConfigAndStart(
188 scoped_ptr<base::DictionaryValue> config,
189 bool consent,
190 const DaemonController::CompletionCallback& done) {
192 // Verify parameters passed in.
193 if (consent && config && config->HasKey("start")) {
194 done.Run(DaemonController::RESULT_OK);
195 } else {
196 done.Run(DaemonController::RESULT_FAILED);
200 void MockDaemonControllerDelegate::UpdateConfig(
201 scoped_ptr<base::DictionaryValue> config,
202 const DaemonController::CompletionCallback& done) {
203 if (config && config->HasKey("update")) {
204 done.Run(DaemonController::RESULT_OK);
205 } else {
206 done.Run(DaemonController::RESULT_FAILED);
210 void MockDaemonControllerDelegate::Stop(
211 const DaemonController::CompletionCallback& done) {
212 done.Run(DaemonController::RESULT_OK);
215 DaemonController::UsageStatsConsent
216 MockDaemonControllerDelegate::GetUsageStatsConsent() {
217 DaemonController::UsageStatsConsent consent;
218 consent.supported = true;
219 consent.allowed = true;
220 consent.set_by_policy = true;
221 return consent;
224 class Me2MeNativeMessagingHostTest : public testing::Test {
225 public:
226 Me2MeNativeMessagingHostTest();
227 ~Me2MeNativeMessagingHostTest() override;
229 void SetUp() override;
230 void TearDown() override;
232 scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe();
234 void WriteMessageToInputPipe(const base::Value& message);
236 // The Host process should shut down when it receives a malformed request.
237 // This is tested by sending a known-good request, followed by |message|,
238 // followed by the known-good request again. The response file should only
239 // contain a single response from the first good request.
240 void TestBadRequest(const base::Value& message);
242 protected:
243 // Reference to the MockDaemonControllerDelegate, which is owned by
244 // |channel_|.
245 MockDaemonControllerDelegate* daemon_controller_delegate_;
247 private:
248 void StartHost();
249 void StopHost();
250 void ExitTest();
252 // Each test creates two unidirectional pipes: "input" and "output".
253 // Me2MeNativeMessagingHost reads from input_read_handle and writes to
254 // output_write_file. The unittest supplies data to input_write_handle, and
255 // verifies output from output_read_handle.
257 // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
258 base::File input_write_file_;
259 base::File output_read_file_;
261 // Message loop of the test thread.
262 scoped_ptr<base::MessageLoop> test_message_loop_;
263 scoped_ptr<base::RunLoop> test_run_loop_;
265 scoped_ptr<base::Thread> host_thread_;
266 scoped_ptr<base::RunLoop> host_run_loop_;
268 // Task runner of the host thread.
269 scoped_refptr<AutoThreadTaskRunner> host_task_runner_;
270 scoped_ptr<remoting::Me2MeNativeMessagingHost> host_;
272 DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest);
275 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
277 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
279 void Me2MeNativeMessagingHostTest::SetUp() {
280 base::File input_read_file;
281 base::File output_write_file;
283 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
284 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
286 test_message_loop_.reset(new base::MessageLoop());
287 test_run_loop_.reset(new base::RunLoop());
289 // Run the host on a dedicated thread.
290 host_thread_.reset(new base::Thread("host_thread"));
291 host_thread_->Start();
293 // Arrange to run |test_message_loop_| until no components depend on it.
294 host_task_runner_ = new AutoThreadTaskRunner(
295 host_thread_->task_runner(),
296 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
297 base::Unretained(this)));
299 host_task_runner_->PostTask(
300 FROM_HERE,
301 base::Bind(&Me2MeNativeMessagingHostTest::StartHost,
302 base::Unretained(this)));
304 // Wait until the host finishes starting.
305 test_run_loop_->Run();
308 void Me2MeNativeMessagingHostTest::StartHost() {
309 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
311 base::File input_read_file;
312 base::File output_write_file;
314 ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
315 ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
317 daemon_controller_delegate_ = new MockDaemonControllerDelegate();
318 scoped_refptr<DaemonController> daemon_controller(
319 new DaemonController(make_scoped_ptr(daemon_controller_delegate_)));
321 scoped_refptr<PairingRegistry> pairing_registry =
322 new SynchronousPairingRegistry(
323 make_scoped_ptr(new MockPairingRegistryDelegate()));
325 scoped_ptr<extensions::NativeMessagingChannel> channel(
326 new PipeMessagingChannel(input_read_file.Pass(),
327 output_write_file.Pass()));
329 scoped_ptr<OAuthClient> oauth_client(
330 new MockOAuthClient("fake_user_email", "fake_refresh_token"));
332 host_.reset(new Me2MeNativeMessagingHost(false, 0, channel.Pass(),
333 daemon_controller, pairing_registry,
334 oauth_client.Pass()));
335 host_->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost,
336 base::Unretained(this)));
338 // Notify the test that the host has finished starting up.
339 test_message_loop_->task_runner()->PostTask(
340 FROM_HERE, test_run_loop_->QuitClosure());
343 void Me2MeNativeMessagingHostTest::StopHost() {
344 DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
346 host_.reset();
348 // Wait till all shutdown tasks have completed.
349 base::RunLoop().RunUntilIdle();
351 // Trigger a test shutdown via ExitTest().
352 host_task_runner_ = nullptr;
355 void Me2MeNativeMessagingHostTest::ExitTest() {
356 if (!test_message_loop_->task_runner()->RunsTasksOnCurrentThread()) {
357 test_message_loop_->task_runner()->PostTask(
358 FROM_HERE,
359 base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
360 base::Unretained(this)));
361 return;
363 test_run_loop_->Quit();
366 void Me2MeNativeMessagingHostTest::TearDown() {
367 // Closing the write-end of the input will send an EOF to the native
368 // messaging reader. This will trigger a host shutdown.
369 input_write_file_.Close();
371 // Start a new RunLoop and Wait until the host finishes shutting down.
372 test_run_loop_.reset(new base::RunLoop());
373 test_run_loop_->Run();
375 // Verify there are no more message in the output pipe.
376 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
377 EXPECT_FALSE(response);
379 // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
380 // to it. So the only handle left to close is |output_read_file_|.
381 output_read_file_.Close();
384 scoped_ptr<base::DictionaryValue>
385 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
386 uint32 length;
387 int read_result = output_read_file_.ReadAtCurrentPos(
388 reinterpret_cast<char*>(&length), sizeof(length));
389 if (read_result != sizeof(length)) {
390 return nullptr;
393 std::string message_json(length, '\0');
394 read_result = output_read_file_.ReadAtCurrentPos(
395 string_as_array(&message_json), length);
396 if (read_result != static_cast<int>(length)) {
397 return nullptr;
400 scoped_ptr<base::Value> message = base::JSONReader::Read(message_json);
401 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
402 return nullptr;
405 return make_scoped_ptr(
406 static_cast<base::DictionaryValue*>(message.release()));
409 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
410 const base::Value& message) {
411 std::string message_json;
412 base::JSONWriter::Write(message, &message_json);
414 uint32 length = message_json.length();
415 input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
416 sizeof(length));
417 input_write_file_.WriteAtCurrentPos(message_json.data(), length);
420 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value& message) {
421 base::DictionaryValue good_message;
422 good_message.SetString("type", "hello");
424 // This test currently relies on synchronous processing of hello messages and
425 // message parameters verification.
426 WriteMessageToInputPipe(good_message);
427 WriteMessageToInputPipe(message);
428 WriteMessageToInputPipe(good_message);
430 // Read from output pipe, and verify responses.
431 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
432 VerifyHelloResponse(response.Pass());
434 response = ReadMessageFromOutputPipe();
435 EXPECT_FALSE(response);
438 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
439 // Test all valid request-types.
440 TEST_F(Me2MeNativeMessagingHostTest, All) {
441 int next_id = 0;
442 base::DictionaryValue message;
443 message.SetInteger("id", next_id++);
444 message.SetString("type", "hello");
445 WriteMessageToInputPipe(message);
447 message.SetInteger("id", next_id++);
448 message.SetString("type", "getHostName");
449 WriteMessageToInputPipe(message);
451 message.SetInteger("id", next_id++);
452 message.SetString("type", "getPinHash");
453 message.SetString("hostId", "my_host");
454 message.SetString("pin", "1234");
455 WriteMessageToInputPipe(message);
457 message.Clear();
458 message.SetInteger("id", next_id++);
459 message.SetString("type", "generateKeyPair");
460 WriteMessageToInputPipe(message);
462 message.SetInteger("id", next_id++);
463 message.SetString("type", "getDaemonConfig");
464 WriteMessageToInputPipe(message);
466 message.SetInteger("id", next_id++);
467 message.SetString("type", "getUsageStatsConsent");
468 WriteMessageToInputPipe(message);
470 message.SetInteger("id", next_id++);
471 message.SetString("type", "stopDaemon");
472 WriteMessageToInputPipe(message);
474 message.SetInteger("id", next_id++);
475 message.SetString("type", "getDaemonState");
476 WriteMessageToInputPipe(message);
478 // Following messages require a "config" dictionary.
479 base::DictionaryValue config;
480 config.SetBoolean("update", true);
481 message.Set("config", config.DeepCopy());
482 message.SetInteger("id", next_id++);
483 message.SetString("type", "updateDaemonConfig");
484 WriteMessageToInputPipe(message);
486 config.Clear();
487 config.SetBoolean("start", true);
488 message.Set("config", config.DeepCopy());
489 message.SetBoolean("consent", true);
490 message.SetInteger("id", next_id++);
491 message.SetString("type", "startDaemon");
492 WriteMessageToInputPipe(message);
494 message.SetInteger("id", next_id++);
495 message.SetString("type", "getCredentialsFromAuthCode");
496 message.SetString("authorizationCode", "fake_auth_code");
497 WriteMessageToInputPipe(message);
499 void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = {
500 &VerifyHelloResponse,
501 &VerifyGetHostNameResponse,
502 &VerifyGetPinHashResponse,
503 &VerifyGenerateKeyPairResponse,
504 &VerifyGetDaemonConfigResponse,
505 &VerifyGetUsageStatsConsentResponse,
506 &VerifyStopDaemonResponse,
507 &VerifyGetDaemonStateResponse,
508 &VerifyUpdateDaemonConfigResponse,
509 &VerifyStartDaemonResponse,
510 &VerifyGetCredentialsFromAuthCodeResponse,
512 ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id));
514 // Read all responses from output pipe, and verify them.
515 for (int i = 0; i < next_id; ++i) {
516 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
518 // Make sure that id is available and is in the range.
519 int id;
520 ASSERT_TRUE(response->GetInteger("id", &id));
521 ASSERT_TRUE(0 <= id && id < next_id);
523 // Call the verification routine corresponding to the message id.
524 ASSERT_TRUE(verify_routines[id]);
525 verify_routines[id](response.Pass());
527 // Clear the pointer so that the routine cannot be called the second time.
528 verify_routines[id] = nullptr;
532 // Verify that response ID matches request ID.
533 TEST_F(Me2MeNativeMessagingHostTest, Id) {
534 base::DictionaryValue message;
535 message.SetString("type", "hello");
536 WriteMessageToInputPipe(message);
537 message.SetString("id", "42");
538 WriteMessageToInputPipe(message);
540 scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
541 EXPECT_TRUE(response);
542 std::string value;
543 EXPECT_FALSE(response->GetString("id", &value));
545 response = ReadMessageFromOutputPipe();
546 EXPECT_TRUE(response);
547 EXPECT_TRUE(response->GetString("id", &value));
548 EXPECT_EQ("42", value);
551 // Verify non-Dictionary requests are rejected.
552 TEST_F(Me2MeNativeMessagingHostTest, WrongFormat) {
553 base::ListValue message;
554 TestBadRequest(message);
557 // Verify requests with no type are rejected.
558 TEST_F(Me2MeNativeMessagingHostTest, MissingType) {
559 base::DictionaryValue message;
560 TestBadRequest(message);
563 // Verify rejection if type is unrecognized.
564 TEST_F(Me2MeNativeMessagingHostTest, InvalidType) {
565 base::DictionaryValue message;
566 message.SetString("type", "xxx");
567 TestBadRequest(message);
570 // Verify rejection if getPinHash request has no hostId.
571 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoHostId) {
572 base::DictionaryValue message;
573 message.SetString("type", "getPinHash");
574 message.SetString("pin", "1234");
575 TestBadRequest(message);
578 // Verify rejection if getPinHash request has no pin.
579 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoPin) {
580 base::DictionaryValue message;
581 message.SetString("type", "getPinHash");
582 message.SetString("hostId", "my_host");
583 TestBadRequest(message);
586 // Verify rejection if updateDaemonConfig request has invalid config.
587 TEST_F(Me2MeNativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
588 base::DictionaryValue message;
589 message.SetString("type", "updateDaemonConfig");
590 message.SetString("config", "xxx");
591 TestBadRequest(message);
594 // Verify rejection if startDaemon request has invalid config.
595 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonInvalidConfig) {
596 base::DictionaryValue message;
597 message.SetString("type", "startDaemon");
598 message.SetString("config", "xxx");
599 message.SetBoolean("consent", true);
600 TestBadRequest(message);
603 // Verify rejection if startDaemon request has no "consent" parameter.
604 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonNoConsent) {
605 base::DictionaryValue message;
606 message.SetString("type", "startDaemon");
607 message.Set("config", base::DictionaryValue().DeepCopy());
608 TestBadRequest(message);
611 // Verify rejection if getCredentialsFromAuthCode has no auth code.
612 TEST_F(Me2MeNativeMessagingHostTest, GetCredentialsFromAuthCodeNoAuthCode) {
613 base::DictionaryValue message;
614 message.SetString("type", "getCredentialsFromAuthCode");
615 TestBadRequest(message);
618 } // namespace remoting