blob: c212e54379cac8836258a2d705240ee8bfca8261 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Vitaly Buka7ce499f2015-06-09 08:04:11 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/privet/privet_handler.h"
Vitaly Buka7ce499f2015-06-09 08:04:11 -07006
7#include <set>
8#include <string>
9#include <utility>
10
11#include <base/bind.h>
12#include <base/json/json_reader.h>
13#include <base/json/json_writer.h>
Vitaly Buka7ce499f2015-06-09 08:04:11 -070014#include <base/strings/string_util.h>
15#include <base/values.h>
Vitaly Buka7ce499f2015-06-09 08:04:11 -070016#include <gmock/gmock.h>
17#include <gtest/gtest.h>
18
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020019#include "src/privet/constants.h"
20#include "src/privet/mock_delegates.h"
Vitaly Buka7ce499f2015-06-09 08:04:11 -070021
22using testing::_;
23using testing::DoAll;
24using testing::Invoke;
25using testing::Return;
26using testing::SetArgPointee;
Alex Vakulenkoefee3a22015-11-17 15:08:38 -080027using testing::SaveArg;
Vitaly Bukaf7f52d42015-10-10 22:43:55 -070028using testing::WithArgs;
Vitaly Buka7ce499f2015-06-09 08:04:11 -070029
Vitaly Bukab6f015a2015-07-09 14:59:23 -070030namespace weave {
31namespace privet {
Vitaly Buka7ce499f2015-06-09 08:04:11 -070032
33namespace {
34
35void LoadTestJson(const std::string& test_json,
36 base::DictionaryValue* dictionary) {
37 std::string json = test_json;
38 base::ReplaceChars(json, "'", "\"", &json);
39 int error = 0;
40 std::string message;
Alex Vakulenkoae1ffbc2015-06-15 12:53:22 -070041 std::unique_ptr<base::Value> value(
42 base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC, &error,
43 &message)
44 .release());
Vitaly Buka7ce499f2015-06-09 08:04:11 -070045 EXPECT_TRUE(value.get()) << "\nError: " << message << "\n" << json;
46 base::DictionaryValue* dictionary_ptr = nullptr;
47 if (value->GetAsDictionary(&dictionary_ptr))
48 dictionary->MergeDictionary(dictionary_ptr);
49}
50
51bool IsEqualValue(const base::Value& val1, const base::Value& val2) {
52 return val1.Equals(&val2);
53}
54
55struct CodeWithReason {
56 CodeWithReason(int code_in, const std::string& reason_in)
57 : code(code_in), reason(reason_in) {}
58 int code;
59 std::string reason;
60};
61
62std::ostream& operator<<(std::ostream& stream, const CodeWithReason& error) {
63 return stream << "{" << error.code << ", " << error.reason << "}";
64}
65
66bool IsEqualError(const CodeWithReason& expected,
67 const base::DictionaryValue& dictionary) {
68 std::string reason;
69 int code = 0;
70 return dictionary.GetInteger("error.http_status", &code) &&
71 code == expected.code && dictionary.GetString("error.code", &reason) &&
72 reason == expected.reason;
73}
74
75bool IsEqualDictionary(const base::DictionaryValue& dictionary1,
76 const base::DictionaryValue& dictionary2) {
77 base::DictionaryValue::Iterator it1(dictionary1);
78 base::DictionaryValue::Iterator it2(dictionary2);
79 for (; !it1.IsAtEnd() && !it2.IsAtEnd(); it1.Advance(), it2.Advance()) {
80 // Output mismatched keys.
81 EXPECT_EQ(it1.key(), it2.key());
82 if (it1.key() != it2.key())
83 return false;
84
85 if (it1.key() == "error") {
86 std::string code1;
87 std::string code2;
88 const char kCodeKey[] = "error.code";
89 if (!dictionary1.GetString(kCodeKey, &code1) ||
90 !dictionary2.GetString(kCodeKey, &code2) || code1 != code2) {
91 return false;
92 }
93 continue;
94 }
95
96 const base::DictionaryValue* d1{nullptr};
97 const base::DictionaryValue* d2{nullptr};
98 if (it1.value().GetAsDictionary(&d1) && it2.value().GetAsDictionary(&d2)) {
99 if (!IsEqualDictionary(*d1, *d2))
100 return false;
101 continue;
102 }
103
104 // Output mismatched values.
105 EXPECT_PRED2(IsEqualValue, it1.value(), it2.value());
106 if (!IsEqualValue(it1.value(), it2.value()))
107 return false;
108 }
109
110 return it1.IsAtEnd() && it2.IsAtEnd();
111}
112
113bool IsEqualJson(const std::string& test_json,
114 const base::DictionaryValue& dictionary) {
115 base::DictionaryValue dictionary2;
116 LoadTestJson(test_json, &dictionary2);
117 return IsEqualDictionary(dictionary2, dictionary);
118}
119
120} // namespace
121
122class PrivetHandlerTest : public testing::Test {
123 public:
124 PrivetHandlerTest() {}
125
126 protected:
127 void SetUp() override {
128 auth_header_ = "Privet anonymous";
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700129 handler_.reset(new PrivetHandler(&cloud_, &device_, &security_, &wifi_));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700130 }
131
132 const base::DictionaryValue& HandleRequest(
133 const std::string& api,
134 const base::DictionaryValue* input) {
135 output_.Clear();
136 handler_->HandleRequest(api, auth_header_, input,
137 base::Bind(&PrivetHandlerTest::HandlerCallback,
138 base::Unretained(this)));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700139 return output_;
140 }
141
142 const base::DictionaryValue& HandleRequest(const std::string& api,
143 const std::string& json_input) {
144 base::DictionaryValue dictionary;
145 LoadTestJson(json_input, &dictionary);
146 return HandleRequest(api, &dictionary);
147 }
148
149 void HandleUnknownRequest(const std::string& api) {
150 output_.Clear();
151 base::DictionaryValue dictionary;
152 handler_->HandleRequest(api, auth_header_, &dictionary,
153 base::Bind(&PrivetHandlerTest::HandlerNoFound));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700154 }
155
Alex Vakulenkoefee3a22015-11-17 15:08:38 -0800156 const base::DictionaryValue& GetResponse() const { return output_; }
157 int GetResponseCount() const { return response_count_; }
158
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700159 void SetNoWifiAndGcd() {
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700160 handler_.reset(new PrivetHandler(&cloud_, &device_, &security_, nullptr));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700161 EXPECT_CALL(cloud_, GetCloudId()).WillRepeatedly(Return(""));
162 EXPECT_CALL(cloud_, GetConnectionState())
163 .WillRepeatedly(ReturnRef(gcd_disabled_state_));
Vitaly Bukaa647c852015-07-06 14:51:01 -0700164 auto set_error = [](const std::string&, const std::string&,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700165 ErrorPtr* error) {
166 Error::AddTo(error, FROM_HERE, errors::kDomain, "setupUnavailable", "");
Vitaly Buka075b3d42015-06-09 08:34:25 -0700167 };
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700168 EXPECT_CALL(cloud_, Setup(_, _, _))
169 .WillRepeatedly(DoAll(Invoke(set_error), Return(false)));
170 }
171
172 testing::StrictMock<MockCloudDelegate> cloud_;
173 testing::StrictMock<MockDeviceDelegate> device_;
174 testing::StrictMock<MockSecurityDelegate> security_;
175 testing::StrictMock<MockWifiDelegate> wifi_;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700176 std::string auth_header_;
177
178 private:
179 void HandlerCallback(int status, const base::DictionaryValue& output) {
Alex Vakulenkoefee3a22015-11-17 15:08:38 -0800180 output_.Clear();
181 ++response_count_;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700182 output_.MergeDictionary(&output);
183 if (!output_.HasKey("error")) {
Vitaly Buka1da65992015-08-06 01:38:57 -0700184 EXPECT_EQ(200, status);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700185 return;
186 }
Vitaly Buka1da65992015-08-06 01:38:57 -0700187 EXPECT_NE(200, status);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700188 output_.SetInteger("error.http_status", status);
189 }
190
191 static void HandlerNoFound(int status, const base::DictionaryValue&) {
Vitaly Buka1da65992015-08-06 01:38:57 -0700192 EXPECT_EQ(404, status);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700193 }
194
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700195 std::unique_ptr<PrivetHandler> handler_;
196 base::DictionaryValue output_;
Alex Vakulenkoefee3a22015-11-17 15:08:38 -0800197 int response_count_{0};
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700198 ConnectionState gcd_disabled_state_{ConnectionState::kDisabled};
199};
200
201TEST_F(PrivetHandlerTest, UnknownApi) {
202 HandleUnknownRequest("/privet/foo");
203}
204
205TEST_F(PrivetHandlerTest, InvalidFormat) {
206 auth_header_ = "";
207 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidFormat"),
208 HandleRequest("/privet/info", nullptr));
209}
210
211TEST_F(PrivetHandlerTest, MissingAuth) {
212 auth_header_ = "";
213 EXPECT_PRED2(IsEqualError, CodeWithReason(401, "missingAuthorization"),
214 HandleRequest("/privet/info", "{}"));
215}
216
217TEST_F(PrivetHandlerTest, InvalidAuth) {
218 auth_header_ = "foo";
219 EXPECT_PRED2(IsEqualError, CodeWithReason(401, "invalidAuthorization"),
220 HandleRequest("/privet/info", "{}"));
221}
222
223TEST_F(PrivetHandlerTest, ExpiredAuth) {
224 auth_header_ = "Privet 123";
225 EXPECT_CALL(security_, ParseAccessToken(_, _))
226 .WillRepeatedly(DoAll(SetArgPointee<1>(base::Time()),
227 Return(UserInfo{AuthScope::kOwner, 1})));
228 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "authorizationExpired"),
229 HandleRequest("/privet/info", "{}"));
230}
231
232TEST_F(PrivetHandlerTest, InvalidAuthScope) {
233 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthorizationScope"),
234 HandleRequest("/privet/v3/setup/start", "{}"));
235}
236
237TEST_F(PrivetHandlerTest, InfoMinimal) {
238 SetNoWifiAndGcd();
239 EXPECT_CALL(security_, GetPairingTypes())
240 .WillRepeatedly(Return(std::set<PairingType>{}));
241 EXPECT_CALL(security_, GetCryptoTypes())
242 .WillRepeatedly(Return(std::set<CryptoType>{}));
243
244 const char kExpected[] = R"({
245 'version': '3.0',
246 'id': 'TestId',
247 'name': 'TestDevice',
Vitaly Buka87eb7882015-10-27 22:23:49 -0700248 'services': [ "developmentBoard" ],
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700249 'modelManifestId': "ABMID",
250 'basicModelManifest': {
251 'uiDeviceKind': 'developmentBoard',
252 'oemName': 'Chromium',
253 'modelName': 'Brillo'
254 },
255 'endpoints': {
256 'httpPort': 0,
257 'httpUpdatesPort': 0,
258 'httpsPort': 0,
259 'httpsUpdatesPort': 0
260 },
261 'authentication': {
262 'anonymousMaxScope': 'user',
263 'mode': [
264 'anonymous',
265 'pairing'
266 ],
267 'pairing': [
268 ],
269 'crypto': [
270 ]
271 },
272 'gcd': {
273 'id': '',
274 'status': 'disabled'
275 },
276 'uptime': 3600
277 })";
278 EXPECT_PRED2(IsEqualJson, kExpected, HandleRequest("/privet/info", "{}"));
279}
280
281TEST_F(PrivetHandlerTest, Info) {
282 EXPECT_CALL(cloud_, GetDescription())
283 .WillRepeatedly(Return("TestDescription"));
284 EXPECT_CALL(cloud_, GetLocation()).WillRepeatedly(Return("TestLocation"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700285 EXPECT_CALL(device_, GetHttpEnpoint())
286 .WillRepeatedly(Return(std::make_pair(80, 10080)));
287 EXPECT_CALL(device_, GetHttpsEnpoint())
288 .WillRepeatedly(Return(std::make_pair(443, 10443)));
289 EXPECT_CALL(wifi_, GetHostedSsid())
290 .WillRepeatedly(Return("Test_device.BBABCLAprv"));
291
292 const char kExpected[] = R"({
293 'version': '3.0',
294 'id': 'TestId',
295 'name': 'TestDevice',
296 'description': 'TestDescription',
297 'location': 'TestLocation',
Vitaly Buka87eb7882015-10-27 22:23:49 -0700298 'services': [ "developmentBoard" ],
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700299 'modelManifestId': "ABMID",
300 'basicModelManifest': {
301 'uiDeviceKind': 'developmentBoard',
302 'oemName': 'Chromium',
303 'modelName': 'Brillo'
304 },
305 'endpoints': {
306 'httpPort': 80,
307 'httpUpdatesPort': 10080,
308 'httpsPort': 443,
309 'httpsUpdatesPort': 10443
310 },
311 'authentication': {
312 'anonymousMaxScope': 'none',
313 'mode': [
314 'anonymous',
315 'pairing'
316 ],
317 'pairing': [
318 'pinCode',
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700319 'embeddedCode'
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700320 ],
321 'crypto': [
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700322 'p224_spake2'
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700323 ]
324 },
325 'wifi': {
326 'capabilities': [
327 '2.4GHz'
328 ],
329 'ssid': 'TestSsid',
330 'hostedSsid': 'Test_device.BBABCLAprv',
331 'status': 'offline'
332 },
333 'gcd': {
334 'id': 'TestCloudId',
335 'status': 'online'
336 },
337 'uptime': 3600
338 })";
339 EXPECT_PRED2(IsEqualJson, kExpected, HandleRequest("/privet/info", "{}"));
340}
341
342TEST_F(PrivetHandlerTest, PairingStartInvalidParams) {
343 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
344 HandleRequest("/privet/v3/pairing/start",
345 "{'pairing':'embeddedCode','crypto':'crypto'}"));
346
347 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
348 HandleRequest("/privet/v3/pairing/start",
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700349 "{'pairing':'code','crypto':'p224_spake2'}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700350}
351
352TEST_F(PrivetHandlerTest, PairingStart) {
353 EXPECT_PRED2(
354 IsEqualJson,
355 "{'deviceCommitment': 'testCommitment', 'sessionId': 'testSession'}",
356 HandleRequest("/privet/v3/pairing/start",
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700357 "{'pairing': 'embeddedCode', 'crypto': 'p224_spake2'}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700358}
359
360TEST_F(PrivetHandlerTest, PairingConfirm) {
361 EXPECT_PRED2(
362 IsEqualJson,
363 "{'certFingerprint':'testFingerprint','certSignature':'testSignature'}",
364 HandleRequest(
365 "/privet/v3/pairing/confirm",
366 "{'sessionId':'testSession','clientCommitment':'testCommitment'}"));
367}
368
369TEST_F(PrivetHandlerTest, PairingCancel) {
370 EXPECT_PRED2(IsEqualJson, "{}",
371 HandleRequest("/privet/v3/pairing/cancel",
372 "{'sessionId': 'testSession'}"));
373}
374
375TEST_F(PrivetHandlerTest, AuthErrorNoType) {
376 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidAuthMode"),
377 HandleRequest("/privet/v3/auth", "{}"));
378}
379
380TEST_F(PrivetHandlerTest, AuthErrorInvalidType) {
381 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidAuthMode"),
382 HandleRequest("/privet/v3/auth", "{'mode':'unknown'}"));
383}
384
385TEST_F(PrivetHandlerTest, AuthErrorNoScope) {
386 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidRequestedScope"),
387 HandleRequest("/privet/v3/auth", "{'mode':'anonymous'}"));
388}
389
390TEST_F(PrivetHandlerTest, AuthErrorInvalidScope) {
391 EXPECT_PRED2(
392 IsEqualError, CodeWithReason(400, "invalidRequestedScope"),
393 HandleRequest("/privet/v3/auth",
394 "{'mode':'anonymous','requestedScope':'unknown'}"));
395}
396
397TEST_F(PrivetHandlerTest, AuthErrorAccessDenied) {
398 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "accessDenied"),
399 HandleRequest("/privet/v3/auth",
400 "{'mode':'anonymous','requestedScope':'owner'}"));
401}
402
403TEST_F(PrivetHandlerTest, AuthErrorInvalidAuthCode) {
404 EXPECT_CALL(security_, IsValidPairingCode("testToken"))
405 .WillRepeatedly(Return(false));
406 const char kInput[] = R"({
407 'mode': 'pairing',
408 'requestedScope': 'user',
409 'authCode': 'testToken'
410 })";
411 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthCode"),
412 HandleRequest("/privet/v3/auth", kInput));
413}
414
415TEST_F(PrivetHandlerTest, AuthAnonymous) {
416 const char kExpected[] = R"({
417 'accessToken': 'GuestAccessToken',
418 'expiresIn': 3600,
419 'scope': 'user',
420 'tokenType': 'Privet'
421 })";
422 EXPECT_PRED2(IsEqualJson, kExpected,
423 HandleRequest("/privet/v3/auth",
424 "{'mode':'anonymous','requestedScope':'auto'}"));
425}
426
427TEST_F(PrivetHandlerTest, AuthPairing) {
428 EXPECT_CALL(security_, IsValidPairingCode("testToken"))
429 .WillRepeatedly(Return(true));
430 EXPECT_CALL(security_, CreateAccessToken(_, _))
431 .WillRepeatedly(Return("OwnerAccessToken"));
432 const char kInput[] = R"({
433 'mode': 'pairing',
434 'requestedScope': 'owner',
435 'authCode': 'testToken'
436 })";
437 const char kExpected[] = R"({
438 'accessToken': 'OwnerAccessToken',
439 'expiresIn': 3600,
440 'scope': 'owner',
441 'tokenType': 'Privet'
442 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700443 EXPECT_PRED2(IsEqualJson, kExpected,
444 HandleRequest("/privet/v3/auth", kInput));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700445}
446
447class PrivetHandlerSetupTest : public PrivetHandlerTest {
448 public:
449 void SetUp() override {
450 PrivetHandlerTest::SetUp();
451 auth_header_ = "Privet 123";
452 EXPECT_CALL(security_, ParseAccessToken(_, _))
453 .WillRepeatedly(DoAll(SetArgPointee<1>(base::Time::Now()),
454 Return(UserInfo{AuthScope::kOwner, 1})));
455 }
456};
457
458TEST_F(PrivetHandlerSetupTest, StatusEmpty) {
459 SetNoWifiAndGcd();
Vitaly Buka075b3d42015-06-09 08:34:25 -0700460 EXPECT_PRED2(IsEqualJson, "{}",
461 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700462}
463
464TEST_F(PrivetHandlerSetupTest, StatusWifi) {
465 wifi_.setup_state_ = SetupState{SetupState::kSuccess};
466
467 const char kExpected[] = R"({
468 'wifi': {
469 'ssid': 'TestSsid',
470 'status': 'success'
471 }
472 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700473 EXPECT_PRED2(IsEqualJson, kExpected,
474 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700475}
476
477TEST_F(PrivetHandlerSetupTest, StatusWifiError) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700478 ErrorPtr error;
479 Error::AddTo(&error, FROM_HERE, "test", "invalidPassphrase", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700480 wifi_.setup_state_ = SetupState{std::move(error)};
481
482 const char kExpected[] = R"({
483 'wifi': {
484 'status': 'error',
485 'error': {
486 'code': 'invalidPassphrase'
487 }
488 }
489 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700490 EXPECT_PRED2(IsEqualJson, kExpected,
491 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700492}
493
494TEST_F(PrivetHandlerSetupTest, StatusGcd) {
495 cloud_.setup_state_ = SetupState{SetupState::kSuccess};
496
497 const char kExpected[] = R"({
498 'gcd': {
499 'id': 'TestCloudId',
500 'status': 'success'
501 }
502 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700503 EXPECT_PRED2(IsEqualJson, kExpected,
504 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700505}
506
507TEST_F(PrivetHandlerSetupTest, StatusGcdError) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700508 ErrorPtr error;
509 Error::AddTo(&error, FROM_HERE, "test", "invalidTicket", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700510 cloud_.setup_state_ = SetupState{std::move(error)};
511
512 const char kExpected[] = R"({
513 'gcd': {
514 'status': 'error',
515 'error': {
516 'code': 'invalidTicket'
517 }
518 }
519 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700520 EXPECT_PRED2(IsEqualJson, kExpected,
521 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700522}
523
524TEST_F(PrivetHandlerSetupTest, SetupNameDescriptionLocation) {
Vitaly Bukab624bc42015-09-29 19:13:55 -0700525 EXPECT_CALL(cloud_,
526 UpdateDeviceInfo("testName", "testDescription", "testLocation"))
Vitaly Bukaa647c852015-07-06 14:51:01 -0700527 .Times(1);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700528 const char kInput[] = R"({
529 'name': 'testName',
530 'description': 'testDescription',
531 'location': 'testLocation'
532 })";
533 EXPECT_PRED2(IsEqualJson, "{}",
534 HandleRequest("/privet/v3/setup/start", kInput));
535}
536
537TEST_F(PrivetHandlerSetupTest, InvalidParams) {
538 const char kInputWifi[] = R"({
539 'wifi': {
540 'ssid': ''
541 }
542 })";
543 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
544 HandleRequest("/privet/v3/setup/start", kInputWifi));
545
546 const char kInputRegistration[] = R"({
547 'gcd': {
548 'ticketId': ''
549 }
550 })";
551 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
552 HandleRequest("/privet/v3/setup/start", kInputRegistration));
553}
554
555TEST_F(PrivetHandlerSetupTest, WifiSetupUnavailable) {
556 SetNoWifiAndGcd();
557 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "setupUnavailable"),
558 HandleRequest("/privet/v3/setup/start", "{'wifi': {}}"));
559}
560
561TEST_F(PrivetHandlerSetupTest, WifiSetup) {
562 const char kInput[] = R"({
563 'wifi': {
564 'ssid': 'testSsid',
565 'passphrase': 'testPass'
566 }
567 })";
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700568 auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) {
569 Error::AddTo(error, FROM_HERE, errors::kDomain, "deviceBusy", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700570 };
571 EXPECT_CALL(wifi_, ConfigureCredentials(_, _, _))
572 .WillOnce(DoAll(Invoke(set_error), Return(false)));
573 EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"),
574 HandleRequest("/privet/v3/setup/start", kInput));
575
576 const char kExpected[] = R"({
577 'wifi': {
578 'status': 'inProgress'
579 }
580 })";
581 wifi_.setup_state_ = SetupState{SetupState::kInProgress};
582 EXPECT_CALL(wifi_, ConfigureCredentials("testSsid", "testPass", _))
583 .WillOnce(Return(true));
584 EXPECT_PRED2(IsEqualJson, kExpected,
585 HandleRequest("/privet/v3/setup/start", kInput));
586}
587
588TEST_F(PrivetHandlerSetupTest, GcdSetupUnavailable) {
589 SetNoWifiAndGcd();
590 const char kInput[] = R"({
591 'gcd': {
592 'ticketId': 'testTicket',
593 'user': 'testUser'
594 }
595 })";
596
597 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "setupUnavailable"),
598 HandleRequest("/privet/v3/setup/start", kInput));
599}
600
601TEST_F(PrivetHandlerSetupTest, GcdSetup) {
602 const char kInput[] = R"({
603 'gcd': {
604 'ticketId': 'testTicket',
605 'user': 'testUser'
606 }
607 })";
608
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700609 auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) {
610 Error::AddTo(error, FROM_HERE, errors::kDomain, "deviceBusy", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700611 };
612 EXPECT_CALL(cloud_, Setup(_, _, _))
613 .WillOnce(DoAll(Invoke(set_error), Return(false)));
614 EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"),
615 HandleRequest("/privet/v3/setup/start", kInput));
616
617 const char kExpected[] = R"({
618 'gcd': {
619 'status': 'inProgress'
620 }
621 })";
622 cloud_.setup_state_ = SetupState{SetupState::kInProgress};
623 EXPECT_CALL(cloud_, Setup("testTicket", "testUser", _))
624 .WillOnce(Return(true));
625 EXPECT_PRED2(IsEqualJson, kExpected,
626 HandleRequest("/privet/v3/setup/start", kInput));
627}
628
629TEST_F(PrivetHandlerSetupTest, State) {
630 EXPECT_PRED2(IsEqualJson, "{'state': {'test': {}}, 'fingerprint': '0'}",
631 HandleRequest("/privet/v3/state", "{}"));
632
633 cloud_.NotifyOnStateChanged();
634
635 EXPECT_PRED2(IsEqualJson, "{'state': {'test': {}}, 'fingerprint': '1'}",
636 HandleRequest("/privet/v3/state", "{}"));
637}
638
639TEST_F(PrivetHandlerSetupTest, CommandsDefs) {
640 EXPECT_PRED2(IsEqualJson, "{'commands': {'test':{}}, 'fingerprint': '0'}",
641 HandleRequest("/privet/v3/commandDefs", "{}"));
642
643 cloud_.NotifyOnCommandDefsChanged();
644
645 EXPECT_PRED2(IsEqualJson, "{'commands': {'test':{}}, 'fingerprint': '1'}",
646 HandleRequest("/privet/v3/commandDefs", "{}"));
647}
648
649TEST_F(PrivetHandlerSetupTest, CommandsExecute) {
650 const char kInput[] = "{'name': 'test'}";
651 base::DictionaryValue command;
652 LoadTestJson(kInput, &command);
653 LoadTestJson("{'id':'5'}", &command);
Vitaly Buka74763422015-10-11 00:39:52 -0700654 EXPECT_CALL(cloud_, AddCommand(_, _, _))
655 .WillOnce(WithArgs<2>(Invoke(
656 [&command](const CloudDelegate::CommandDoneCallback& callback) {
657 callback.Run(command, nullptr);
658 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700659
660 EXPECT_PRED2(IsEqualJson, "{'name':'test', 'id':'5'}",
661 HandleRequest("/privet/v3/commands/execute", kInput));
662}
663
664TEST_F(PrivetHandlerSetupTest, CommandsStatus) {
665 const char kInput[] = "{'id': '5'}";
666 base::DictionaryValue command;
667 LoadTestJson(kInput, &command);
668 LoadTestJson("{'name':'test'}", &command);
Vitaly Buka74763422015-10-11 00:39:52 -0700669 EXPECT_CALL(cloud_, GetCommand(_, _, _))
670 .WillOnce(WithArgs<2>(Invoke(
671 [&command](const CloudDelegate::CommandDoneCallback& callback) {
672 callback.Run(command, nullptr);
673 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700674
675 EXPECT_PRED2(IsEqualJson, "{'name':'test', 'id':'5'}",
676 HandleRequest("/privet/v3/commands/status", kInput));
677
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700678 ErrorPtr error;
679 Error::AddTo(&error, FROM_HERE, errors::kDomain, "notFound", "");
Vitaly Buka74763422015-10-11 00:39:52 -0700680 EXPECT_CALL(cloud_, GetCommand(_, _, _))
681 .WillOnce(WithArgs<2>(
682 Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) {
683 callback.Run({}, std::move(error));
684 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700685
686 EXPECT_PRED2(IsEqualError, CodeWithReason(404, "notFound"),
687 HandleRequest("/privet/v3/commands/status", "{'id': '15'}"));
688}
689
690TEST_F(PrivetHandlerSetupTest, CommandsCancel) {
691 const char kExpected[] = "{'id': '5', 'name':'test', 'state':'cancelled'}";
692 base::DictionaryValue command;
693 LoadTestJson(kExpected, &command);
Vitaly Buka74763422015-10-11 00:39:52 -0700694 EXPECT_CALL(cloud_, CancelCommand(_, _, _))
695 .WillOnce(WithArgs<2>(Invoke(
696 [&command](const CloudDelegate::CommandDoneCallback& callback) {
697 callback.Run(command, nullptr);
698 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700699
700 EXPECT_PRED2(IsEqualJson, kExpected,
701 HandleRequest("/privet/v3/commands/cancel", "{'id': '8'}"));
702
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700703 ErrorPtr error;
704 Error::AddTo(&error, FROM_HERE, errors::kDomain, "notFound", "");
Vitaly Buka74763422015-10-11 00:39:52 -0700705 EXPECT_CALL(cloud_, CancelCommand(_, _, _))
706 .WillOnce(WithArgs<2>(
707 Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) {
708 callback.Run({}, std::move(error));
709 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700710
711 EXPECT_PRED2(IsEqualError, CodeWithReason(404, "notFound"),
712 HandleRequest("/privet/v3/commands/cancel", "{'id': '11'}"));
713}
714
715TEST_F(PrivetHandlerSetupTest, CommandsList) {
716 const char kExpected[] = R"({
717 'commands' : [
718 {'id':'5', 'state':'cancelled'},
719 {'id':'15', 'state':'inProgress'}
720 ]})";
721
722 base::DictionaryValue commands;
723 LoadTestJson(kExpected, &commands);
724
Vitaly Buka74763422015-10-11 00:39:52 -0700725 EXPECT_CALL(cloud_, ListCommands(_, _))
726 .WillOnce(WithArgs<1>(Invoke(
727 [&commands](const CloudDelegate::CommandDoneCallback& callback) {
728 callback.Run(commands, nullptr);
729 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700730
731 EXPECT_PRED2(IsEqualJson, kExpected,
732 HandleRequest("/privet/v3/commands/list", "{}"));
733}
734
Alex Vakulenkoefee3a22015-11-17 15:08:38 -0800735TEST_F(PrivetHandlerSetupTest, CheckForUpdates_NoInput) {
736 EXPECT_CALL(device_, GetHttpRequestTimeout())
737 .WillOnce(Return(base::TimeDelta::Max()));
738 cloud_.NotifyOnCommandDefsChanged();
739 cloud_.NotifyOnStateChanged();
740 const char kInput[] = "{}";
741 const char kExpected[] = R"({
742 'commandsFingerprint': '1',
743 'stateFingerprint': '1'
744 })";
745 EXPECT_PRED2(IsEqualJson, kExpected,
746 HandleRequest("/privet/v3/checkForUpdates", kInput));
747 EXPECT_EQ(1, GetResponseCount());
748}
749
750TEST_F(PrivetHandlerSetupTest, CheckForUpdates_AlreadyChanged) {
751 EXPECT_CALL(device_, GetHttpRequestTimeout())
752 .WillOnce(Return(base::TimeDelta::Max()));
753 cloud_.NotifyOnCommandDefsChanged();
754 cloud_.NotifyOnStateChanged();
755 const char kInput[] = R"({
756 'commandsFingerprint': '0',
757 'stateFingerprint': '0'
758 })";
759 const char kExpected[] = R"({
760 'commandsFingerprint': '1',
761 'stateFingerprint': '1'
762 })";
763 EXPECT_PRED2(IsEqualJson, kExpected,
764 HandleRequest("/privet/v3/checkForUpdates", kInput));
765 EXPECT_EQ(1, GetResponseCount());
766}
767
768TEST_F(PrivetHandlerSetupTest, CheckForUpdates_LongPollCommands) {
769 EXPECT_CALL(device_, GetHttpRequestTimeout())
770 .WillOnce(Return(base::TimeDelta::Max()));
771 const char kInput[] = R"({
772 'commandsFingerprint': '0',
773 'stateFingerprint': '0'
774 })";
775 EXPECT_PRED2(IsEqualJson, "{}",
776 HandleRequest("/privet/v3/checkForUpdates", kInput));
777 EXPECT_EQ(0, GetResponseCount());
778 cloud_.NotifyOnCommandDefsChanged();
779 EXPECT_EQ(1, GetResponseCount());
780 const char kExpected[] = R"({
781 'commandsFingerprint': '1',
782 'stateFingerprint': '0'
783 })";
784 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
785}
786
787TEST_F(PrivetHandlerSetupTest, CheckForUpdates_LongPollState) {
788 EXPECT_CALL(device_, GetHttpRequestTimeout())
789 .WillOnce(Return(base::TimeDelta::Max()));
790 const char kInput[] = R"({
791 'commandsFingerprint': '0',
792 'stateFingerprint': '0'
793 })";
794 EXPECT_PRED2(IsEqualJson, "{}",
795 HandleRequest("/privet/v3/checkForUpdates", kInput));
796 EXPECT_EQ(0, GetResponseCount());
797 cloud_.NotifyOnStateChanged();
798 EXPECT_EQ(1, GetResponseCount());
799 const char kExpected[] = R"({
800 'commandsFingerprint': '0',
801 'stateFingerprint': '1'
802 })";
803 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
804}
805
806TEST_F(PrivetHandlerSetupTest, CheckForUpdates_LongPollIgnoreCommands) {
807 EXPECT_CALL(device_, GetHttpRequestTimeout())
808 .WillOnce(Return(base::TimeDelta::Max()));
809 const char kInput[] = R"({
810 'stateFingerprint': '0'
811 })";
812 EXPECT_PRED2(IsEqualJson, "{}",
813 HandleRequest("/privet/v3/checkForUpdates", kInput));
814 EXPECT_EQ(0, GetResponseCount());
815 cloud_.NotifyOnCommandDefsChanged();
816 EXPECT_EQ(0, GetResponseCount());
817 cloud_.NotifyOnStateChanged();
818 EXPECT_EQ(1, GetResponseCount());
819 const char kExpected[] = R"({
820 'commandsFingerprint': '1',
821 'stateFingerprint': '1'
822 })";
823 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
824}
825
826TEST_F(PrivetHandlerSetupTest, CheckForUpdates_LongPollIgnoreState) {
827 EXPECT_CALL(device_, GetHttpRequestTimeout())
828 .WillOnce(Return(base::TimeDelta::Max()));
829 const char kInput[] = R"({
830 'commandsFingerprint': '0'
831 })";
832 EXPECT_PRED2(IsEqualJson, "{}",
833 HandleRequest("/privet/v3/checkForUpdates", kInput));
834 EXPECT_EQ(0, GetResponseCount());
835 cloud_.NotifyOnStateChanged();
836 EXPECT_EQ(0, GetResponseCount());
837 cloud_.NotifyOnCommandDefsChanged();
838 EXPECT_EQ(1, GetResponseCount());
839 const char kExpected[] = R"({
840 'commandsFingerprint': '1',
841 'stateFingerprint': '1'
842 })";
843 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
844}
845
846TEST_F(PrivetHandlerSetupTest, CheckForUpdates_InstantTimeout) {
847 EXPECT_CALL(device_, GetHttpRequestTimeout())
848 .WillOnce(Return(base::TimeDelta::Max()));
849 const char kInput[] = R"({
850 'commandsFingerprint': '0',
851 'stateFingerprint': '0',
852 'waitTimeout': 0
853 })";
854 const char kExpected[] = R"({
855 'commandsFingerprint': '0',
856 'stateFingerprint': '0'
857 })";
858 EXPECT_PRED2(IsEqualJson, kExpected,
859 HandleRequest("/privet/v3/checkForUpdates", kInput));
860}
861
862TEST_F(PrivetHandlerSetupTest, CheckForUpdates_UserTimeout) {
863 EXPECT_CALL(device_, GetHttpRequestTimeout())
864 .WillOnce(Return(base::TimeDelta::Max()));
865 const char kInput[] = R"({
866 'commandsFingerprint': '0',
867 'stateFingerprint': '0',
868 'waitTimeout': 3
869 })";
870 base::Closure callback;
871 EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(3)))
872 .WillOnce(SaveArg<1>(&callback));
873 EXPECT_PRED2(IsEqualJson, "{}",
874 HandleRequest("/privet/v3/checkForUpdates", kInput));
875 EXPECT_EQ(0, GetResponseCount());
876 callback.Run();
877 EXPECT_EQ(1, GetResponseCount());
878 const char kExpected[] = R"({
879 'commandsFingerprint': '0',
880 'stateFingerprint': '0'
881 })";
882 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
883}
884
885TEST_F(PrivetHandlerSetupTest, CheckForUpdates_ServerTimeout) {
886 EXPECT_CALL(device_, GetHttpRequestTimeout())
887 .WillOnce(Return(base::TimeDelta::FromMinutes(1)));
888 const char kInput[] = R"({
889 'commandsFingerprint': '0',
890 'stateFingerprint': '0'
891 })";
892 base::Closure callback;
893 EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(50)))
894 .WillOnce(SaveArg<1>(&callback));
895 EXPECT_PRED2(IsEqualJson, "{}",
896 HandleRequest("/privet/v3/checkForUpdates", kInput));
897 EXPECT_EQ(0, GetResponseCount());
898 callback.Run();
899 EXPECT_EQ(1, GetResponseCount());
900 const char kExpected[] = R"({
901 'commandsFingerprint': '0',
902 'stateFingerprint': '0'
903 })";
904 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
905}
906
907TEST_F(PrivetHandlerSetupTest, CheckForUpdates_VeryShortServerTimeout) {
908 EXPECT_CALL(device_, GetHttpRequestTimeout())
909 .WillOnce(Return(base::TimeDelta::FromSeconds(5)));
910 const char kInput[] = R"({
911 'commandsFingerprint': '0',
912 'stateFingerprint': '0'
913 })";
914 EXPECT_PRED2(IsEqualJson, kInput,
915 HandleRequest("/privet/v3/checkForUpdates", kInput));
916 EXPECT_EQ(1, GetResponseCount());
917}
918
919TEST_F(PrivetHandlerSetupTest, CheckForUpdates_ServerAndUserTimeout) {
920 EXPECT_CALL(device_, GetHttpRequestTimeout())
921 .WillOnce(Return(base::TimeDelta::FromMinutes(1)));
922 const char kInput[] = R"({
923 'commandsFingerprint': '0',
924 'stateFingerprint': '0',
925 'waitTimeout': 10
926 })";
927 base::Closure callback;
928 EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(10)))
929 .WillOnce(SaveArg<1>(&callback));
930 EXPECT_PRED2(IsEqualJson, "{}",
931 HandleRequest("/privet/v3/checkForUpdates", kInput));
932 EXPECT_EQ(0, GetResponseCount());
933 callback.Run();
934 EXPECT_EQ(1, GetResponseCount());
935 const char kExpected[] = R"({
936 'commandsFingerprint': '0',
937 'stateFingerprint': '0'
938 })";
939 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
940}
941
942TEST_F(PrivetHandlerSetupTest, CheckForUpdates_ChangeBeforeTimeout) {
943 EXPECT_CALL(device_, GetHttpRequestTimeout())
944 .WillOnce(Return(base::TimeDelta::Max()));
945 const char kInput[] = R"({
946 'commandsFingerprint': '0',
947 'stateFingerprint': '0',
948 'waitTimeout': 10
949 })";
950 base::Closure callback;
951 EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(10)))
952 .WillOnce(SaveArg<1>(&callback));
953 EXPECT_PRED2(IsEqualJson, "{}",
954 HandleRequest("/privet/v3/checkForUpdates", kInput));
955 EXPECT_EQ(0, GetResponseCount());
956 cloud_.NotifyOnCommandDefsChanged();
957 EXPECT_EQ(1, GetResponseCount());
958 const char kExpected[] = R"({
959 'commandsFingerprint': '1',
960 'stateFingerprint': '0'
961 })";
962 EXPECT_PRED2(IsEqualJson, kExpected, GetResponse());
963 callback.Run();
964 EXPECT_EQ(1, GetResponseCount());
965}
966
967
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700968} // namespace privet
969} // namespace weave