blob: d430935d50f65d6fab2b1f9dd535e01f11a7692d [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;
Vitaly Bukaf7f52d42015-10-10 22:43:55 -070027using testing::WithArgs;
Vitaly Buka7ce499f2015-06-09 08:04:11 -070028
Vitaly Bukab6f015a2015-07-09 14:59:23 -070029namespace weave {
30namespace privet {
Vitaly Buka7ce499f2015-06-09 08:04:11 -070031
32namespace {
33
34void LoadTestJson(const std::string& test_json,
35 base::DictionaryValue* dictionary) {
36 std::string json = test_json;
37 base::ReplaceChars(json, "'", "\"", &json);
38 int error = 0;
39 std::string message;
Alex Vakulenkoae1ffbc2015-06-15 12:53:22 -070040 std::unique_ptr<base::Value> value(
41 base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC, &error,
42 &message)
43 .release());
Vitaly Buka7ce499f2015-06-09 08:04:11 -070044 EXPECT_TRUE(value.get()) << "\nError: " << message << "\n" << json;
45 base::DictionaryValue* dictionary_ptr = nullptr;
46 if (value->GetAsDictionary(&dictionary_ptr))
47 dictionary->MergeDictionary(dictionary_ptr);
48}
49
50bool IsEqualValue(const base::Value& val1, const base::Value& val2) {
51 return val1.Equals(&val2);
52}
53
54struct CodeWithReason {
55 CodeWithReason(int code_in, const std::string& reason_in)
56 : code(code_in), reason(reason_in) {}
57 int code;
58 std::string reason;
59};
60
61std::ostream& operator<<(std::ostream& stream, const CodeWithReason& error) {
62 return stream << "{" << error.code << ", " << error.reason << "}";
63}
64
65bool IsEqualError(const CodeWithReason& expected,
66 const base::DictionaryValue& dictionary) {
67 std::string reason;
68 int code = 0;
69 return dictionary.GetInteger("error.http_status", &code) &&
70 code == expected.code && dictionary.GetString("error.code", &reason) &&
71 reason == expected.reason;
72}
73
74bool IsEqualDictionary(const base::DictionaryValue& dictionary1,
75 const base::DictionaryValue& dictionary2) {
76 base::DictionaryValue::Iterator it1(dictionary1);
77 base::DictionaryValue::Iterator it2(dictionary2);
78 for (; !it1.IsAtEnd() && !it2.IsAtEnd(); it1.Advance(), it2.Advance()) {
79 // Output mismatched keys.
80 EXPECT_EQ(it1.key(), it2.key());
81 if (it1.key() != it2.key())
82 return false;
83
84 if (it1.key() == "error") {
85 std::string code1;
86 std::string code2;
87 const char kCodeKey[] = "error.code";
88 if (!dictionary1.GetString(kCodeKey, &code1) ||
89 !dictionary2.GetString(kCodeKey, &code2) || code1 != code2) {
90 return false;
91 }
92 continue;
93 }
94
95 const base::DictionaryValue* d1{nullptr};
96 const base::DictionaryValue* d2{nullptr};
97 if (it1.value().GetAsDictionary(&d1) && it2.value().GetAsDictionary(&d2)) {
98 if (!IsEqualDictionary(*d1, *d2))
99 return false;
100 continue;
101 }
102
103 // Output mismatched values.
104 EXPECT_PRED2(IsEqualValue, it1.value(), it2.value());
105 if (!IsEqualValue(it1.value(), it2.value()))
106 return false;
107 }
108
109 return it1.IsAtEnd() && it2.IsAtEnd();
110}
111
112bool IsEqualJson(const std::string& test_json,
113 const base::DictionaryValue& dictionary) {
114 base::DictionaryValue dictionary2;
115 LoadTestJson(test_json, &dictionary2);
116 return IsEqualDictionary(dictionary2, dictionary);
117}
118
119} // namespace
120
121class PrivetHandlerTest : public testing::Test {
122 public:
123 PrivetHandlerTest() {}
124
125 protected:
126 void SetUp() override {
127 auth_header_ = "Privet anonymous";
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700128 handler_.reset(new PrivetHandler(&cloud_, &device_, &security_, &wifi_));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700129 }
130
131 const base::DictionaryValue& HandleRequest(
132 const std::string& api,
133 const base::DictionaryValue* input) {
134 output_.Clear();
135 handler_->HandleRequest(api, auth_header_, input,
136 base::Bind(&PrivetHandlerTest::HandlerCallback,
137 base::Unretained(this)));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700138 return output_;
139 }
140
141 const base::DictionaryValue& HandleRequest(const std::string& api,
142 const std::string& json_input) {
143 base::DictionaryValue dictionary;
144 LoadTestJson(json_input, &dictionary);
145 return HandleRequest(api, &dictionary);
146 }
147
148 void HandleUnknownRequest(const std::string& api) {
149 output_.Clear();
150 base::DictionaryValue dictionary;
151 handler_->HandleRequest(api, auth_header_, &dictionary,
152 base::Bind(&PrivetHandlerTest::HandlerNoFound));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700153 }
154
155 void SetNoWifiAndGcd() {
Johan Euphrosine0b7bb9f2015-09-29 01:11:21 -0700156 handler_.reset(new PrivetHandler(&cloud_, &device_, &security_, nullptr));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700157 EXPECT_CALL(cloud_, GetCloudId()).WillRepeatedly(Return(""));
158 EXPECT_CALL(cloud_, GetConnectionState())
159 .WillRepeatedly(ReturnRef(gcd_disabled_state_));
Vitaly Bukaa647c852015-07-06 14:51:01 -0700160 auto set_error = [](const std::string&, const std::string&,
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700161 ErrorPtr* error) {
162 Error::AddTo(error, FROM_HERE, errors::kDomain, "setupUnavailable", "");
Vitaly Buka075b3d42015-06-09 08:34:25 -0700163 };
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700164 EXPECT_CALL(cloud_, Setup(_, _, _))
165 .WillRepeatedly(DoAll(Invoke(set_error), Return(false)));
166 }
167
168 testing::StrictMock<MockCloudDelegate> cloud_;
169 testing::StrictMock<MockDeviceDelegate> device_;
170 testing::StrictMock<MockSecurityDelegate> security_;
171 testing::StrictMock<MockWifiDelegate> wifi_;
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700172 std::string auth_header_;
173
174 private:
175 void HandlerCallback(int status, const base::DictionaryValue& output) {
176 output_.MergeDictionary(&output);
177 if (!output_.HasKey("error")) {
Vitaly Buka1da65992015-08-06 01:38:57 -0700178 EXPECT_EQ(200, status);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700179 return;
180 }
Vitaly Buka1da65992015-08-06 01:38:57 -0700181 EXPECT_NE(200, status);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700182 output_.SetInteger("error.http_status", status);
183 }
184
185 static void HandlerNoFound(int status, const base::DictionaryValue&) {
Vitaly Buka1da65992015-08-06 01:38:57 -0700186 EXPECT_EQ(404, status);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700187 }
188
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700189 std::unique_ptr<PrivetHandler> handler_;
190 base::DictionaryValue output_;
191 ConnectionState gcd_disabled_state_{ConnectionState::kDisabled};
192};
193
194TEST_F(PrivetHandlerTest, UnknownApi) {
195 HandleUnknownRequest("/privet/foo");
196}
197
198TEST_F(PrivetHandlerTest, InvalidFormat) {
199 auth_header_ = "";
200 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidFormat"),
201 HandleRequest("/privet/info", nullptr));
202}
203
204TEST_F(PrivetHandlerTest, MissingAuth) {
205 auth_header_ = "";
206 EXPECT_PRED2(IsEqualError, CodeWithReason(401, "missingAuthorization"),
207 HandleRequest("/privet/info", "{}"));
208}
209
210TEST_F(PrivetHandlerTest, InvalidAuth) {
211 auth_header_ = "foo";
212 EXPECT_PRED2(IsEqualError, CodeWithReason(401, "invalidAuthorization"),
213 HandleRequest("/privet/info", "{}"));
214}
215
216TEST_F(PrivetHandlerTest, ExpiredAuth) {
217 auth_header_ = "Privet 123";
218 EXPECT_CALL(security_, ParseAccessToken(_, _))
219 .WillRepeatedly(DoAll(SetArgPointee<1>(base::Time()),
220 Return(UserInfo{AuthScope::kOwner, 1})));
221 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "authorizationExpired"),
222 HandleRequest("/privet/info", "{}"));
223}
224
225TEST_F(PrivetHandlerTest, InvalidAuthScope) {
226 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthorizationScope"),
227 HandleRequest("/privet/v3/setup/start", "{}"));
228}
229
230TEST_F(PrivetHandlerTest, InfoMinimal) {
231 SetNoWifiAndGcd();
232 EXPECT_CALL(security_, GetPairingTypes())
233 .WillRepeatedly(Return(std::set<PairingType>{}));
234 EXPECT_CALL(security_, GetCryptoTypes())
235 .WillRepeatedly(Return(std::set<CryptoType>{}));
236
237 const char kExpected[] = R"({
238 'version': '3.0',
239 'id': 'TestId',
240 'name': 'TestDevice',
Vitaly Buka87eb7882015-10-27 22:23:49 -0700241 'services': [ "developmentBoard" ],
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700242 'modelManifestId': "ABMID",
243 'basicModelManifest': {
244 'uiDeviceKind': 'developmentBoard',
245 'oemName': 'Chromium',
246 'modelName': 'Brillo'
247 },
248 'endpoints': {
249 'httpPort': 0,
250 'httpUpdatesPort': 0,
251 'httpsPort': 0,
252 'httpsUpdatesPort': 0
253 },
254 'authentication': {
255 'anonymousMaxScope': 'user',
256 'mode': [
257 'anonymous',
258 'pairing'
259 ],
260 'pairing': [
261 ],
262 'crypto': [
263 ]
264 },
265 'gcd': {
266 'id': '',
267 'status': 'disabled'
268 },
269 'uptime': 3600
270 })";
271 EXPECT_PRED2(IsEqualJson, kExpected, HandleRequest("/privet/info", "{}"));
272}
273
274TEST_F(PrivetHandlerTest, Info) {
275 EXPECT_CALL(cloud_, GetDescription())
276 .WillRepeatedly(Return("TestDescription"));
277 EXPECT_CALL(cloud_, GetLocation()).WillRepeatedly(Return("TestLocation"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700278 EXPECT_CALL(device_, GetHttpEnpoint())
279 .WillRepeatedly(Return(std::make_pair(80, 10080)));
280 EXPECT_CALL(device_, GetHttpsEnpoint())
281 .WillRepeatedly(Return(std::make_pair(443, 10443)));
282 EXPECT_CALL(wifi_, GetHostedSsid())
283 .WillRepeatedly(Return("Test_device.BBABCLAprv"));
284
285 const char kExpected[] = R"({
286 'version': '3.0',
287 'id': 'TestId',
288 'name': 'TestDevice',
289 'description': 'TestDescription',
290 'location': 'TestLocation',
Vitaly Buka87eb7882015-10-27 22:23:49 -0700291 'services': [ "developmentBoard" ],
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700292 'modelManifestId': "ABMID",
293 'basicModelManifest': {
294 'uiDeviceKind': 'developmentBoard',
295 'oemName': 'Chromium',
296 'modelName': 'Brillo'
297 },
298 'endpoints': {
299 'httpPort': 80,
300 'httpUpdatesPort': 10080,
301 'httpsPort': 443,
302 'httpsUpdatesPort': 10443
303 },
304 'authentication': {
305 'anonymousMaxScope': 'none',
306 'mode': [
307 'anonymous',
308 'pairing'
309 ],
310 'pairing': [
311 'pinCode',
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700312 'embeddedCode'
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700313 ],
314 'crypto': [
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700315 'p224_spake2'
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700316 ]
317 },
318 'wifi': {
319 'capabilities': [
320 '2.4GHz'
321 ],
322 'ssid': 'TestSsid',
323 'hostedSsid': 'Test_device.BBABCLAprv',
324 'status': 'offline'
325 },
326 'gcd': {
327 'id': 'TestCloudId',
328 'status': 'online'
329 },
330 'uptime': 3600
331 })";
332 EXPECT_PRED2(IsEqualJson, kExpected, HandleRequest("/privet/info", "{}"));
333}
334
335TEST_F(PrivetHandlerTest, PairingStartInvalidParams) {
336 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
337 HandleRequest("/privet/v3/pairing/start",
338 "{'pairing':'embeddedCode','crypto':'crypto'}"));
339
340 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
341 HandleRequest("/privet/v3/pairing/start",
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700342 "{'pairing':'code','crypto':'p224_spake2'}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700343}
344
345TEST_F(PrivetHandlerTest, PairingStart) {
346 EXPECT_PRED2(
347 IsEqualJson,
348 "{'deviceCommitment': 'testCommitment', 'sessionId': 'testSession'}",
349 HandleRequest("/privet/v3/pairing/start",
Vitaly Bukac8ba2282015-10-01 17:42:40 -0700350 "{'pairing': 'embeddedCode', 'crypto': 'p224_spake2'}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700351}
352
353TEST_F(PrivetHandlerTest, PairingConfirm) {
354 EXPECT_PRED2(
355 IsEqualJson,
356 "{'certFingerprint':'testFingerprint','certSignature':'testSignature'}",
357 HandleRequest(
358 "/privet/v3/pairing/confirm",
359 "{'sessionId':'testSession','clientCommitment':'testCommitment'}"));
360}
361
362TEST_F(PrivetHandlerTest, PairingCancel) {
363 EXPECT_PRED2(IsEqualJson, "{}",
364 HandleRequest("/privet/v3/pairing/cancel",
365 "{'sessionId': 'testSession'}"));
366}
367
368TEST_F(PrivetHandlerTest, AuthErrorNoType) {
369 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidAuthMode"),
370 HandleRequest("/privet/v3/auth", "{}"));
371}
372
373TEST_F(PrivetHandlerTest, AuthErrorInvalidType) {
374 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidAuthMode"),
375 HandleRequest("/privet/v3/auth", "{'mode':'unknown'}"));
376}
377
378TEST_F(PrivetHandlerTest, AuthErrorNoScope) {
379 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidRequestedScope"),
380 HandleRequest("/privet/v3/auth", "{'mode':'anonymous'}"));
381}
382
383TEST_F(PrivetHandlerTest, AuthErrorInvalidScope) {
384 EXPECT_PRED2(
385 IsEqualError, CodeWithReason(400, "invalidRequestedScope"),
386 HandleRequest("/privet/v3/auth",
387 "{'mode':'anonymous','requestedScope':'unknown'}"));
388}
389
390TEST_F(PrivetHandlerTest, AuthErrorAccessDenied) {
391 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "accessDenied"),
392 HandleRequest("/privet/v3/auth",
393 "{'mode':'anonymous','requestedScope':'owner'}"));
394}
395
396TEST_F(PrivetHandlerTest, AuthErrorInvalidAuthCode) {
397 EXPECT_CALL(security_, IsValidPairingCode("testToken"))
398 .WillRepeatedly(Return(false));
399 const char kInput[] = R"({
400 'mode': 'pairing',
401 'requestedScope': 'user',
402 'authCode': 'testToken'
403 })";
404 EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthCode"),
405 HandleRequest("/privet/v3/auth", kInput));
406}
407
408TEST_F(PrivetHandlerTest, AuthAnonymous) {
409 const char kExpected[] = R"({
410 'accessToken': 'GuestAccessToken',
411 'expiresIn': 3600,
412 'scope': 'user',
413 'tokenType': 'Privet'
414 })";
415 EXPECT_PRED2(IsEqualJson, kExpected,
416 HandleRequest("/privet/v3/auth",
417 "{'mode':'anonymous','requestedScope':'auto'}"));
418}
419
420TEST_F(PrivetHandlerTest, AuthPairing) {
421 EXPECT_CALL(security_, IsValidPairingCode("testToken"))
422 .WillRepeatedly(Return(true));
423 EXPECT_CALL(security_, CreateAccessToken(_, _))
424 .WillRepeatedly(Return("OwnerAccessToken"));
425 const char kInput[] = R"({
426 'mode': 'pairing',
427 'requestedScope': 'owner',
428 'authCode': 'testToken'
429 })";
430 const char kExpected[] = R"({
431 'accessToken': 'OwnerAccessToken',
432 'expiresIn': 3600,
433 'scope': 'owner',
434 'tokenType': 'Privet'
435 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700436 EXPECT_PRED2(IsEqualJson, kExpected,
437 HandleRequest("/privet/v3/auth", kInput));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700438}
439
440class PrivetHandlerSetupTest : public PrivetHandlerTest {
441 public:
442 void SetUp() override {
443 PrivetHandlerTest::SetUp();
444 auth_header_ = "Privet 123";
445 EXPECT_CALL(security_, ParseAccessToken(_, _))
446 .WillRepeatedly(DoAll(SetArgPointee<1>(base::Time::Now()),
447 Return(UserInfo{AuthScope::kOwner, 1})));
448 }
449};
450
451TEST_F(PrivetHandlerSetupTest, StatusEmpty) {
452 SetNoWifiAndGcd();
Vitaly Buka075b3d42015-06-09 08:34:25 -0700453 EXPECT_PRED2(IsEqualJson, "{}",
454 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700455}
456
457TEST_F(PrivetHandlerSetupTest, StatusWifi) {
458 wifi_.setup_state_ = SetupState{SetupState::kSuccess};
459
460 const char kExpected[] = R"({
461 'wifi': {
462 'ssid': 'TestSsid',
463 'status': 'success'
464 }
465 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700466 EXPECT_PRED2(IsEqualJson, kExpected,
467 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700468}
469
470TEST_F(PrivetHandlerSetupTest, StatusWifiError) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700471 ErrorPtr error;
472 Error::AddTo(&error, FROM_HERE, "test", "invalidPassphrase", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700473 wifi_.setup_state_ = SetupState{std::move(error)};
474
475 const char kExpected[] = R"({
476 'wifi': {
477 'status': 'error',
478 'error': {
479 'code': 'invalidPassphrase'
480 }
481 }
482 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700483 EXPECT_PRED2(IsEqualJson, kExpected,
484 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700485}
486
487TEST_F(PrivetHandlerSetupTest, StatusGcd) {
488 cloud_.setup_state_ = SetupState{SetupState::kSuccess};
489
490 const char kExpected[] = R"({
491 'gcd': {
492 'id': 'TestCloudId',
493 'status': 'success'
494 }
495 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700496 EXPECT_PRED2(IsEqualJson, kExpected,
497 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700498}
499
500TEST_F(PrivetHandlerSetupTest, StatusGcdError) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700501 ErrorPtr error;
502 Error::AddTo(&error, FROM_HERE, "test", "invalidTicket", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700503 cloud_.setup_state_ = SetupState{std::move(error)};
504
505 const char kExpected[] = R"({
506 'gcd': {
507 'status': 'error',
508 'error': {
509 'code': 'invalidTicket'
510 }
511 }
512 })";
Vitaly Buka075b3d42015-06-09 08:34:25 -0700513 EXPECT_PRED2(IsEqualJson, kExpected,
514 HandleRequest("/privet/v3/setup/status", "{}"));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700515}
516
517TEST_F(PrivetHandlerSetupTest, SetupNameDescriptionLocation) {
Vitaly Bukab624bc42015-09-29 19:13:55 -0700518 EXPECT_CALL(cloud_,
519 UpdateDeviceInfo("testName", "testDescription", "testLocation"))
Vitaly Bukaa647c852015-07-06 14:51:01 -0700520 .Times(1);
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700521 const char kInput[] = R"({
522 'name': 'testName',
523 'description': 'testDescription',
524 'location': 'testLocation'
525 })";
526 EXPECT_PRED2(IsEqualJson, "{}",
527 HandleRequest("/privet/v3/setup/start", kInput));
528}
529
530TEST_F(PrivetHandlerSetupTest, InvalidParams) {
531 const char kInputWifi[] = R"({
532 'wifi': {
533 'ssid': ''
534 }
535 })";
536 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
537 HandleRequest("/privet/v3/setup/start", kInputWifi));
538
539 const char kInputRegistration[] = R"({
540 'gcd': {
541 'ticketId': ''
542 }
543 })";
544 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"),
545 HandleRequest("/privet/v3/setup/start", kInputRegistration));
546}
547
548TEST_F(PrivetHandlerSetupTest, WifiSetupUnavailable) {
549 SetNoWifiAndGcd();
550 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "setupUnavailable"),
551 HandleRequest("/privet/v3/setup/start", "{'wifi': {}}"));
552}
553
554TEST_F(PrivetHandlerSetupTest, WifiSetup) {
555 const char kInput[] = R"({
556 'wifi': {
557 'ssid': 'testSsid',
558 'passphrase': 'testPass'
559 }
560 })";
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700561 auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) {
562 Error::AddTo(error, FROM_HERE, errors::kDomain, "deviceBusy", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700563 };
564 EXPECT_CALL(wifi_, ConfigureCredentials(_, _, _))
565 .WillOnce(DoAll(Invoke(set_error), Return(false)));
566 EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"),
567 HandleRequest("/privet/v3/setup/start", kInput));
568
569 const char kExpected[] = R"({
570 'wifi': {
571 'status': 'inProgress'
572 }
573 })";
574 wifi_.setup_state_ = SetupState{SetupState::kInProgress};
575 EXPECT_CALL(wifi_, ConfigureCredentials("testSsid", "testPass", _))
576 .WillOnce(Return(true));
577 EXPECT_PRED2(IsEqualJson, kExpected,
578 HandleRequest("/privet/v3/setup/start", kInput));
579}
580
581TEST_F(PrivetHandlerSetupTest, GcdSetupUnavailable) {
582 SetNoWifiAndGcd();
583 const char kInput[] = R"({
584 'gcd': {
585 'ticketId': 'testTicket',
586 'user': 'testUser'
587 }
588 })";
589
590 EXPECT_PRED2(IsEqualError, CodeWithReason(400, "setupUnavailable"),
591 HandleRequest("/privet/v3/setup/start", kInput));
592}
593
594TEST_F(PrivetHandlerSetupTest, GcdSetup) {
595 const char kInput[] = R"({
596 'gcd': {
597 'ticketId': 'testTicket',
598 'user': 'testUser'
599 }
600 })";
601
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700602 auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) {
603 Error::AddTo(error, FROM_HERE, errors::kDomain, "deviceBusy", "");
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700604 };
605 EXPECT_CALL(cloud_, Setup(_, _, _))
606 .WillOnce(DoAll(Invoke(set_error), Return(false)));
607 EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"),
608 HandleRequest("/privet/v3/setup/start", kInput));
609
610 const char kExpected[] = R"({
611 'gcd': {
612 'status': 'inProgress'
613 }
614 })";
615 cloud_.setup_state_ = SetupState{SetupState::kInProgress};
616 EXPECT_CALL(cloud_, Setup("testTicket", "testUser", _))
617 .WillOnce(Return(true));
618 EXPECT_PRED2(IsEqualJson, kExpected,
619 HandleRequest("/privet/v3/setup/start", kInput));
620}
621
622TEST_F(PrivetHandlerSetupTest, State) {
623 EXPECT_PRED2(IsEqualJson, "{'state': {'test': {}}, 'fingerprint': '0'}",
624 HandleRequest("/privet/v3/state", "{}"));
625
626 cloud_.NotifyOnStateChanged();
627
628 EXPECT_PRED2(IsEqualJson, "{'state': {'test': {}}, 'fingerprint': '1'}",
629 HandleRequest("/privet/v3/state", "{}"));
630}
631
632TEST_F(PrivetHandlerSetupTest, CommandsDefs) {
633 EXPECT_PRED2(IsEqualJson, "{'commands': {'test':{}}, 'fingerprint': '0'}",
634 HandleRequest("/privet/v3/commandDefs", "{}"));
635
636 cloud_.NotifyOnCommandDefsChanged();
637
638 EXPECT_PRED2(IsEqualJson, "{'commands': {'test':{}}, 'fingerprint': '1'}",
639 HandleRequest("/privet/v3/commandDefs", "{}"));
640}
641
642TEST_F(PrivetHandlerSetupTest, CommandsExecute) {
643 const char kInput[] = "{'name': 'test'}";
644 base::DictionaryValue command;
645 LoadTestJson(kInput, &command);
646 LoadTestJson("{'id':'5'}", &command);
Vitaly Buka74763422015-10-11 00:39:52 -0700647 EXPECT_CALL(cloud_, AddCommand(_, _, _))
648 .WillOnce(WithArgs<2>(Invoke(
649 [&command](const CloudDelegate::CommandDoneCallback& callback) {
650 callback.Run(command, nullptr);
651 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700652
653 EXPECT_PRED2(IsEqualJson, "{'name':'test', 'id':'5'}",
654 HandleRequest("/privet/v3/commands/execute", kInput));
655}
656
657TEST_F(PrivetHandlerSetupTest, CommandsStatus) {
658 const char kInput[] = "{'id': '5'}";
659 base::DictionaryValue command;
660 LoadTestJson(kInput, &command);
661 LoadTestJson("{'name':'test'}", &command);
Vitaly Buka74763422015-10-11 00:39:52 -0700662 EXPECT_CALL(cloud_, GetCommand(_, _, _))
663 .WillOnce(WithArgs<2>(Invoke(
664 [&command](const CloudDelegate::CommandDoneCallback& callback) {
665 callback.Run(command, nullptr);
666 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700667
668 EXPECT_PRED2(IsEqualJson, "{'name':'test', 'id':'5'}",
669 HandleRequest("/privet/v3/commands/status", kInput));
670
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700671 ErrorPtr error;
672 Error::AddTo(&error, FROM_HERE, errors::kDomain, "notFound", "");
Vitaly Buka74763422015-10-11 00:39:52 -0700673 EXPECT_CALL(cloud_, GetCommand(_, _, _))
674 .WillOnce(WithArgs<2>(
675 Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) {
676 callback.Run({}, std::move(error));
677 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700678
679 EXPECT_PRED2(IsEqualError, CodeWithReason(404, "notFound"),
680 HandleRequest("/privet/v3/commands/status", "{'id': '15'}"));
681}
682
683TEST_F(PrivetHandlerSetupTest, CommandsCancel) {
684 const char kExpected[] = "{'id': '5', 'name':'test', 'state':'cancelled'}";
685 base::DictionaryValue command;
686 LoadTestJson(kExpected, &command);
Vitaly Buka74763422015-10-11 00:39:52 -0700687 EXPECT_CALL(cloud_, CancelCommand(_, _, _))
688 .WillOnce(WithArgs<2>(Invoke(
689 [&command](const CloudDelegate::CommandDoneCallback& callback) {
690 callback.Run(command, nullptr);
691 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700692
693 EXPECT_PRED2(IsEqualJson, kExpected,
694 HandleRequest("/privet/v3/commands/cancel", "{'id': '8'}"));
695
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700696 ErrorPtr error;
697 Error::AddTo(&error, FROM_HERE, errors::kDomain, "notFound", "");
Vitaly Buka74763422015-10-11 00:39:52 -0700698 EXPECT_CALL(cloud_, CancelCommand(_, _, _))
699 .WillOnce(WithArgs<2>(
700 Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) {
701 callback.Run({}, std::move(error));
702 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700703
704 EXPECT_PRED2(IsEqualError, CodeWithReason(404, "notFound"),
705 HandleRequest("/privet/v3/commands/cancel", "{'id': '11'}"));
706}
707
708TEST_F(PrivetHandlerSetupTest, CommandsList) {
709 const char kExpected[] = R"({
710 'commands' : [
711 {'id':'5', 'state':'cancelled'},
712 {'id':'15', 'state':'inProgress'}
713 ]})";
714
715 base::DictionaryValue commands;
716 LoadTestJson(kExpected, &commands);
717
Vitaly Buka74763422015-10-11 00:39:52 -0700718 EXPECT_CALL(cloud_, ListCommands(_, _))
719 .WillOnce(WithArgs<1>(Invoke(
720 [&commands](const CloudDelegate::CommandDoneCallback& callback) {
721 callback.Run(commands, nullptr);
722 })));
Vitaly Buka7ce499f2015-06-09 08:04:11 -0700723
724 EXPECT_PRED2(IsEqualJson, kExpected,
725 HandleRequest("/privet/v3/commands/list", "{}"));
726}
727
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700728} // namespace privet
729} // namespace weave