Index: remoting/host/setup/native_messaging_host_unittest.cc |
diff --git a/remoting/host/setup/native_messaging_host_unittest.cc b/remoting/host/setup/native_messaging_host_unittest.cc |
deleted file mode 100644 |
index 164b77d5c9dfb6dcd2dbf79edb657e9fc4c03f19..0000000000000000000000000000000000000000 |
--- a/remoting/host/setup/native_messaging_host_unittest.cc |
+++ /dev/null |
@@ -1,555 +0,0 @@ |
-// Copyright 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "remoting/host/setup/native_messaging_host.h" |
- |
-#include "base/basictypes.h" |
-#include "base/compiler_specific.h" |
-#include "base/json/json_reader.h" |
-#include "base/json/json_writer.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/run_loop.h" |
-#include "base/stl_util.h" |
-#include "base/strings/stringize_macros.h" |
-#include "base/values.h" |
-#include "google_apis/gaia/gaia_oauth_client.h" |
-#include "net/base/file_stream.h" |
-#include "net/base/net_util.h" |
-#include "remoting/base/auto_thread_task_runner.h" |
-#include "remoting/host/pin_hash.h" |
-#include "remoting/host/setup/native_messaging_channel.h" |
-#include "remoting/host/setup/test_util.h" |
-#include "remoting/protocol/pairing_registry.h" |
-#include "remoting/protocol/protocol_mock_objects.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-using remoting::protocol::MockPairingRegistryDelegate; |
-using remoting::protocol::PairingRegistry; |
-using remoting::protocol::SynchronousPairingRegistry; |
- |
-namespace { |
- |
-void VerifyHelloResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("helloResponse", value); |
- EXPECT_TRUE(response->GetString("version", &value)); |
- EXPECT_EQ(STRINGIZE(VERSION), value); |
-} |
- |
-void VerifyGetHostNameResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("getHostNameResponse", value); |
- EXPECT_TRUE(response->GetString("hostname", &value)); |
- EXPECT_EQ(net::GetHostName(), value); |
-} |
- |
-void VerifyGetPinHashResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("getPinHashResponse", value); |
- EXPECT_TRUE(response->GetString("hash", &value)); |
- EXPECT_EQ(remoting::MakeHostPinHash("my_host", "1234"), value); |
-} |
- |
-void VerifyGenerateKeyPairResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("generateKeyPairResponse", value); |
- EXPECT_TRUE(response->GetString("privateKey", &value)); |
- EXPECT_TRUE(response->GetString("publicKey", &value)); |
-} |
- |
-void VerifyGetDaemonConfigResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("getDaemonConfigResponse", value); |
- const base::DictionaryValue* config = NULL; |
- EXPECT_TRUE(response->GetDictionary("config", &config)); |
- EXPECT_TRUE(base::DictionaryValue().Equals(config)); |
-} |
- |
-void VerifyGetUsageStatsConsentResponse( |
- scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("getUsageStatsConsentResponse", value); |
- bool supported, allowed, set_by_policy; |
- EXPECT_TRUE(response->GetBoolean("supported", &supported)); |
- EXPECT_TRUE(response->GetBoolean("allowed", &allowed)); |
- EXPECT_TRUE(response->GetBoolean("setByPolicy", &set_by_policy)); |
- EXPECT_TRUE(supported); |
- EXPECT_TRUE(allowed); |
- EXPECT_TRUE(set_by_policy); |
-} |
- |
-void VerifyStopDaemonResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("stopDaemonResponse", value); |
- EXPECT_TRUE(response->GetString("result", &value)); |
- EXPECT_EQ("OK", value); |
-} |
- |
-void VerifyGetDaemonStateResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("getDaemonStateResponse", value); |
- EXPECT_TRUE(response->GetString("state", &value)); |
- EXPECT_EQ("STARTED", value); |
-} |
- |
-void VerifyUpdateDaemonConfigResponse( |
- scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("updateDaemonConfigResponse", value); |
- EXPECT_TRUE(response->GetString("result", &value)); |
- EXPECT_EQ("OK", value); |
-} |
- |
-void VerifyStartDaemonResponse(scoped_ptr<base::DictionaryValue> response) { |
- ASSERT_TRUE(response); |
- std::string value; |
- EXPECT_TRUE(response->GetString("type", &value)); |
- EXPECT_EQ("startDaemonResponse", value); |
- EXPECT_TRUE(response->GetString("result", &value)); |
- EXPECT_EQ("OK", value); |
-} |
- |
-} // namespace |
- |
-namespace remoting { |
- |
-class MockDaemonControllerDelegate : public DaemonController::Delegate { |
- public: |
- MockDaemonControllerDelegate(); |
- virtual ~MockDaemonControllerDelegate(); |
- |
- // DaemonController::Delegate interface. |
- virtual DaemonController::State GetState() OVERRIDE; |
- virtual scoped_ptr<base::DictionaryValue> GetConfig() OVERRIDE; |
- virtual void SetConfigAndStart( |
- scoped_ptr<base::DictionaryValue> config, |
- bool consent, |
- const DaemonController::CompletionCallback& done) OVERRIDE; |
- virtual void UpdateConfig( |
- scoped_ptr<base::DictionaryValue> config, |
- const DaemonController::CompletionCallback& done) OVERRIDE; |
- virtual void Stop(const DaemonController::CompletionCallback& done) OVERRIDE; |
- virtual void SetWindow(void* window_handle) OVERRIDE; |
- virtual std::string GetVersion() OVERRIDE; |
- virtual DaemonController::UsageStatsConsent GetUsageStatsConsent() OVERRIDE; |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(MockDaemonControllerDelegate); |
-}; |
- |
-MockDaemonControllerDelegate::MockDaemonControllerDelegate() {} |
- |
-MockDaemonControllerDelegate::~MockDaemonControllerDelegate() {} |
- |
-DaemonController::State MockDaemonControllerDelegate::GetState() { |
- return DaemonController::STATE_STARTED; |
-} |
- |
-scoped_ptr<base::DictionaryValue> MockDaemonControllerDelegate::GetConfig() { |
- return scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()); |
-} |
- |
-void MockDaemonControllerDelegate::SetConfigAndStart( |
- scoped_ptr<base::DictionaryValue> config, |
- bool consent, |
- const DaemonController::CompletionCallback& done) { |
- |
- // Verify parameters passed in. |
- if (consent && config && config->HasKey("start")) { |
- done.Run(DaemonController::RESULT_OK); |
- } else { |
- done.Run(DaemonController::RESULT_FAILED); |
- } |
-} |
- |
-void MockDaemonControllerDelegate::UpdateConfig( |
- scoped_ptr<base::DictionaryValue> config, |
- const DaemonController::CompletionCallback& done) { |
- if (config && config->HasKey("update")) { |
- done.Run(DaemonController::RESULT_OK); |
- } else { |
- done.Run(DaemonController::RESULT_FAILED); |
- } |
-} |
- |
-void MockDaemonControllerDelegate::Stop( |
- const DaemonController::CompletionCallback& done) { |
- done.Run(DaemonController::RESULT_OK); |
-} |
- |
-void MockDaemonControllerDelegate::SetWindow(void* window_handle) {} |
- |
-std::string MockDaemonControllerDelegate::GetVersion() { |
- // Unused - NativeMessagingHost returns the compiled-in version string |
- // instead of calling this method. |
- NOTREACHED(); |
- return std::string(); |
-} |
- |
-DaemonController::UsageStatsConsent |
-MockDaemonControllerDelegate::GetUsageStatsConsent() { |
- DaemonController::UsageStatsConsent consent; |
- consent.supported = true; |
- consent.allowed = true; |
- consent.set_by_policy = true; |
- return consent; |
-} |
- |
-class NativeMessagingHostTest : public testing::Test { |
- public: |
- NativeMessagingHostTest(); |
- virtual ~NativeMessagingHostTest(); |
- |
- virtual void SetUp() OVERRIDE; |
- virtual void TearDown() OVERRIDE; |
- |
- void Run(); |
- |
- // Deletes |host_|. |
- void DeleteHost(); |
- |
- scoped_ptr<base::DictionaryValue> ReadMessageFromOutputPipe(); |
- |
- void WriteMessageToInputPipe(const base::Value& message); |
- |
- // The Host process should shut down when it receives a malformed request. |
- // This is tested by sending a known-good request, followed by |message|, |
- // followed by the known-good request again. The response file should only |
- // contain a single response from the first good request. |
- void TestBadRequest(const base::Value& message); |
- |
- protected: |
- // Reference to the MockDaemonControllerDelegate, which is owned by |
- // |channel_|. |
- MockDaemonControllerDelegate* daemon_controller_delegate_; |
- |
- private: |
- // Each test creates two unidirectional pipes: "input" and "output". |
- // NativeMessagingHost reads from input_read_handle and writes to |
- // output_write_handle. The unittest supplies data to input_write_handle, and |
- // verifies output from output_read_handle. |
- // |
- // unittest -> [input] -> NativeMessagingHost -> [output] -> unittest |
- base::PlatformFile input_write_handle_; |
- base::PlatformFile output_read_handle_; |
- |
- base::MessageLoop message_loop_; |
- base::RunLoop run_loop_; |
- scoped_refptr<AutoThreadTaskRunner> task_runner_; |
- scoped_ptr<remoting::NativeMessagingChannel> channel_; |
- |
- DISALLOW_COPY_AND_ASSIGN(NativeMessagingHostTest); |
-}; |
- |
-NativeMessagingHostTest::NativeMessagingHostTest() |
- : message_loop_(base::MessageLoop::TYPE_IO) {} |
- |
-NativeMessagingHostTest::~NativeMessagingHostTest() {} |
- |
-void NativeMessagingHostTest::SetUp() { |
- base::PlatformFile input_read_handle; |
- base::PlatformFile output_write_handle; |
- |
- ASSERT_TRUE(MakePipe(&input_read_handle, &input_write_handle_)); |
- ASSERT_TRUE(MakePipe(&output_read_handle_, &output_write_handle)); |
- |
- // Arrange to run |message_loop_| until no components depend on it. |
- task_runner_ = new AutoThreadTaskRunner( |
- message_loop_.message_loop_proxy(), run_loop_.QuitClosure()); |
- |
- daemon_controller_delegate_ = new MockDaemonControllerDelegate(); |
- scoped_refptr<DaemonController> daemon_controller( |
- new DaemonController( |
- scoped_ptr<DaemonController::Delegate>(daemon_controller_delegate_))); |
- |
- scoped_refptr<PairingRegistry> pairing_registry = |
- new SynchronousPairingRegistry(scoped_ptr<PairingRegistry::Delegate>( |
- new MockPairingRegistryDelegate())); |
- scoped_ptr<NativeMessagingChannel::Delegate> host( |
- new NativeMessagingHost(daemon_controller, |
- pairing_registry, |
- scoped_ptr<remoting::OAuthClient>())); |
- channel_.reset( |
- new NativeMessagingChannel(host.Pass(), |
- input_read_handle, |
- output_write_handle)); |
-} |
- |
-void NativeMessagingHostTest::TearDown() { |
- // DaemonController destroys its internals asynchronously. Let these and any |
- // other pending tasks run to make sure we don't leak the memory owned by |
- // them. |
- message_loop_.RunUntilIdle(); |
- |
- // The NativeMessagingHost dtor closes the handles that are passed to it. |
- // |input_write_handle_| gets closed just before starting the host. So the |
- // only handle left to close is |output_read_handle_|. |
- base::ClosePlatformFile(output_read_handle_); |
-} |
- |
-void NativeMessagingHostTest::Run() { |
- // Close the write-end of input, so that the host sees EOF after reading |
- // messages and won't block waiting for more input. |
- base::ClosePlatformFile(input_write_handle_); |
- channel_->Start(base::Bind(&NativeMessagingHostTest::DeleteHost, |
- base::Unretained(this))); |
- run_loop_.Run(); |
-} |
- |
-void NativeMessagingHostTest::DeleteHost() { |
- // Destroy |channel_| so that it closes its end of the output pipe, so that |
- // TestBadRequest() will see EOF and won't block waiting for more data. |
- channel_.reset(); |
- task_runner_ = NULL; |
-} |
- |
-scoped_ptr<base::DictionaryValue> |
-NativeMessagingHostTest::ReadMessageFromOutputPipe() { |
- uint32 length; |
- int read_result = base::ReadPlatformFileAtCurrentPos( |
- output_read_handle_, reinterpret_cast<char*>(&length), sizeof(length)); |
- if (read_result != sizeof(length)) { |
- return scoped_ptr<base::DictionaryValue>(); |
- } |
- |
- std::string message_json(length, '\0'); |
- read_result = base::ReadPlatformFileAtCurrentPos( |
- output_read_handle_, string_as_array(&message_json), length); |
- if (read_result != static_cast<int>(length)) { |
- return scoped_ptr<base::DictionaryValue>(); |
- } |
- |
- scoped_ptr<base::Value> message(base::JSONReader::Read(message_json)); |
- if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) { |
- return scoped_ptr<base::DictionaryValue>(); |
- } |
- |
- return scoped_ptr<base::DictionaryValue>( |
- static_cast<base::DictionaryValue*>(message.release())); |
-} |
- |
-void NativeMessagingHostTest::WriteMessageToInputPipe( |
- const base::Value& message) { |
- std::string message_json; |
- base::JSONWriter::Write(&message, &message_json); |
- |
- uint32 length = message_json.length(); |
- base::WritePlatformFileAtCurrentPos(input_write_handle_, |
- reinterpret_cast<char*>(&length), |
- sizeof(length)); |
- base::WritePlatformFileAtCurrentPos(input_write_handle_, message_json.data(), |
- length); |
-} |
- |
-void NativeMessagingHostTest::TestBadRequest(const base::Value& message) { |
- base::DictionaryValue good_message; |
- good_message.SetString("type", "hello"); |
- |
- // This test currently relies on synchronous processing of hello messages and |
- // message parameters verification. |
- WriteMessageToInputPipe(good_message); |
- WriteMessageToInputPipe(message); |
- WriteMessageToInputPipe(good_message); |
- |
- Run(); |
- |
- // Read from output pipe, and verify responses. |
- scoped_ptr<base::DictionaryValue> response = |
- ReadMessageFromOutputPipe(); |
- VerifyHelloResponse(response.Pass()); |
- |
- response = ReadMessageFromOutputPipe(); |
- EXPECT_FALSE(response); |
-} |
- |
-// Test all valid request-types. |
-TEST_F(NativeMessagingHostTest, All) { |
- int next_id = 0; |
- base::DictionaryValue message; |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "hello"); |
- WriteMessageToInputPipe(message); |
- |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "getHostName"); |
- WriteMessageToInputPipe(message); |
- |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "getPinHash"); |
- message.SetString("hostId", "my_host"); |
- message.SetString("pin", "1234"); |
- WriteMessageToInputPipe(message); |
- |
- message.Clear(); |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "generateKeyPair"); |
- WriteMessageToInputPipe(message); |
- |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "getDaemonConfig"); |
- WriteMessageToInputPipe(message); |
- |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "getUsageStatsConsent"); |
- WriteMessageToInputPipe(message); |
- |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "stopDaemon"); |
- WriteMessageToInputPipe(message); |
- |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "getDaemonState"); |
- WriteMessageToInputPipe(message); |
- |
- // Following messages require a "config" dictionary. |
- base::DictionaryValue config; |
- config.SetBoolean("update", true); |
- message.Set("config", config.DeepCopy()); |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "updateDaemonConfig"); |
- WriteMessageToInputPipe(message); |
- |
- config.Clear(); |
- config.SetBoolean("start", true); |
- message.Set("config", config.DeepCopy()); |
- message.SetBoolean("consent", true); |
- message.SetInteger("id", next_id++); |
- message.SetString("type", "startDaemon"); |
- WriteMessageToInputPipe(message); |
- |
- Run(); |
- |
- void (*verify_routines[])(scoped_ptr<base::DictionaryValue>) = { |
- &VerifyHelloResponse, |
- &VerifyGetHostNameResponse, |
- &VerifyGetPinHashResponse, |
- &VerifyGenerateKeyPairResponse, |
- &VerifyGetDaemonConfigResponse, |
- &VerifyGetUsageStatsConsentResponse, |
- &VerifyStopDaemonResponse, |
- &VerifyGetDaemonStateResponse, |
- &VerifyUpdateDaemonConfigResponse, |
- &VerifyStartDaemonResponse, |
- }; |
- ASSERT_EQ(arraysize(verify_routines), static_cast<size_t>(next_id)); |
- |
- // Read all responses from output pipe, and verify them. |
- for (int i = 0; i < next_id; ++i) { |
- scoped_ptr<base::DictionaryValue> response = ReadMessageFromOutputPipe(); |
- |
- // Make sure that id is available and is in the range. |
- int id; |
- ASSERT_TRUE(response->GetInteger("id", &id)); |
- ASSERT_TRUE(0 <= id && id < next_id); |
- |
- // Call the verification routine corresponding to the message id. |
- ASSERT_TRUE(verify_routines[id]); |
- verify_routines[id](response.Pass()); |
- |
- // Clear the pointer so that the routine cannot be called the second time. |
- verify_routines[id] = NULL; |
- } |
-} |
- |
-// Verify that response ID matches request ID. |
-TEST_F(NativeMessagingHostTest, Id) { |
- base::DictionaryValue message; |
- message.SetString("type", "hello"); |
- WriteMessageToInputPipe(message); |
- message.SetString("id", "42"); |
- WriteMessageToInputPipe(message); |
- |
- Run(); |
- |
- scoped_ptr<base::DictionaryValue> response = |
- ReadMessageFromOutputPipe(); |
- EXPECT_TRUE(response); |
- std::string value; |
- EXPECT_FALSE(response->GetString("id", &value)); |
- |
- response = ReadMessageFromOutputPipe(); |
- EXPECT_TRUE(response); |
- EXPECT_TRUE(response->GetString("id", &value)); |
- EXPECT_EQ("42", value); |
-} |
- |
-// Verify non-Dictionary requests are rejected. |
-TEST_F(NativeMessagingHostTest, WrongFormat) { |
- base::ListValue message; |
- TestBadRequest(message); |
-} |
- |
-// Verify requests with no type are rejected. |
-TEST_F(NativeMessagingHostTest, MissingType) { |
- base::DictionaryValue message; |
- TestBadRequest(message); |
-} |
- |
-// Verify rejection if type is unrecognized. |
-TEST_F(NativeMessagingHostTest, InvalidType) { |
- base::DictionaryValue message; |
- message.SetString("type", "xxx"); |
- TestBadRequest(message); |
-} |
- |
-// Verify rejection if getPinHash request has no hostId. |
-TEST_F(NativeMessagingHostTest, GetPinHashNoHostId) { |
- base::DictionaryValue message; |
- message.SetString("type", "getPinHash"); |
- message.SetString("pin", "1234"); |
- TestBadRequest(message); |
-} |
- |
-// Verify rejection if getPinHash request has no pin. |
-TEST_F(NativeMessagingHostTest, GetPinHashNoPin) { |
- base::DictionaryValue message; |
- message.SetString("type", "getPinHash"); |
- message.SetString("hostId", "my_host"); |
- TestBadRequest(message); |
-} |
- |
-// Verify rejection if updateDaemonConfig request has invalid config. |
-TEST_F(NativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) { |
- base::DictionaryValue message; |
- message.SetString("type", "updateDaemonConfig"); |
- message.SetString("config", "xxx"); |
- TestBadRequest(message); |
-} |
- |
-// Verify rejection if startDaemon request has invalid config. |
-TEST_F(NativeMessagingHostTest, StartDaemonInvalidConfig) { |
- base::DictionaryValue message; |
- message.SetString("type", "startDaemon"); |
- message.SetString("config", "xxx"); |
- message.SetBoolean("consent", true); |
- TestBadRequest(message); |
-} |
- |
-// Verify rejection if startDaemon request has no "consent" parameter. |
-TEST_F(NativeMessagingHostTest, StartDaemonNoConsent) { |
- base::DictionaryValue message; |
- message.SetString("type", "startDaemon"); |
- message.Set("config", base::DictionaryValue().DeepCopy()); |
- TestBadRequest(message); |
-} |
- |
-} // namespace remoting |