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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "base/compiler_specific.h"
6 #include "base/file_util.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/stl_util.h"
12 #include "base/strings/stringize_macros.h"
13 #include "base/values.h"
14 #include "net/base/file_stream.h"
15 #include "net/base/net_util.h"
16 #include "remoting/host/pin_hash.h"
17 #include "remoting/host/setup/mock_daemon_controller.h"
18 #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.
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace {
22
23 void VerifyHelloResponse(const base::DictionaryValue* response) {
24 EXPECT_TRUE(response);
25 std::string value;
26 EXPECT_TRUE(response->GetString("type", &value));
27 EXPECT_EQ(value, "helloResponse");
28 EXPECT_TRUE(response->GetString("version", &value));
29 EXPECT_EQ(value, STRINGIZE(VERSION));
30 }
31
32 void VerifyGetHostNameResponse(const base::DictionaryValue* response) {
33 EXPECT_TRUE(response);
34 std::string value;
35 EXPECT_TRUE(response->GetString("type", &value));
36 EXPECT_EQ(value, "getHostNameResponse");
37 EXPECT_TRUE(response->GetString("hostname", &value));
38 EXPECT_EQ(value, net::GetHostName());
39 }
40
41 void VerifyGetPinHashResponse(const base::DictionaryValue* response) {
42 EXPECT_TRUE(response);
43 std::string value;
44 EXPECT_TRUE(response->GetString("type", &value));
45 EXPECT_EQ(value, "getPinHashResponse");
46 EXPECT_TRUE(response->GetString("hash", &value));
47 EXPECT_EQ(value, remoting::MakeHostPinHash("my_host", "1234"));
48 }
49
50 void VerifyGenerateKeyPairResponse(const base::DictionaryValue* response) {
51 EXPECT_TRUE(response);
52 std::string value;
53 EXPECT_TRUE(response->GetString("type", &value));
54 EXPECT_EQ(value, "generateKeyPairResponse");
55 EXPECT_TRUE(response->GetString("private_key", &value));
56 EXPECT_TRUE(response->GetString("public_key", &value));
57 }
58
59 void VerifyGetDaemonConfigResponse(const base::DictionaryValue* response) {
60 EXPECT_TRUE(response);
61 std::string value;
62 EXPECT_TRUE(response->GetString("type", &value));
63 EXPECT_EQ(value, "getDaemonConfigResponse");
64 EXPECT_TRUE(response->GetString("config", &value));
65 EXPECT_EQ(value, "{}");
66 }
67
68 void VerifyGetUsageStatsConsentResponse(const base::DictionaryValue* response) {
69 EXPECT_TRUE(response);
70 std::string value;
71 EXPECT_TRUE(response->GetString("type", &value));
72 EXPECT_EQ(value, "getUsageStatsConsentResponse");
73 bool supported, allowed, set_by_policy;
74 EXPECT_TRUE(response->GetBoolean("supported", &supported));
75 EXPECT_TRUE(response->GetBoolean("allowed", &allowed));
76 EXPECT_TRUE(response->GetBoolean("set_by_policy", &set_by_policy));
77 EXPECT_TRUE(supported);
78 EXPECT_TRUE(allowed);
79 EXPECT_TRUE(set_by_policy);
80 }
81
82 void VerifyStopDaemonResponse(const base::DictionaryValue* response) {
83 EXPECT_TRUE(response);
84 std::string value;
85 EXPECT_TRUE(response->GetString("type", &value));
86 EXPECT_EQ(value, "stopDaemonResponse");
87 int result;
88 EXPECT_TRUE(response->GetInteger("result", &result));
89 EXPECT_EQ(result, 0);
90 }
91
92 void VerifyGetDaemonStateResponse(const base::DictionaryValue* response) {
93 EXPECT_TRUE(response);
94 std::string value;
95 EXPECT_TRUE(response->GetString("type", &value));
96 EXPECT_EQ(value, "getDaemonStateResponse");
97 int result;
98 EXPECT_TRUE(response->GetInteger("state", &result));
99 EXPECT_EQ(result, 4);
100 }
101
102 void VerifyUpdateDaemonConfigResponse(const base::DictionaryValue* response) {
103 EXPECT_TRUE(response);
104 std::string value;
105 EXPECT_TRUE(response->GetString("type", &value));
106 EXPECT_EQ(value, "updateDaemonConfigResponse");
107 int result;
108 EXPECT_TRUE(response->GetInteger("result", &result));
109 EXPECT_EQ(result, 0);
110 }
111
112 void VerifyStartDaemonResponse(const base::DictionaryValue* response) {
113 EXPECT_TRUE(response);
114 std::string value;
115 EXPECT_TRUE(response->GetString("type", &value));
116 EXPECT_EQ(value, "startDaemonResponse");
117 int result;
118 EXPECT_TRUE(response->GetInteger("result", &result));
119 EXPECT_EQ(result, 0);
120 }
121
122 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
123 base::PlatformFile handle) {
124 uint32 length;
125 int read_result = base::ReadPlatformFileAtCurrentPos(
126 handle, reinterpret_cast<char*>(&length), sizeof(length));
127 if (read_result != sizeof(length)) {
128 return scoped_ptr<base::DictionaryValue>();
129 }
130
131 std::string message_json(length, '\0');
132 read_result = base::ReadPlatformFileAtCurrentPos(
133 handle, string_as_array(&message_json), length);
134 if (read_result != static_cast<int>(length)) {
135 return scoped_ptr<base::DictionaryValue>();
136 }
137
138 scoped_ptr<base::Value> message(base::JSONReader::Read(message_json));
139 if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) {
140 return scoped_ptr<base::DictionaryValue>();
141 }
142
143 return scoped_ptr<base::DictionaryValue>(
144 static_cast<base::DictionaryValue*>(message.release()));
145 }
146
147 } // namespace
148
149 namespace remoting {
150
151 class NativeMessagingHostTest : public testing::Test {
152 public:
153 NativeMessagingHostTest();
154 virtual ~NativeMessagingHostTest();
155
156 virtual void SetUp() OVERRIDE;
157 virtual void TearDown() OVERRIDE;
158
159 void Run();
160
161 void WriteMessageToInputFile(const base::Value& message);
162
163 // The Host process should shut down when it receives a malformed request.
164 // This is tested by sending a known-good request, followed by |message|,
165 // followed by the known-good request again. The response file should only
166 // contain a single response from the first good request.
167 void TestBadRequest(const base::Value& message);
168
169 base::FilePath output_path() const { return output_path_; }
170
171 private:
172 base::FilePath input_path_;
173 base::PlatformFile input_handle_;
174 base::FilePath output_path_;
175 base::PlatformFile output_handle_;
176
177 base::MessageLoop message_loop_;
178 base::RunLoop run_loop_;
179 scoped_ptr<remoting::NativeMessagingHost> host_;
180 };
181
182 NativeMessagingHostTest::NativeMessagingHostTest()
183 : message_loop_(base::MessageLoop::TYPE_IO) {}
184
185 NativeMessagingHostTest::~NativeMessagingHostTest() {}
186
187 void NativeMessagingHostTest::SetUp() {
188 file_util::CreateTemporaryFile(&input_path_);
189 input_handle_ = base::CreatePlatformFile(
190 input_path_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
191 NULL);
192
193 file_util::CreateTemporaryFile(&output_path_);
194 output_handle_ = base::CreatePlatformFile(
195 output_path_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, NULL,
196 NULL);
197
198 host_.reset(new NativeMessagingHost(input_handle_, output_handle_,
199 message_loop_.message_loop_proxy(),
200 run_loop_.QuitClosure()));
201 host_->SetDaemonControllerForTest(
202 scoped_ptr<DaemonController>(new MockDaemonController()));
203 }
204
205 void NativeMessagingHostTest::TearDown() {
206 base::ClosePlatformFile(input_handle_);
207 base::ClosePlatformFile(output_handle_);
208 EXPECT_TRUE(file_util::Delete(input_path_, false));
209 EXPECT_TRUE(file_util::Delete(output_path_, false));
210 }
211
212 void NativeMessagingHostTest::Run() {
213 host_->Start();
214 run_loop_.Run();
215 }
216
217 void NativeMessagingHostTest::WriteMessageToInputFile(
218 const base::Value& message) {
219 std::string message_json;
220 base::JSONWriter::Write(&message, &message_json);
221
222 uint32 length = message_json.length();
223 file_util::AppendToFile(input_path_, reinterpret_cast<char*>(&length),
224 sizeof(length));
225 file_util::AppendToFile(input_path_, message_json.data(), length);
226 }
227
228 void NativeMessagingHostTest::TestBadRequest(const base::Value& message) {
229 base::DictionaryValue good_message;
230 good_message.SetString("type", "hello");
231
232 WriteMessageToInputFile(good_message);
233 WriteMessageToInputFile(message);
234 WriteMessageToInputFile(good_message);
235
236 Run();
237
238 // Read from output file, and verify responses.
239 base::PlatformFile handle = base::CreatePlatformFile(
240 output_path(), base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
241 NULL);
242
243 scoped_ptr<base::DictionaryValue> response = ReadMessageFromFile(handle);
244 VerifyHelloResponse(response.get());
245
246 response = ReadMessageFromFile(handle);
247 EXPECT_FALSE(response);
248 }
249
250 TEST_F(NativeMessagingHostTest, All) {
251 base::DictionaryValue message;
252 message.SetString("type", "hello");
253 WriteMessageToInputFile(message);
254
255 message.SetString("type", "getHostName");
256 WriteMessageToInputFile(message);
257
258 message.SetString("type", "getPinHash");
259 message.SetString("hostId", "my_host");
260 message.SetString("pin", "1234");
261 WriteMessageToInputFile(message);
262
263 message.Clear();
264 message.SetString("type", "generateKeyPair");
265 WriteMessageToInputFile(message);
266
267 message.SetString("type", "getDaemonConfig");
268 WriteMessageToInputFile(message);
269
270 message.SetString("type", "getUsageStatsConsent");
271 WriteMessageToInputFile(message);
272
273 message.SetString("type", "stopDaemon");
274 WriteMessageToInputFile(message);
275
276 message.SetString("type", "getDaemonState");
277 WriteMessageToInputFile(message);
278
279 // Following messages require a "config" dictionary.
280 message.SetString("config", "{}");
281 message.SetString("type", "updateDaemonConfig");
282 WriteMessageToInputFile(message);
283
284 message.SetBoolean("consent", true);
285 message.SetString("type", "startDaemon");
286 WriteMessageToInputFile(message);
287
288 Run();
289
290 // Read from output file, and verify responses.
291 base::PlatformFile handle = base::CreatePlatformFile(
292 output_path(), base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
293 NULL);
294
295 scoped_ptr<base::DictionaryValue> response = ReadMessageFromFile(handle);
296 VerifyHelloResponse(response.get());
297
298 response = ReadMessageFromFile(handle);
299 VerifyGetHostNameResponse(response.get());
300
301 response = ReadMessageFromFile(handle);
302 VerifyGetPinHashResponse(response.get());
303
304 response = ReadMessageFromFile(handle);
305 VerifyGenerateKeyPairResponse(response.get());
306
307 response = ReadMessageFromFile(handle);
308 VerifyGetDaemonConfigResponse(response.get());
309
310 response = ReadMessageFromFile(handle);
311 VerifyGetUsageStatsConsentResponse(response.get());
312
313 response = ReadMessageFromFile(handle);
314 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
315
316 response = ReadMessageFromFile(handle);
317 VerifyGetDaemonStateResponse(response.get());
318
319 response = ReadMessageFromFile(handle);
320 VerifyUpdateDaemonConfigResponse(response.get());
321
322 response = ReadMessageFromFile(handle);
323 VerifyStartDaemonResponse(response.get());
324
325 base::ClosePlatformFile(handle);
326 }
327
328 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.
329 base::DictionaryValue message;
330 message.SetString("type", "hello");
331 WriteMessageToInputFile(message);
332 message.SetString("id", "42");
333 WriteMessageToInputFile(message);
334
335 Run();
336
337 base::PlatformFile handle = base::CreatePlatformFile(
338 output_path(), base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, NULL,
339 NULL);
340 scoped_ptr<base::DictionaryValue> response = ReadMessageFromFile(handle);
341 EXPECT_TRUE(response);
342 std::string value;
343 EXPECT_FALSE(response->GetString("id", &value));
344
345 response = ReadMessageFromFile(handle);
346 EXPECT_TRUE(response);
347 EXPECT_TRUE(response->GetString("id", &value));
348 EXPECT_EQ(value, "42");
349 }
350
351 TEST_F(NativeMessagingHostTest, WrongFormat) {
352 // Request should be a Dictionary.
353 base::ListValue message;
354 TestBadRequest(message);
355 }
356
357 TEST_F(NativeMessagingHostTest, MissingType) {
358 base::DictionaryValue message;
359 TestBadRequest(message);
360 }
361
362 TEST_F(NativeMessagingHostTest, InvalidType) {
363 base::DictionaryValue message;
364 message.SetString("type", "xxx");
365 TestBadRequest(message);
366 }
367
368 TEST_F(NativeMessagingHostTest, GetPinHashNoHostId) {
369 base::DictionaryValue message;
370 message.SetString("type", "getPinHash");
371 message.SetString("pin", "1234");
372 TestBadRequest(message);
373 }
374
375 TEST_F(NativeMessagingHostTest, GetPinHashNoPin) {
376 base::DictionaryValue message;
377 message.SetString("type", "getPinHash");
378 message.SetString("hostId", "my_host");
379 TestBadRequest(message);
380 }
381
382 TEST_F(NativeMessagingHostTest, UpdateDaemonConfigInvalidConfig) {
383 base::DictionaryValue message;
384 message.SetString("type", "updateDaemonConfig");
385 message.SetString("config", "xxx");
386 TestBadRequest(message);
387 }
388
389 TEST_F(NativeMessagingHostTest, StartDaemonInvalidConfig) {
390 base::DictionaryValue message;
391 message.SetString("type", "startDaemon");
392 message.SetString("config", "xxx");
393 message.SetBoolean("consent", true);
394 TestBadRequest(message);
395 }
396
397 TEST_F(NativeMessagingHostTest, StartDaemonNoConsent) {
398 base::DictionaryValue message;
399 message.SetString("type", "startDaemon");
400 message.SetString("config", "{}");
401 TestBadRequest(message);
402 }
403
404 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698