| // Copyright 2015 The Weave 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 "src/privet/privet_handler.h" |
| |
| #include <set> |
| #include <string> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/json/json_reader.h> |
| #include <base/json/json_writer.h> |
| #include <base/strings/string_util.h> |
| #include <base/values.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <weave/test/unittest_utils.h> |
| |
| #include "src/privet/constants.h" |
| #include "src/privet/mock_delegates.h" |
| #include "src/test/mock_clock.h" |
| |
| using testing::_; |
| using testing::DoAll; |
| using testing::Invoke; |
| using testing::Return; |
| using testing::SetArgPointee; |
| using testing::SaveArg; |
| using testing::WithArgs; |
| |
| namespace weave { |
| namespace privet { |
| |
| namespace { |
| |
| void LoadTestJson(const std::string& test_json, |
| base::DictionaryValue* dictionary) { |
| std::string json = test_json; |
| base::ReplaceChars(json, "'", "\"", &json); |
| int error = 0; |
| std::string message; |
| std::unique_ptr<base::Value> value( |
| base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC, &error, |
| &message) |
| .release()); |
| EXPECT_TRUE(value.get()) << "\nError: " << message << "\n" << json; |
| base::DictionaryValue* dictionary_ptr = nullptr; |
| if (value->GetAsDictionary(&dictionary_ptr)) |
| dictionary->MergeDictionary(dictionary_ptr); |
| } |
| |
| struct CodeWithReason { |
| CodeWithReason(int code_in, const std::string& reason_in) |
| : code(code_in), reason(reason_in) {} |
| int code; |
| std::string reason; |
| }; |
| |
| std::ostream& operator<<(std::ostream& stream, const CodeWithReason& error) { |
| return stream << "{" << error.code << ", " << error.reason << "}"; |
| } |
| |
| bool IsEqualError(const CodeWithReason& expected, |
| const base::DictionaryValue& dictionary) { |
| std::string reason; |
| int code = 0; |
| return dictionary.GetInteger("error.http_status", &code) && |
| code == expected.code && dictionary.GetString("error.code", &reason) && |
| reason == expected.reason; |
| } |
| |
| // Some error sections in response JSON objects contained debugging information |
| // which is of no interest for this test. So, remove the debug info from the |
| // JSON before running validation logic on it. |
| std::unique_ptr<base::DictionaryValue> StripDebugErrorDetails( |
| const std::string& path_to_error_object, |
| const base::DictionaryValue& value) { |
| std::unique_ptr<base::DictionaryValue> result{value.DeepCopy()}; |
| base::DictionaryValue* error_dict = nullptr; |
| EXPECT_TRUE(result->GetDictionary(path_to_error_object, &error_dict)); |
| scoped_ptr<base::Value> dummy; |
| error_dict->RemovePath("error.debugInfo", &dummy); |
| error_dict->RemovePath("error.message", &dummy); |
| return result; |
| } |
| |
| } // namespace |
| |
| class PrivetHandlerTest : public testing::Test { |
| public: |
| PrivetHandlerTest() {} |
| |
| protected: |
| void SetUp() override { |
| EXPECT_CALL(clock_, Now()) |
| .WillRepeatedly(Return(base::Time::FromTimeT(1410000001))); |
| |
| auth_header_ = "Privet anonymous"; |
| handler_.reset( |
| new PrivetHandler(&cloud_, &device_, &security_, &wifi_, &clock_)); |
| } |
| |
| const base::DictionaryValue& HandleRequest( |
| const std::string& api, |
| const base::DictionaryValue* input) { |
| output_.Clear(); |
| handler_->HandleRequest(api, auth_header_, input, |
| base::Bind(&PrivetHandlerTest::HandlerCallback, |
| base::Unretained(this))); |
| return output_; |
| } |
| |
| const base::DictionaryValue& HandleRequest(const std::string& api, |
| const std::string& json_input) { |
| base::DictionaryValue dictionary; |
| LoadTestJson(json_input, &dictionary); |
| return HandleRequest(api, &dictionary); |
| } |
| |
| void HandleUnknownRequest(const std::string& api) { |
| output_.Clear(); |
| base::DictionaryValue dictionary; |
| handler_->HandleRequest(api, auth_header_, &dictionary, |
| base::Bind(&PrivetHandlerTest::HandlerNoFound)); |
| } |
| |
| const base::DictionaryValue& GetResponse() const { return output_; } |
| int GetResponseCount() const { return response_count_; } |
| |
| void SetNoWifiAndGcd() { |
| handler_.reset( |
| new PrivetHandler(&cloud_, &device_, &security_, nullptr, &clock_)); |
| EXPECT_CALL(cloud_, GetCloudId()).WillRepeatedly(Return("")); |
| EXPECT_CALL(cloud_, GetConnectionState()) |
| .WillRepeatedly(ReturnRef(gcd_disabled_state_)); |
| auto set_error = [](const std::string&, const std::string&, |
| ErrorPtr* error) { |
| Error::AddTo(error, FROM_HERE, "setupUnavailable", ""); |
| }; |
| EXPECT_CALL(cloud_, Setup(_, _, _)) |
| .WillRepeatedly(DoAll(Invoke(set_error), Return(false))); |
| } |
| |
| test::MockClock clock_; |
| testing::StrictMock<MockCloudDelegate> cloud_; |
| testing::StrictMock<MockDeviceDelegate> device_; |
| testing::StrictMock<MockSecurityDelegate> security_; |
| testing::StrictMock<MockWifiDelegate> wifi_; |
| std::string auth_header_; |
| |
| private: |
| void HandlerCallback(int status, const base::DictionaryValue& output) { |
| output_.Clear(); |
| ++response_count_; |
| output_.MergeDictionary(&output); |
| if (!output_.HasKey("error")) { |
| EXPECT_EQ(200, status); |
| return; |
| } |
| EXPECT_NE(200, status); |
| output_.SetInteger("error.http_status", status); |
| } |
| |
| static void HandlerNoFound(int status, const base::DictionaryValue&) { |
| EXPECT_EQ(404, status); |
| } |
| |
| std::unique_ptr<PrivetHandler> handler_; |
| base::DictionaryValue output_; |
| int response_count_{0}; |
| ConnectionState gcd_disabled_state_{ConnectionState::kDisabled}; |
| }; |
| |
| TEST_F(PrivetHandlerTest, UnknownApi) { |
| HandleUnknownRequest("/privet/foo"); |
| } |
| |
| TEST_F(PrivetHandlerTest, InvalidFormat) { |
| auth_header_ = ""; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidFormat"), |
| HandleRequest("/privet/info", nullptr)); |
| } |
| |
| TEST_F(PrivetHandlerTest, MissingAuth) { |
| auth_header_ = ""; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(401, "missingAuthorization"), |
| HandleRequest("/privet/info", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, InvalidAuth) { |
| auth_header_ = "foo"; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(401, "invalidAuthorization"), |
| HandleRequest("/privet/info", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, ExpiredAuth) { |
| auth_header_ = "Privet 123"; |
| EXPECT_CALL(security_, ParseAccessToken(_, _, _)) |
| .WillRepeatedly(WithArgs<2>(Invoke([](ErrorPtr* error) { |
| return Error::AddTo(error, FROM_HERE, "authorizationExpired", ""); |
| }))); |
| EXPECT_PRED2(IsEqualError, CodeWithReason(403, "authorizationExpired"), |
| HandleRequest("/privet/info", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, InvalidAuthScope) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthorizationScope"), |
| HandleRequest("/privet/v3/setup/start", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, InfoMinimal) { |
| SetNoWifiAndGcd(); |
| EXPECT_CALL(security_, GetPairingTypes()) |
| .WillRepeatedly(Return(std::set<PairingType>{})); |
| EXPECT_CALL(security_, GetCryptoTypes()) |
| .WillRepeatedly(Return(std::set<CryptoType>{})); |
| EXPECT_CALL(security_, GetAuthTypes()) |
| .WillRepeatedly(Return(std::set<AuthType>{})); |
| |
| const char kExpected[] = R"({ |
| 'version': '3.0', |
| 'id': 'TestId', |
| 'name': 'TestDevice', |
| 'services': [ "developmentBoard" ], |
| 'modelManifestId': "ABMID", |
| 'basicModelManifest': { |
| 'uiDeviceKind': 'developmentBoard', |
| 'oemName': 'Chromium', |
| 'modelName': 'Brillo' |
| }, |
| 'endpoints': { |
| 'httpPort': 0, |
| 'httpUpdatesPort': 0, |
| 'httpsPort': 0, |
| 'httpsUpdatesPort': 0 |
| }, |
| 'authentication': { |
| 'anonymousMaxScope': 'user', |
| 'mode': [ |
| ], |
| 'pairing': [ |
| ], |
| 'crypto': [ |
| ] |
| }, |
| 'gcd': { |
| 'id': '', |
| 'status': 'disabled' |
| }, |
| 'time': 1410000001000.0, |
| 'sessionId': 'SessionId' |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/info", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, Info) { |
| EXPECT_CALL(cloud_, GetDescription()) |
| .WillRepeatedly(Return("TestDescription")); |
| EXPECT_CALL(cloud_, GetLocation()).WillRepeatedly(Return("TestLocation")); |
| EXPECT_CALL(device_, GetHttpEnpoint()) |
| .WillRepeatedly(Return(std::make_pair(80, 10080))); |
| EXPECT_CALL(device_, GetHttpsEnpoint()) |
| .WillRepeatedly(Return(std::make_pair(443, 10443))); |
| EXPECT_CALL(wifi_, GetHostedSsid()) |
| .WillRepeatedly(Return("Test_device.BBABCLAprv")); |
| |
| const char kExpected[] = R"({ |
| 'version': '3.0', |
| 'id': 'TestId', |
| 'name': 'TestDevice', |
| 'description': 'TestDescription', |
| 'location': 'TestLocation', |
| 'services': [ "developmentBoard" ], |
| 'modelManifestId': "ABMID", |
| 'basicModelManifest': { |
| 'uiDeviceKind': 'developmentBoard', |
| 'oemName': 'Chromium', |
| 'modelName': 'Brillo' |
| }, |
| 'endpoints': { |
| 'httpPort': 80, |
| 'httpUpdatesPort': 10080, |
| 'httpsPort': 443, |
| 'httpsUpdatesPort': 10443 |
| }, |
| 'authentication': { |
| 'anonymousMaxScope': 'none', |
| 'mode': [ |
| 'anonymous', |
| 'pairing', |
| 'local' |
| ], |
| 'pairing': [ |
| 'pinCode', |
| 'embeddedCode' |
| ], |
| 'crypto': [ |
| 'p224_spake2' |
| ] |
| }, |
| 'wifi': { |
| 'capabilities': [ |
| '2.4GHz' |
| ], |
| 'ssid': 'TestSsid', |
| 'hostedSsid': 'Test_device.BBABCLAprv', |
| 'status': 'offline' |
| }, |
| 'gcd': { |
| 'id': 'TestCloudId', |
| 'status': 'online' |
| }, |
| 'time': 1410000001000.0, |
| 'sessionId': 'SessionId' |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/info", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingStartInvalidParams) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"), |
| HandleRequest("/privet/v3/pairing/start", |
| "{'pairing':'embeddedCode','crypto':'crypto'}")); |
| |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"), |
| HandleRequest("/privet/v3/pairing/start", |
| "{'pairing':'code','crypto':'p224_spake2'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingStart) { |
| EXPECT_JSON_EQ( |
| "{'deviceCommitment': 'testCommitment', 'sessionId': 'testSession'}", |
| HandleRequest("/privet/v3/pairing/start", |
| "{'pairing': 'embeddedCode', 'crypto': 'p224_spake2'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingConfirm) { |
| EXPECT_JSON_EQ( |
| "{'certFingerprint':'testFingerprint','certSignature':'testSignature'}", |
| HandleRequest( |
| "/privet/v3/pairing/confirm", |
| "{'sessionId':'testSession','clientCommitment':'testCommitment'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingCancel) { |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/pairing/cancel", |
| "{'sessionId': 'testSession'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorNoType) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidAuthMode"), |
| HandleRequest("/privet/v3/auth", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorInvalidType) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidAuthMode"), |
| HandleRequest("/privet/v3/auth", "{'mode':'unknown'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorNoScope) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidRequestedScope"), |
| HandleRequest("/privet/v3/auth", "{'mode':'anonymous'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorInvalidScope) { |
| EXPECT_PRED2( |
| IsEqualError, CodeWithReason(400, "invalidRequestedScope"), |
| HandleRequest("/privet/v3/auth", |
| "{'mode':'anonymous','requestedScope':'unknown'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorAccessDenied) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(403, "accessDenied"), |
| HandleRequest("/privet/v3/auth", |
| "{'mode':'anonymous','requestedScope':'owner'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorInvalidAuthCode) { |
| auto set_error = [](ErrorPtr* error) { |
| return Error::AddTo(error, FROM_HERE, "invalidAuthCode", ""); |
| }; |
| EXPECT_CALL(security_, CreateAccessToken(_, "testToken", _, _, _, _, _)) |
| .WillRepeatedly(WithArgs<6>(Invoke(set_error))); |
| const char kInput[] = R"({ |
| 'mode': 'pairing', |
| 'requestedScope': 'user', |
| 'authCode': 'testToken' |
| })"; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthCode"), |
| HandleRequest("/privet/v3/auth", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthAnonymous) { |
| const char kExpected[] = R"({ |
| 'accessToken': 'GuestAccessToken', |
| 'expiresIn': 15, |
| 'scope': 'viewer', |
| 'tokenType': 'Privet' |
| })"; |
| EXPECT_JSON_EQ(kExpected, |
| HandleRequest("/privet/v3/auth", |
| "{'mode':'anonymous','requestedScope':'auto'}")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthPairing) { |
| EXPECT_CALL(security_, CreateAccessToken(_, _, _, _, _, _, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<3>("OwnerAccessToken"), |
| SetArgPointee<4>(AuthScope::kOwner), |
| SetArgPointee<5>(base::TimeDelta::FromSeconds(15)), |
| Return(true))); |
| const char kInput[] = R"({ |
| 'mode': 'pairing', |
| 'requestedScope': 'owner', |
| 'authCode': 'testToken' |
| })"; |
| const char kExpected[] = R"({ |
| 'accessToken': 'OwnerAccessToken', |
| 'expiresIn': 15, |
| 'scope': 'owner', |
| 'tokenType': 'Privet' |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/auth", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthLocalAuto) { |
| EXPECT_CALL(security_, CreateAccessToken(_, _, _, _, _, _, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<3>("UserAccessToken"), |
| SetArgPointee<4>(AuthScope::kUser), |
| SetArgPointee<5>(base::TimeDelta::FromSeconds(15)), |
| Return(true))); |
| const char kInput[] = R"({ |
| 'mode': 'local', |
| 'requestedScope': 'auto', |
| 'authCode': 'localAuthToken' |
| })"; |
| const char kExpected[] = R"({ |
| 'accessToken': 'UserAccessToken', |
| 'expiresIn': 15, |
| 'scope': 'user', |
| 'tokenType': 'Privet' |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/auth", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthLocal) { |
| EXPECT_CALL(security_, CreateAccessToken(_, _, _, _, _, _, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<3>("ManagerAccessToken"), |
| SetArgPointee<4>(AuthScope::kManager), |
| SetArgPointee<5>(base::TimeDelta::FromSeconds(15)), |
| Return(true))); |
| const char kInput[] = R"({ |
| 'mode': 'local', |
| 'requestedScope': 'manager', |
| 'authCode': 'localAuthToken' |
| })"; |
| const char kExpected[] = R"({ |
| 'accessToken': 'ManagerAccessToken', |
| 'expiresIn': 15, |
| 'scope': 'manager', |
| 'tokenType': 'Privet' |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/auth", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthLocalHighScope) { |
| EXPECT_CALL(security_, CreateAccessToken(_, _, _, _, _, _, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<3>("UserAccessToken"), |
| SetArgPointee<4>(AuthScope::kUser), |
| SetArgPointee<5>(base::TimeDelta::FromSeconds(1)), |
| Return(true))); |
| const char kInput[] = R"({ |
| 'mode': 'local', |
| 'requestedScope': 'manager', |
| 'authCode': 'localAuthToken' |
| })"; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(403, "accessDenied"), |
| HandleRequest("/privet/v3/auth", kInput)); |
| } |
| |
| class PrivetHandlerTestWithAuth : public PrivetHandlerTest { |
| public: |
| void SetUp() override { |
| PrivetHandlerTest::SetUp(); |
| auth_header_ = "Privet 123"; |
| EXPECT_CALL(security_, ParseAccessToken(_, _, _)) |
| .WillRepeatedly(DoAll( |
| SetArgPointee<1>(UserInfo{AuthScope::kOwner, TestUserId{"1"}}), |
| Return(true))); |
| } |
| }; |
| |
| class PrivetHandlerSetupTest : public PrivetHandlerTestWithAuth {}; |
| |
| TEST_F(PrivetHandlerSetupTest, StatusEmpty) { |
| SetNoWifiAndGcd(); |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/setup/status", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, StatusWifi) { |
| wifi_.setup_state_ = SetupState{SetupState::kSuccess}; |
| |
| const char kExpected[] = R"({ |
| 'wifi': { |
| 'ssid': 'TestSsid', |
| 'status': 'success' |
| } |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/setup/status", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, StatusWifiError) { |
| ErrorPtr error; |
| Error::AddTo(&error, FROM_HERE, "invalidPassphrase", ""); |
| wifi_.setup_state_ = SetupState{std::move(error)}; |
| |
| const char kExpected[] = R"({ |
| 'wifi': { |
| 'status': 'error', |
| 'error': { |
| 'code': 'invalidPassphrase' |
| } |
| } |
| })"; |
| EXPECT_JSON_EQ(kExpected, |
| *StripDebugErrorDetails( |
| "wifi", HandleRequest("/privet/v3/setup/status", "{}"))); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, StatusGcd) { |
| cloud_.setup_state_ = SetupState{SetupState::kSuccess}; |
| |
| const char kExpected[] = R"({ |
| 'gcd': { |
| 'id': 'TestCloudId', |
| 'status': 'success' |
| } |
| })"; |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/setup/status", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, StatusGcdError) { |
| ErrorPtr error; |
| Error::AddTo(&error, FROM_HERE, "invalidTicket", ""); |
| cloud_.setup_state_ = SetupState{std::move(error)}; |
| |
| const char kExpected[] = R"({ |
| 'gcd': { |
| 'status': 'error', |
| 'error': { |
| 'code': 'invalidTicket' |
| } |
| } |
| })"; |
| EXPECT_JSON_EQ(kExpected, |
| *StripDebugErrorDetails( |
| "gcd", HandleRequest("/privet/v3/setup/status", "{}"))); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, SetupNameDescriptionLocation) { |
| EXPECT_CALL(cloud_, |
| UpdateDeviceInfo("testName", "testDescription", "testLocation")) |
| .Times(1); |
| const char kInput[] = R"({ |
| 'name': 'testName', |
| 'description': 'testDescription', |
| 'location': 'testLocation' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/setup/start", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, InvalidParams) { |
| const char kInputWifi[] = R"({ |
| 'wifi': { |
| 'ssid': '' |
| } |
| })"; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"), |
| HandleRequest("/privet/v3/setup/start", kInputWifi)); |
| |
| const char kInputRegistration[] = R"({ |
| 'gcd': { |
| 'ticketId': '' |
| } |
| })"; |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"), |
| HandleRequest("/privet/v3/setup/start", kInputRegistration)); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, WifiSetupUnavailable) { |
| SetNoWifiAndGcd(); |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "setupUnavailable"), |
| HandleRequest("/privet/v3/setup/start", "{'wifi': {}}")); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, WifiSetup) { |
| const char kInput[] = R"({ |
| 'wifi': { |
| 'ssid': 'testSsid', |
| 'passphrase': 'testPass' |
| } |
| })"; |
| auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) { |
| return Error::AddTo(error, FROM_HERE, "deviceBusy", ""); |
| }; |
| EXPECT_CALL(wifi_, ConfigureCredentials(_, _, _)).WillOnce(Invoke(set_error)); |
| EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"), |
| HandleRequest("/privet/v3/setup/start", kInput)); |
| |
| const char kExpected[] = R"({ |
| 'wifi': { |
| 'status': 'inProgress' |
| } |
| })"; |
| wifi_.setup_state_ = SetupState{SetupState::kInProgress}; |
| EXPECT_CALL(wifi_, ConfigureCredentials("testSsid", "testPass", _)) |
| .WillOnce(Return(true)); |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/setup/start", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, GcdSetupUnavailable) { |
| SetNoWifiAndGcd(); |
| const char kInput[] = R"({ |
| 'gcd': { |
| 'ticketId': 'testTicket', |
| 'user': 'testUser' |
| } |
| })"; |
| |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "setupUnavailable"), |
| HandleRequest("/privet/v3/setup/start", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, GcdSetup) { |
| const char kInput[] = R"({ |
| 'gcd': { |
| 'ticketId': 'testTicket', |
| 'user': 'testUser' |
| } |
| })"; |
| |
| auto set_error = [](const std::string&, const std::string&, ErrorPtr* error) { |
| return Error::AddTo(error, FROM_HERE, "deviceBusy", ""); |
| }; |
| EXPECT_CALL(cloud_, Setup(_, _, _)).WillOnce(Invoke(set_error)); |
| EXPECT_PRED2(IsEqualError, CodeWithReason(503, "deviceBusy"), |
| HandleRequest("/privet/v3/setup/start", kInput)); |
| |
| const char kExpected[] = R"({ |
| 'gcd': { |
| 'status': 'inProgress' |
| } |
| })"; |
| cloud_.setup_state_ = SetupState{SetupState::kInProgress}; |
| EXPECT_CALL(cloud_, Setup("testTicket", "testUser", _)) |
| .WillOnce(Return(true)); |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/setup/start", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, GcdSetupAsMaster) { |
| EXPECT_CALL(security_, ParseAccessToken(_, _, _)) |
| .WillRepeatedly(DoAll( |
| SetArgPointee<1>(UserInfo{AuthScope::kManager, TestUserId{"1"}}), |
| Return(true))); |
| const char kInput[] = R"({ |
| 'gcd': { |
| 'ticketId': 'testTicket', |
| 'user': 'testUser' |
| } |
| })"; |
| |
| EXPECT_PRED2(IsEqualError, CodeWithReason(403, "invalidAuthorizationScope"), |
| HandleRequest("/privet/v3/setup/start", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, ClaimAccessControl) { |
| EXPECT_JSON_EQ("{'clientToken': 'RootClientAuthToken'}", |
| HandleRequest("/privet/v3/accessControl/claim", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, ConfirmAccessControl) { |
| EXPECT_JSON_EQ("{}", |
| HandleRequest("/privet/v3/accessControl/confirm", |
| "{'clientToken': 'DerivedClientAuthToken'}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, State) { |
| EXPECT_JSON_EQ("{'state': {'test': {}}, 'fingerprint': '1'}", |
| HandleRequest("/privet/v3/state", "{}")); |
| |
| cloud_.NotifyOnStateChanged(); |
| |
| EXPECT_JSON_EQ("{'state': {'test': {}}, 'fingerprint': '2'}", |
| HandleRequest("/privet/v3/state", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsDefs) { |
| EXPECT_JSON_EQ("{'commands': {'test':{}}, 'fingerprint': '1'}", |
| HandleRequest("/privet/v3/commandDefs", "{}")); |
| |
| cloud_.NotifyOnTraitDefsChanged(); |
| |
| EXPECT_JSON_EQ("{'commands': {'test':{}}, 'fingerprint': '2'}", |
| HandleRequest("/privet/v3/commandDefs", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, Traits) { |
| EXPECT_JSON_EQ("{'traits': {'test': {}}, 'fingerprint': '1'}", |
| HandleRequest("/privet/v3/traits", "{}")); |
| |
| cloud_.NotifyOnTraitDefsChanged(); |
| |
| EXPECT_JSON_EQ("{'traits': {'test': {}}, 'fingerprint': '2'}", |
| HandleRequest("/privet/v3/traits", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, Components) { |
| EXPECT_JSON_EQ("{'components': {'test': {}}, 'fingerprint': '1'}", |
| HandleRequest("/privet/v3/components", "{}")); |
| |
| cloud_.NotifyOnComponentTreeChanged(); |
| |
| EXPECT_JSON_EQ("{'components': {'test': {}}, 'fingerprint': '2'}", |
| HandleRequest("/privet/v3/components", "{}")); |
| |
| // State change will also change the components fingerprint. |
| cloud_.NotifyOnStateChanged(); |
| |
| EXPECT_JSON_EQ("{'components': {'test': {}}, 'fingerprint': '3'}", |
| HandleRequest("/privet/v3/components", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, ComponentsWithFiltersAndPaths) { |
| const char kComponents[] = R"({ |
| "comp1": { |
| "traits": ["a", "b"], |
| "state": { |
| "a" : { |
| "prop": 1 |
| } |
| }, |
| "components": { |
| "comp2": { |
| "traits": ["c"], |
| "components": { |
| "comp4": { |
| "traits": ["d"] |
| } |
| } |
| }, |
| "comp3": { |
| "traits": ["e"] |
| } |
| } |
| } |
| })"; |
| base::DictionaryValue components; |
| LoadTestJson(kComponents, &components); |
| EXPECT_CALL(cloud_, FindComponent(_, _)).WillRepeatedly(Return(nullptr)); |
| EXPECT_CALL(cloud_, GetComponents()).WillRepeatedly(ReturnRef(components)); |
| const char kExpected1[] = R"({ |
| "components": { |
| "comp1": { |
| "state": { |
| "a" : { |
| "prop": 1 |
| } |
| } |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ(kExpected1, HandleRequest("/privet/v3/components", |
| "{'filter':['state']}")); |
| |
| const char kExpected2[] = R"({ |
| "components": { |
| "comp1": { |
| "traits": ["a", "b"] |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ(kExpected2, HandleRequest("/privet/v3/components", |
| "{'filter':['traits']}")); |
| |
| const char kExpected3[] = R"({ |
| "components": { |
| "comp1": { |
| "components": { |
| "comp2": { |
| "components": { |
| "comp4": {} |
| } |
| }, |
| "comp3": {} |
| } |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ(kExpected3, HandleRequest("/privet/v3/components", |
| "{'filter':['components']}")); |
| |
| const char kExpected4[] = R"({ |
| "components": { |
| "comp1": { |
| "traits": ["a", "b"], |
| "state": { |
| "a" : { |
| "prop": 1 |
| } |
| }, |
| "components": { |
| "comp2": { |
| "traits": ["c"], |
| "components": { |
| "comp4": { |
| "traits": ["d"] |
| } |
| } |
| }, |
| "comp3": { |
| "traits": ["e"] |
| } |
| } |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ(kExpected4, |
| HandleRequest("/privet/v3/components", |
| "{'filter':['traits', 'components', 'state']}")); |
| |
| const base::DictionaryValue* comp2 = nullptr; |
| ASSERT_TRUE(components.GetDictionary("comp1.components.comp2", &comp2)); |
| EXPECT_CALL(cloud_, FindComponent("comp1.comp2", _)).WillOnce(Return(comp2)); |
| |
| const char kExpected5[] = R"({ |
| "components": { |
| "comp2": { |
| "traits": ["c"], |
| "components": { |
| "comp4": { |
| "traits": ["d"] |
| } |
| } |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ( |
| kExpected5, |
| HandleRequest( |
| "/privet/v3/components", |
| "{'path':'comp1.comp2', 'filter':['traits', 'components']}")); |
| |
| auto error_handler = [](ErrorPtr* error) -> const base::DictionaryValue* { |
| return Error::AddTo(error, FROM_HERE, "componentNotFound", ""); |
| }; |
| EXPECT_CALL(cloud_, FindComponent("comp7", _)) |
| .WillOnce(WithArgs<1>(Invoke(error_handler))); |
| |
| EXPECT_PRED2( |
| IsEqualError, CodeWithReason(500, "componentNotFound"), |
| HandleRequest("/privet/v3/components", |
| "{'path':'comp7', 'filter':['traits', 'components']}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsExecute) { |
| const char kInput[] = "{'name': 'test'}"; |
| base::DictionaryValue command; |
| LoadTestJson(kInput, &command); |
| LoadTestJson("{'id':'5'}", &command); |
| EXPECT_CALL(cloud_, AddCommand(_, _, _)) |
| .WillOnce(WithArgs<2>(Invoke( |
| [&command](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run(command, nullptr); |
| }))); |
| |
| EXPECT_JSON_EQ("{'name':'test', 'id':'5'}", |
| HandleRequest("/privet/v3/commands/execute", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsStatus) { |
| const char kInput[] = "{'id': '5'}"; |
| base::DictionaryValue command; |
| LoadTestJson(kInput, &command); |
| LoadTestJson("{'name':'test'}", &command); |
| EXPECT_CALL(cloud_, GetCommand(_, _, _)) |
| .WillOnce(WithArgs<2>(Invoke( |
| [&command](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run(command, nullptr); |
| }))); |
| |
| EXPECT_JSON_EQ("{'name':'test', 'id':'5'}", |
| HandleRequest("/privet/v3/commands/status", kInput)); |
| |
| ErrorPtr error; |
| Error::AddTo(&error, FROM_HERE, "notFound", ""); |
| EXPECT_CALL(cloud_, GetCommand(_, _, _)) |
| .WillOnce(WithArgs<2>( |
| Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run({}, std::move(error)); |
| }))); |
| |
| EXPECT_PRED2(IsEqualError, CodeWithReason(404, "notFound"), |
| HandleRequest("/privet/v3/commands/status", "{'id': '15'}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsCancel) { |
| const char kExpected[] = "{'id': '5', 'name':'test', 'state':'cancelled'}"; |
| base::DictionaryValue command; |
| LoadTestJson(kExpected, &command); |
| EXPECT_CALL(cloud_, CancelCommand(_, _, _)) |
| .WillOnce(WithArgs<2>(Invoke( |
| [&command](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run(command, nullptr); |
| }))); |
| |
| EXPECT_JSON_EQ(kExpected, |
| HandleRequest("/privet/v3/commands/cancel", "{'id': '8'}")); |
| |
| ErrorPtr error; |
| Error::AddTo(&error, FROM_HERE, "notFound", ""); |
| EXPECT_CALL(cloud_, CancelCommand(_, _, _)) |
| .WillOnce(WithArgs<2>( |
| Invoke([&error](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run({}, std::move(error)); |
| }))); |
| |
| EXPECT_PRED2(IsEqualError, CodeWithReason(404, "notFound"), |
| HandleRequest("/privet/v3/commands/cancel", "{'id': '11'}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsList) { |
| const char kExpected[] = R"({ |
| 'commands' : [ |
| {'id':'5', 'state':'cancelled'}, |
| {'id':'15', 'state':'inProgress'} |
| ]})"; |
| |
| base::DictionaryValue commands; |
| LoadTestJson(kExpected, &commands); |
| |
| EXPECT_CALL(cloud_, ListCommands(_, _)) |
| .WillOnce(WithArgs<1>(Invoke( |
| [&commands](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run(commands, nullptr); |
| }))); |
| |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/commands/list", "{}")); |
| } |
| |
| class PrivetHandlerCheckForUpdatesTest : public PrivetHandlerTestWithAuth {}; |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, NoInput) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| cloud_.NotifyOnTraitDefsChanged(); |
| cloud_.NotifyOnComponentTreeChanged(); |
| cloud_.NotifyOnStateChanged(); |
| const char kInput[] = "{}"; |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '2', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '3' |
| })"; |
| EXPECT_JSON_EQ(kExpected, |
| HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(1, GetResponseCount()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, AlreadyChanged) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| cloud_.NotifyOnTraitDefsChanged(); |
| cloud_.NotifyOnComponentTreeChanged(); |
| cloud_.NotifyOnStateChanged(); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '2', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '3' |
| })"; |
| EXPECT_JSON_EQ(kExpected, |
| HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(1, GetResponseCount()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, LongPollCommands) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnTraitDefsChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, LongPollTraits) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnTraitDefsChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, LongPollState) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnStateChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '2', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '2' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, LongPollComponents) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnComponentTreeChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '2' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, LongPollIgnoreTraits) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'stateFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnTraitDefsChanged(); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnComponentTreeChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '2' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, LongPollIgnoreState) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'traitsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnStateChanged(); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnComponentTreeChanged(); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnTraitDefsChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '2', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '3' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, InstantTimeout) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1', |
| 'waitTimeout': 0 |
| })"; |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, |
| HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, UserTimeout) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1', |
| 'waitTimeout': 3 |
| })"; |
| base::Closure callback; |
| EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(3))) |
| .WillOnce(SaveArg<1>(&callback)); |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| callback.Run(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, ServerTimeout) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::FromMinutes(1))); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| base::Closure callback; |
| EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(50))) |
| .WillOnce(SaveArg<1>(&callback)); |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| callback.Run(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, VeryShortServerTimeout) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::FromSeconds(5))); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kInput, HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(1, GetResponseCount()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, ServerAndUserTimeout) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::FromMinutes(1))); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1', |
| 'waitTimeout': 10 |
| })"; |
| base::Closure callback; |
| EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(10))) |
| .WillOnce(SaveArg<1>(&callback)); |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| callback.Run(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| } |
| |
| TEST_F(PrivetHandlerCheckForUpdatesTest, ChangeBeforeTimeout) { |
| EXPECT_CALL(device_, GetHttpRequestTimeout()) |
| .WillOnce(Return(base::TimeDelta::Max())); |
| const char kInput[] = R"({ |
| 'commandsFingerprint': '1', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '1', |
| 'componentsFingerprint': '1', |
| 'waitTimeout': 10 |
| })"; |
| base::Closure callback; |
| EXPECT_CALL(device_, PostDelayedTask(_, _, base::TimeDelta::FromSeconds(10))) |
| .WillOnce(SaveArg<1>(&callback)); |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/checkForUpdates", kInput)); |
| EXPECT_EQ(0, GetResponseCount()); |
| cloud_.NotifyOnTraitDefsChanged(); |
| EXPECT_EQ(1, GetResponseCount()); |
| const char kExpected[] = R"({ |
| 'commandsFingerprint': '2', |
| 'stateFingerprint': '1', |
| 'traitsFingerprint': '2', |
| 'componentsFingerprint': '1' |
| })"; |
| EXPECT_JSON_EQ(kExpected, GetResponse()); |
| callback.Run(); |
| EXPECT_EQ(1, GetResponseCount()); |
| } |
| |
| } // namespace privet |
| } // namespace weave |