Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Unified Diff: remoting/host/setup/native_messaging_host_unittest.cc

Issue 14979008: unittests for Chromoting native messaging host. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Some clang-format fixes Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
new file mode 100644
index 0000000000000000000000000000000000000000..7944e9d70818044acbc3db51bcf89edcb332d7bd
--- /dev/null
+++ b/remoting/host/setup/native_messaging_host_unittest.cc
@@ -0,0 +1,404 @@
+// 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 "base/compiler_specific.h"
+#include "base/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/message_loop.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/stringize_macros.h"
+#include "base/values.h"
+#include "net/base/file_stream.h"
+#include "net/base/net_util.h"
+#include "remoting/host/pin_hash.h"
+#include "remoting/host/setup/mock_daemon_controller.h"
+#include "remoting/host/setup/native_messaging_host.h"
Sergey Ulanov 2013/05/18 01:59:31 nit: this should be first include for this file.
Lambros 2013/05/22 21:42:18 Done.
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void VerifyHelloResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "helloResponse");
+ EXPECT_TRUE(response->GetString("version", &value));
+ EXPECT_EQ(value, STRINGIZE(VERSION));
+}
+
+void VerifyGetHostNameResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "getHostNameResponse");
+ EXPECT_TRUE(response->GetString("hostname", &value));
+ EXPECT_EQ(value, net::GetHostName());
+}
+
+void VerifyGetPinHashResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "getPinHashResponse");
+ EXPECT_TRUE(response->GetString("hash", &value));
+ EXPECT_EQ(value, remoting::MakeHostPinHash("my_host", "1234"));
+}
+
+void VerifyGenerateKeyPairResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "generateKeyPairResponse");
+ EXPECT_TRUE(response->GetString("private_key", &value));
+ EXPECT_TRUE(response->GetString("public_key", &value));
+}
+
+void VerifyGetDaemonConfigResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "getDaemonConfigResponse");
+ EXPECT_TRUE(response->GetString("config", &value));
+ EXPECT_EQ(value, "{}");
+}
+
+void VerifyGetUsageStatsConsentResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "getUsageStatsConsentResponse");
+ bool supported, allowed, set_by_policy;
+ EXPECT_TRUE(response->GetBoolean("supported", &supported));
+ EXPECT_TRUE(response->GetBoolean("allowed", &allowed));
+ EXPECT_TRUE(response->GetBoolean("set_by_policy", &set_by_policy));
+ EXPECT_TRUE(supported);
+ EXPECT_TRUE(allowed);
+ EXPECT_TRUE(set_by_policy);
+}
+
+void VerifyStopDaemonResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "stopDaemonResponse");
+ int result;
+ EXPECT_TRUE(response->GetInteger("result", &result));
+ EXPECT_EQ(result, 0);
+}
+
+void VerifyGetDaemonStateResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "getDaemonStateResponse");
+ int result;
+ EXPECT_TRUE(response->GetInteger("state", &result));
+ EXPECT_EQ(result, 4);
+}
+
+void VerifyUpdateDaemonConfigResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "updateDaemonConfigResponse");
+ int result;
+ EXPECT_TRUE(response->GetInteger("result", &result));
+ EXPECT_EQ(result, 0);
+}
+
+void VerifyStartDaemonResponse(const base::DictionaryValue* response) {
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_TRUE(response->GetString("type", &value));
+ EXPECT_EQ(value, "startDaemonResponse");
+ int result;
+ EXPECT_TRUE(response->GetInteger("result", &result));
+ EXPECT_EQ(result, 0);
+}
+
+scoped_ptr<base::DictionaryValue> ReadMessageFromFile(
Sergey Ulanov 2013/05/18 01:59:31 Can you use FileStreams to read from files?
Lambros 2013/05/22 21:42:18 Probably, but not sure if there's any advantage, o
+ base::PlatformFile handle) {
+ uint32 length;
+ int read_result = base::ReadPlatformFileAtCurrentPos(
+ 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(
+ 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()));
+}
+
+} // namespace
+
+namespace remoting {
+
+class NativeMessagingHostTest : public testing::Test {
+ public:
+ NativeMessagingHostTest();
+ virtual ~NativeMessagingHostTest();
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ void Run();
+
+ void WriteMessageToInputFile(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);
+
+ base::FilePath output_path() const { return output_path_; }
+
+ private:
+ base::FilePath input_path_;
+ base::PlatformFile input_handle_;
+ base::FilePath output_path_;
+ base::PlatformFile output_handle_;
+
+ base::MessageLoop message_loop_;
+ base::RunLoop run_loop_;
+ scoped_ptr<remoting::NativeMessagingHost> host_;
+};
+
+NativeMessagingHostTest::NativeMessagingHostTest()
+ : message_loop_(base::MessageLoop::TYPE_IO) {}
+
+NativeMessagingHostTest::~NativeMessagingHostTest() {}
+
+void NativeMessagingHostTest::SetUp() {
+ file_util::CreateTemporaryFile(&input_path_);
+ input_handle_ = base::CreatePlatformFile(
+ input_path_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
+ NULL);
+
+ file_util::CreateTemporaryFile(&output_path_);
+ output_handle_ = base::CreatePlatformFile(
+ output_path_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, NULL,
+ NULL);
+
+ host_.reset(new NativeMessagingHost(input_handle_, output_handle_,
+ message_loop_.message_loop_proxy(),
+ run_loop_.QuitClosure()));
+ host_->SetDaemonControllerForTest(
+ scoped_ptr<DaemonController>(new MockDaemonController()));
+}
+
+void NativeMessagingHostTest::TearDown() {
+ base::ClosePlatformFile(input_handle_);
+ base::ClosePlatformFile(output_handle_);
+ EXPECT_TRUE(file_util::Delete(input_path_, false));
+ EXPECT_TRUE(file_util::Delete(output_path_, false));
+}
+
+void NativeMessagingHostTest::Run() {
+ host_->Start();
+ run_loop_.Run();
+}
+
+void NativeMessagingHostTest::WriteMessageToInputFile(
+ const base::Value& message) {
+ std::string message_json;
+ base::JSONWriter::Write(&message, &message_json);
+
+ uint32 length = message_json.length();
+ file_util::AppendToFile(input_path_, reinterpret_cast<char*>(&length),
+ sizeof(length));
+ file_util::AppendToFile(input_path_, message_json.data(), length);
+}
+
+void NativeMessagingHostTest::TestBadRequest(const base::Value& message) {
+ base::DictionaryValue good_message;
+ good_message.SetString("type", "hello");
+
+ WriteMessageToInputFile(good_message);
+ WriteMessageToInputFile(message);
+ WriteMessageToInputFile(good_message);
+
+ Run();
+
+ // Read from output file, and verify responses.
+ base::PlatformFile handle = base::CreatePlatformFile(
+ output_path(), base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
+ NULL);
+
+ scoped_ptr<base::DictionaryValue> response = ReadMessageFromFile(handle);
+ VerifyHelloResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ EXPECT_FALSE(response);
+}
+
+TEST_F(NativeMessagingHostTest, All) {
+ base::DictionaryValue message;
+ message.SetString("type", "hello");
+ WriteMessageToInputFile(message);
+
+ message.SetString("type", "getHostName");
+ WriteMessageToInputFile(message);
+
+ message.SetString("type", "getPinHash");
+ message.SetString("hostId", "my_host");
+ message.SetString("pin", "1234");
+ WriteMessageToInputFile(message);
+
+ message.Clear();
+ message.SetString("type", "generateKeyPair");
+ WriteMessageToInputFile(message);
+
+ message.SetString("type", "getDaemonConfig");
+ WriteMessageToInputFile(message);
+
+ message.SetString("type", "getUsageStatsConsent");
+ WriteMessageToInputFile(message);
+
+ message.SetString("type", "stopDaemon");
+ WriteMessageToInputFile(message);
+
+ message.SetString("type", "getDaemonState");
+ WriteMessageToInputFile(message);
+
+ // Following messages require a "config" dictionary.
+ message.SetString("config", "{}");
+ message.SetString("type", "updateDaemonConfig");
+ WriteMessageToInputFile(message);
+
+ message.SetBoolean("consent", true);
+ message.SetString("type", "startDaemon");
+ WriteMessageToInputFile(message);
+
+ Run();
+
+ // Read from output file, and verify responses.
+ base::PlatformFile handle = base::CreatePlatformFile(
+ output_path(), base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
+ NULL);
+
+ scoped_ptr<base::DictionaryValue> response = ReadMessageFromFile(handle);
+ VerifyHelloResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyGetHostNameResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyGetPinHashResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyGenerateKeyPairResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyGetDaemonConfigResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyGetUsageStatsConsentResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyStopDaemonResponse(response.get());
Sergey Ulanov 2013/05/18 01:59:31 This doesn't really verify that daemon controller
Lambros 2013/05/22 21:42:18 I've improved the mock object to try to address th
+
+ response = ReadMessageFromFile(handle);
+ VerifyGetDaemonStateResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyUpdateDaemonConfigResponse(response.get());
+
+ response = ReadMessageFromFile(handle);
+ VerifyStartDaemonResponse(response.get());
+
+ base::ClosePlatformFile(handle);
+}
+
+TEST_F(NativeMessagingHostTest, Id) {
Sergey Ulanov 2013/05/18 01:59:31 Please add short description for each test, e.g.
Lambros 2013/05/22 21:42:18 Done.
+ base::DictionaryValue message;
+ message.SetString("type", "hello");
+ WriteMessageToInputFile(message);
+ message.SetString("id", "42");
+ WriteMessageToInputFile(message);
+
+ Run();
+
+ base::PlatformFile handle = base::CreatePlatformFile(
+ output_path(), base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
+ NULL);
+ scoped_ptr<base::DictionaryValue> response = ReadMessageFromFile(handle);
+ EXPECT_TRUE(response);
+ std::string value;
+ EXPECT_FALSE(response->GetString("id", &value));
+
+ response = ReadMessageFromFile(handle);
+ EXPECT_TRUE(response);
+ EXPECT_TRUE(response->GetString("id", &value));
+ EXPECT_EQ(value, "42");
+}
+
+TEST_F(NativeMessagingHostTest, WrongFormat) {
+ // Request should be a Dictionary.
+ base::ListValue message;
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, MissingType) {
+ base::DictionaryValue message;
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, InvalidType) {
+ base::DictionaryValue message;
+ message.SetString("type", "xxx");
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, GetPinHashNoHostId) {
+ base::DictionaryValue message;
+ message.SetString("type", "getPinHash");
+ message.SetString("pin", "1234");
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, GetPinHashNoPin) {
+ base::DictionaryValue message;
+ message.SetString("type", "getPinHash");
+ message.SetString("hostId", "my_host");
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
+ base::DictionaryValue message;
+ message.SetString("type", "updateDaemonConfig");
+ message.SetString("config", "xxx");
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, StartDaemonInvalidConfig) {
+ base::DictionaryValue message;
+ message.SetString("type", "startDaemon");
+ message.SetString("config", "xxx");
+ message.SetBoolean("consent", true);
+ TestBadRequest(message);
+}
+
+TEST_F(NativeMessagingHostTest, StartDaemonNoConsent) {
+ base::DictionaryValue message;
+ message.SetString("type", "startDaemon");
+ message.SetString("config", "{}");
+ TestBadRequest(message);
+}
+
+} // namespace remoting

Powered by Google App Engine
This is Rietveld 408576698