Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / remoting / host / setup / me2me_native_messaging_host_unittest.cc
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.
4
5 #include "remoting/host/setup/me2me_native_messaging_host.h"
6
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"
26
27 using remoting::protocol::MockPairingRegistryDelegate;
28 using remoting::protocol::PairingRegistry;
29 using remoting::protocol::SynchronousPairingRegistry;
30
31 namespace {
32
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);
40 }
41
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);
49 }
50
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);
58 }
59
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));
67 }
68
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));
77 }
78
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);
92 }
93
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);
101 }
102
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);
110 }
111
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);
120 }
121
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);
129 }
130
131 }  // namespace
132
133 namespace remoting {
134
135 class MockDaemonControllerDelegate : public DaemonController::Delegate {
136  public:
137   MockDaemonControllerDelegate();
138   virtual ~MockDaemonControllerDelegate();
139
140   // DaemonController::Delegate interface.
141   virtual DaemonController::State GetState() OVERRIDE;
142   virtual scoped_ptr<base::DictionaryValue> GetConfig() OVERRIDE;
143   virtual void InstallHost(
144       const DaemonController::CompletionCallback& done) OVERRIDE;
145   virtual void SetConfigAndStart(
146       scoped_ptr<base::DictionaryValue> config,
147       bool consent,
148       const DaemonController::CompletionCallback& done) OVERRIDE;
149   virtual void UpdateConfig(
150       scoped_ptr<base::DictionaryValue> config,
151       const DaemonController::CompletionCallback& done) OVERRIDE;
152   virtual void Stop(const DaemonController::CompletionCallback& done) OVERRIDE;
153   virtual void SetWindow(void* window_handle) OVERRIDE;
154   virtual std::string GetVersion() OVERRIDE;
155   virtual DaemonController::UsageStatsConsent GetUsageStatsConsent() OVERRIDE;
156
157  private:
158   DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate);
159 };
160
161 MockDaemonControllerDelegate::MockDaemonControllerDelegate() {}
162
163 MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {}
164
165 DaemonController::State MockDaemonControllerDelegate::GetState() {
166   return DaemonController::STATE_STARTED;
167 }
168
169 scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() {
170   return scoped_ptr<base::DictionaryValue>(new base::DictionaryValue());
171 }
172
173 void MockDaemonControllerDelegate::InstallHost(
174     const DaemonController::CompletionCallback& done) {
175   done.Run(DaemonController::RESULT_OK);
176 }
177
178 void MockDaemonControllerDelegate::SetConfigAndStart(
179     scoped_ptr<base::DictionaryValue> config,
180     bool consent,
181     const DaemonController::CompletionCallback& done) {
182
183   // Verify parameters passed in.
184   if (consent && config && config->HasKey("start")) {
185     done.Run(DaemonController::RESULT_OK);
186   } else {
187     done.Run(DaemonController::RESULT_FAILED);
188   }
189 }
190
191 void MockDaemonControllerDelegate::UpdateConfig(
192     scoped_ptr<base::DictionaryValue> config,
193     const DaemonController::CompletionCallback& done) {
194   if (config && config->HasKey("update")) {
195     done.Run(DaemonController::RESULT_OK);
196   } else {
197     done.Run(DaemonController::RESULT_FAILED);
198   }
199 }
200
201 void MockDaemonControllerDelegate::Stop(
202     const DaemonController::CompletionCallback& done) {
203   done.Run(DaemonController::RESULT_OK);
204 }
205
206 void MockDaemonControllerDelegate::SetWindow(void* window_handle) {}
207
208 std::string MockDaemonControllerDelegate::GetVersion() {
209   // Unused - Me2MeNativeMessagingHost returns the compiled-in version string
210   // instead of calling this method.
211   NOTREACHED();
212   return std::string();
213 }
214
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;
222 }
223
224 class Me2MeNativeMessagingHostTest : public testing::Test {
225  public:
226   Me2MeNativeMessagingHostTest();
227   virtual ~Me2MeNativeMessagingHostTest();
228
229   virtual void SetUp() OVERRIDE;
230   virtual void TearDown() OVERRIDE;
231
232   scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe();
233
234   void WriteMessageToInputPipe(const base::Value& message);
235
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);
241
242  protected:
243   // Reference to the MockDaemonControllerDelegate, which is owned by
244   // |channel_|.
245   MockDaemonControllerDelegate* daemon_controller_delegate_;
246
247  private:
248   void StartHost();
249   void StopHost();
250   void ExitTest();
251
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.
256   //
257   // unittest -> [input] -> Me2MeNativeMessagingHost -> [output] -> unittest
258   base::File input_write_file_;
259   base::File output_read_file_;
260
261   // Message loop of the test thread.
262   scoped_ptr<base::MessageLoop> test_message_loop_;
263   scoped_ptr<base::RunLoop> test_run_loop_;
264
265   scoped_ptr<base::Thread> host_thread_;
266   scoped_ptr<base::RunLoop> host_run_loop_;
267
268   // Task runner of the host thread.
269   scoped_refptr<AutoThreadTaskRunner> host_task_runner_;
270   scoped_ptr<remoting::Me2MeNativeMessagingHost> host_;
271
272   DISALLOW_COPY_AND_ASSIGN(Me2MeNativeMessagingHostTest);
273 };
274
275 Me2MeNativeMessagingHostTest::Me2MeNativeMessagingHostTest() {}
276
277 Me2MeNativeMessagingHostTest::~Me2MeNativeMessagingHostTest() {}
278
279 void Me2MeNativeMessagingHostTest::SetUp() {
280   base::File input_read_file;
281   base::File output_write_file;
282
283   ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
284   ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
285
286   test_message_loop_.reset(new base::MessageLoop());
287   test_run_loop_.reset(new base::RunLoop());
288
289   // Run the host on a dedicated thread.
290   host_thread_.reset(new base::Thread("host_thread"));
291   host_thread_->Start();
292
293   // Arrange to run |test_message_loop_| until no components depend on it.
294   host_task_runner_ = new AutoThreadTaskRunner(
295       host_thread_->message_loop_proxy(),
296       base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
297                  base::Unretained(this)));
298
299   host_task_runner_->PostTask(
300       FROM_HERE,
301       base::Bind(&Me2MeNativeMessagingHostTest::StartHost,
302                  base::Unretained(this)));
303
304   // Wait until the host finishes starting.
305   test_run_loop_->Run();
306 }
307
308 void Me2MeNativeMessagingHostTest::StartHost() {
309   DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
310
311   base::File input_read_file;
312   base::File output_write_file;
313
314   ASSERT_TRUE(MakePipe(&input_read_file, &input_write_file_));
315   ASSERT_TRUE(MakePipe(&output_read_file_, &output_write_file));
316
317   daemon_controller_delegate_ = new MockDaemonControllerDelegate();
318   scoped_refptr<DaemonController> daemon_controller(
319       new DaemonController(
320           scoped_ptr<DaemonController::Delegate>(daemon_controller_delegate_)));
321
322   scoped_refptr<PairingRegistry> pairing_registry =
323       new SynchronousPairingRegistry(scoped_ptr<PairingRegistry::Delegate>(
324           new MockPairingRegistryDelegate()));
325
326   scoped_ptr<NativeMessagingChannel> channel(
327       new NativeMessagingChannel(input_read_file.Pass(),
328                                  output_write_file.Pass()));
329
330   host_.reset(new Me2MeNativeMessagingHost(
331         false,
332         0,
333         channel.Pass(),
334         daemon_controller,
335         pairing_registry,
336         scoped_ptr<remoting::OAuthClient>()));
337   host_->Start(base::Bind(&Me2MeNativeMessagingHostTest::StopHost,
338                           base::Unretained(this)));
339
340   // Notify the test that the host has finished starting up.
341   test_message_loop_->message_loop_proxy()->PostTask(
342       FROM_HERE, test_run_loop_->QuitClosure());
343 }
344
345 void Me2MeNativeMessagingHostTest::StopHost() {
346   DCHECK(host_task_runner_->RunsTasksOnCurrentThread());
347
348   host_.reset();
349
350   // Wait till all shutdown tasks have completed.
351   base::RunLoop().RunUntilIdle();
352
353   // Trigger a test shutdown via ExitTest().
354   host_task_runner_ = NULL;
355 }
356
357 void Me2MeNativeMessagingHostTest::ExitTest() {
358   if (!test_message_loop_->message_loop_proxy()->RunsTasksOnCurrentThread()) {
359     test_message_loop_->message_loop_proxy()->PostTask(
360         FROM_HERE,
361         base::Bind(&Me2MeNativeMessagingHostTest::ExitTest,
362                    base::Unretained(this)));
363     return;
364   }
365   test_run_loop_->Quit();
366 }
367
368 void Me2MeNativeMessagingHostTest::TearDown() {
369   // Closing the write-end of the input will send an EOF to the native
370   // messaging reader. This will trigger a host shutdown.
371   input_write_file_.Close();
372
373   // Start a new RunLoop and Wait until the host finishes shutting down.
374   test_run_loop_.reset(new base::RunLoop());
375   test_run_loop_->Run();
376
377   // Verify there are no more message in the output pipe.
378   scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
379   EXPECT_FALSE(response);
380
381   // The It2MeMe2MeNativeMessagingHost dtor closes the handles that are passed
382   // to it. So the only handle left to close is |output_read_file_|.
383   output_read_file_.Close();
384 }
385
386 scoped_ptr<base::DictionaryValue>
387 Me2MeNativeMessagingHostTest::ReadMessageFromOutputPipe() {
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 scoped_ptr<base::DictionaryValue>();
393   }
394
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 scoped_ptr<base::DictionaryValue>();
400   }
401
402   scoped_ptr<base::Value> message(base::JSONReader::Read(message_json));
403   if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
404     return scoped_ptr<base::DictionaryValue>();
405   }
406
407   return scoped_ptr<base::DictionaryValue>(
408       static_cast<base::DictionaryValue*>(message.release()));
409 }
410
411 void Me2MeNativeMessagingHostTest::WriteMessageToInputPipe(
412     const base::Value& message) {
413   std::string message_json;
414   base::JSONWriter::Write(&message, &message_json);
415
416   uint32 length = message_json.length();
417   input_write_file_.WriteAtCurrentPos(reinterpret_cast<char*>(&length),
418                                       sizeof(length));
419   input_write_file_.WriteAtCurrentPos(message_json.data(), length);
420 }
421
422 void Me2MeNativeMessagingHostTest::TestBadRequest(const base::Value& message) {
423   base::DictionaryValue good_message;
424   good_message.SetString("type", "hello");
425
426   // This test currently relies on synchronous processing of hello messages and
427   // message parameters verification.
428   WriteMessageToInputPipe(good_message);
429   WriteMessageToInputPipe(message);
430   WriteMessageToInputPipe(good_message);
431
432   // Read from output pipe, and verify responses.
433   scoped_ptr<base::DictionaryValue> response =
434       ReadMessageFromOutputPipe();
435   VerifyHelloResponse(response.Pass());
436
437   response = ReadMessageFromOutputPipe();
438   EXPECT_FALSE(response);
439 }
440
441 // TODO (weitaosu): crbug.com/323306. Re-enable these tests.
442 // Test all valid request-types.
443 TEST_F(Me2MeNativeMessagingHostTest, All) {
444   int next_id = 0;
445   base::DictionaryValue message;
446   message.SetInteger("id", next_id++);
447   message.SetString("type", "hello");
448   WriteMessageToInputPipe(message);
449
450   message.SetInteger("id", next_id++);
451   message.SetString("type", "getHostName");
452   WriteMessageToInputPipe(message);
453
454   message.SetInteger("id", next_id++);
455   message.SetString("type", "getPinHash");
456   message.SetString("hostId", "my_host");
457   message.SetString("pin", "1234");
458   WriteMessageToInputPipe(message);
459
460   message.Clear();
461   message.SetInteger("id", next_id++);
462   message.SetString("type", "generateKeyPair");
463   WriteMessageToInputPipe(message);
464
465   message.SetInteger("id", next_id++);
466   message.SetString("type", "getDaemonConfig");
467   WriteMessageToInputPipe(message);
468
469   message.SetInteger("id", next_id++);
470   message.SetString("type", "getUsageStatsConsent");
471   WriteMessageToInputPipe(message);
472
473   message.SetInteger("id", next_id++);
474   message.SetString("type", "stopDaemon");
475   WriteMessageToInputPipe(message);
476
477   message.SetInteger("id", next_id++);
478   message.SetString("type", "getDaemonState");
479   WriteMessageToInputPipe(message);
480
481   // Following messages require a "config" dictionary.
482   base::DictionaryValue config;
483   config.SetBoolean("update", true);
484   message.Set("config", config.DeepCopy());
485   message.SetInteger("id", next_id++);
486   message.SetString("type", "updateDaemonConfig");
487   WriteMessageToInputPipe(message);
488
489   config.Clear();
490   config.SetBoolean("start", true);
491   message.Set("config", config.DeepCopy());
492   message.SetBoolean("consent", true);
493   message.SetInteger("id", next_id++);
494   message.SetString("type", "startDaemon");
495   WriteMessageToInputPipe(message);
496
497   void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = {
498     &VerifyHelloResponse,
499     &VerifyGetHostNameResponse,
500     &VerifyGetPinHashResponse,
501     &VerifyGenerateKeyPairResponse,
502     &VerifyGetDaemonConfigResponse,
503     &VerifyGetUsageStatsConsentResponse,
504     &VerifyStopDaemonResponse,
505     &VerifyGetDaemonStateResponse,
506     &VerifyUpdateDaemonConfigResponse,
507     &VerifyStartDaemonResponse,
508   };
509   ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id));
510
511   // Read all responses from output pipe, and verify them.
512   for (int i = 0; i < next_id; ++i) {
513     scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe();
514
515     // Make sure that id is available and is in the range.
516     int id;
517     ASSERT_TRUE(response->GetInteger("id", &id));
518     ASSERT_TRUE(0 <= id && id < next_id);
519
520     // Call the verification routine corresponding to the message id.
521     ASSERT_TRUE(verify_routines[id]);
522     verify_routines[id](response.Pass());
523
524     // Clear the pointer so that the routine cannot be called the second time.
525     verify_routines[id] = NULL;
526   }
527 }
528
529 // Verify that response ID matches request ID.
530 TEST_F(Me2MeNativeMessagingHostTest, Id) {
531   base::DictionaryValue message;
532   message.SetString("type", "hello");
533   WriteMessageToInputPipe(message);
534   message.SetString("id", "42");
535   WriteMessageToInputPipe(message);
536
537   scoped_ptr<base::DictionaryValue> response =
538       ReadMessageFromOutputPipe();
539   EXPECT_TRUE(response);
540   std::string value;
541   EXPECT_FALSE(response->GetString("id", &value));
542
543   response = ReadMessageFromOutputPipe();
544   EXPECT_TRUE(response);
545   EXPECT_TRUE(response->GetString("id", &value));
546   EXPECT_EQ("42", value);
547 }
548
549 // Verify non-Dictionary requests are rejected.
550 TEST_F(Me2MeNativeMessagingHostTest, WrongFormat) {
551   base::ListValue message;
552   TestBadRequest(message);
553 }
554
555 // Verify requests with no type are rejected.
556 TEST_F(Me2MeNativeMessagingHostTest, MissingType) {
557   base::DictionaryValue message;
558   TestBadRequest(message);
559 }
560
561 // Verify rejection if type is unrecognized.
562 TEST_F(Me2MeNativeMessagingHostTest, InvalidType) {
563   base::DictionaryValue message;
564   message.SetString("type", "xxx");
565   TestBadRequest(message);
566 }
567
568 // Verify rejection if getPinHash request has no hostId.
569 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoHostId) {
570   base::DictionaryValue message;
571   message.SetString("type", "getPinHash");
572   message.SetString("pin", "1234");
573   TestBadRequest(message);
574 }
575
576 // Verify rejection if getPinHash request has no pin.
577 TEST_F(Me2MeNativeMessagingHostTest, GetPinHashNoPin) {
578   base::DictionaryValue message;
579   message.SetString("type", "getPinHash");
580   message.SetString("hostId", "my_host");
581   TestBadRequest(message);
582 }
583
584 // Verify rejection if updateDaemonConfig request has invalid config.
585 TEST_F(Me2MeNativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
586   base::DictionaryValue message;
587   message.SetString("type", "updateDaemonConfig");
588   message.SetString("config", "xxx");
589   TestBadRequest(message);
590 }
591
592 // Verify rejection if startDaemon request has invalid config.
593 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonInvalidConfig) {
594   base::DictionaryValue message;
595   message.SetString("type", "startDaemon");
596   message.SetString("config", "xxx");
597   message.SetBoolean("consent", true);
598   TestBadRequest(message);
599 }
600
601 // Verify rejection if startDaemon request has no "consent" parameter.
602 TEST_F(Me2MeNativeMessagingHostTest, StartDaemonNoConsent) {
603   base::DictionaryValue message;
604   message.SetString("type", "startDaemon");
605   message.Set("config", base::DictionaryValue().DeepCopy());
606   TestBadRequest(message);
607 }
608
609 }  // namespace remoting