| // 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/device.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) { |
| int error = 0; |
| std::string message; |
| std::unique_ptr<base::Value> value( |
| base::JSONReader::ReadAndReturnError(test_json, base::JSON_PARSE_RFC, |
| &error, &message) |
| .release()); |
| EXPECT_TRUE(value.get()) << "\nError: " << message << "\n" << test_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 << R"({" << 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 = [](ErrorPtr* error) { |
| Error::AddTo(error, FROM_HERE, "setupUnavailable", ""); |
| }; |
| EXPECT_CALL(cloud_, Setup(_, _)) |
| .WillRepeatedly(DoAll(WithArgs<1>(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": "", |
| "oauth_url": "https://oauths/", |
| "service_url": "https://service/", |
| "status": "disabled", |
| "xmpp_endpoint": "xmpp:678" |
| }, |
| "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", |
| "oauth_url": "https://oauths/", |
| "service_url": "https://service/", |
| "status": "online", |
| "xmpp_endpoint": "xmpp:678" |
| }, |
| "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", |
| R"({"pairing":"embeddedCode","crypto":"crypto"})")); |
| |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidParams"), |
| HandleRequest("/privet/v3/pairing/start", |
| R"({"pairing":"code","crypto":"p224_spake2"})")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingStart) { |
| EXPECT_JSON_EQ( |
| R"({"deviceCommitment": "testCommitment", "sessionId": "testSession"})", |
| HandleRequest("/privet/v3/pairing/start", |
| R"({"pairing": "embeddedCode", "crypto": "p224_spake2"})")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingConfirm) { |
| EXPECT_JSON_EQ( |
| R"({"certFingerprint":"testFingerprint","certSignature":"testSignature"})", |
| HandleRequest( |
| "/privet/v3/pairing/confirm", |
| R"({"sessionId":"testSession","clientCommitment":"testCommitment"})")); |
| } |
| |
| TEST_F(PrivetHandlerTest, PairingCancel) { |
| EXPECT_JSON_EQ("{}", HandleRequest("/privet/v3/pairing/cancel", |
| R"({"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", R"({"mode":"unknown"})")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorNoScope) { |
| EXPECT_PRED2(IsEqualError, CodeWithReason(400, "invalidRequestedScope"), |
| HandleRequest("/privet/v3/auth", R"({"mode":"anonymous"})")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorInvalidScope) { |
| EXPECT_PRED2( |
| IsEqualError, CodeWithReason(400, "invalidRequestedScope"), |
| HandleRequest("/privet/v3/auth", |
| R"({"mode":"anonymous","requestedScope":"unknown"})")); |
| } |
| |
| TEST_F(PrivetHandlerTest, AuthErrorAccessDenied) { |
| EXPECT_PRED2( |
| IsEqualError, CodeWithReason(403, "accessDenied"), |
| HandleRequest("/privet/v3/auth", |
| R"({"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", |
| R"({"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", |
| "oauth_url": "https://oauths/", |
| "service_url": "https://service/", |
| "status": "success", |
| "xmpp_endpoint": "xmpp:678" |
| } |
| })"; |
| 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", R"({"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 = [](ErrorPtr* error) { |
| return Error::AddTo(error, FROM_HERE, "deviceBusy", ""); |
| }; |
| EXPECT_CALL(cloud_, Setup(_, _)).WillOnce(WithArgs<1>(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(RegistrationData{"testTicket"}, _)) |
| .WillOnce(Return(true)); |
| EXPECT_JSON_EQ(kExpected, HandleRequest("/privet/v3/setup/start", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerSetupTest, GcdSetupWithEndpoints) { |
| const char kInput[] = R"({ |
| "gcd": { |
| "api_key": "test_api_key", |
| "client_id": "test_client_id", |
| "client_secret": "test_client_secret", |
| "oauth_url": "https://oauths/", |
| "service_url": "https://service/", |
| "xmpp_endpoint": "xmpp:678", |
| "ticketId": "testTicket", |
| "user": "testUser" |
| } |
| })"; |
| |
| const char kExpected[] = R"({ |
| "gcd": { |
| "status": "inProgress" |
| } |
| })"; |
| cloud_.setup_state_ = SetupState{SetupState::kInProgress}; |
| |
| RegistrationData expected_reg_data; |
| expected_reg_data.ticket_id = "testTicket"; |
| expected_reg_data.oauth_url = "https://oauths/"; |
| expected_reg_data.client_id = "test_client_id"; |
| expected_reg_data.client_secret = "test_client_secret"; |
| expected_reg_data.api_key = "test_api_key"; |
| expected_reg_data.service_url = "https://service/"; |
| expected_reg_data.xmpp_endpoint = "xmpp:678"; |
| |
| EXPECT_CALL(cloud_, Setup(expected_reg_data, _)).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(R"({"clientToken": "RootClientAuthToken"})", |
| HandleRequest("/privet/v3/accessControl/claim", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, ConfirmAccessControl) { |
| EXPECT_JSON_EQ("{}", |
| HandleRequest("/privet/v3/accessControl/confirm", |
| R"({"clientToken": "DerivedClientAuthToken"})")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, Traits) { |
| EXPECT_JSON_EQ(R"({"traits": {"test": {}}, "fingerprint": "1"})", |
| HandleRequest("/privet/v3/traits", "{}")); |
| |
| cloud_.NotifyOnTraitDefsChanged(); |
| |
| EXPECT_JSON_EQ(R"({"traits": {"test": {}}, "fingerprint": "2"})", |
| HandleRequest("/privet/v3/traits", "{}")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, Components) { |
| EXPECT_JSON_EQ(R"({"components": {"test": {}}, "fingerprint": "1"})", |
| HandleRequest("/privet/v3/components", "{}")); |
| |
| cloud_.NotifyOnComponentTreeChanged(); |
| |
| EXPECT_JSON_EQ(R"({"components": {"test": {}}, "fingerprint": "2"})", |
| HandleRequest("/privet/v3/components", "{}")); |
| |
| // State change will also change the components fingerprint. |
| cloud_.NotifyOnStateChanged(); |
| |
| EXPECT_JSON_EQ(R"({"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", |
| R"({"filter":["state"]})")); |
| |
| const char kExpected2[] = R"({ |
| "components": { |
| "comp1": { |
| "traits": ["a", "b"] |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ(kExpected2, HandleRequest("/privet/v3/components", |
| R"({"filter":["traits"]})")); |
| |
| const char kExpected3[] = R"({ |
| "components": { |
| "comp1": { |
| "components": { |
| "comp2": { |
| "components": { |
| "comp4": {} |
| } |
| }, |
| "comp3": {} |
| } |
| } |
| }, |
| "fingerprint": "1" |
| })"; |
| EXPECT_JSON_EQ(kExpected3, HandleRequest("/privet/v3/components", |
| R"({"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", |
| R"({"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", |
| R"({"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", |
| R"({"path":"comp7", "filter":["traits", "components"]})")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsExecute) { |
| const char kInput[] = R"({"name": "test"})"; |
| base::DictionaryValue command; |
| LoadTestJson(kInput, &command); |
| LoadTestJson(R"({"id":"5"})", &command); |
| EXPECT_CALL(cloud_, AddCommand(_, _, _)) |
| .WillOnce(WithArgs<2>(Invoke( |
| [&command](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run(command, nullptr); |
| }))); |
| |
| EXPECT_JSON_EQ(R"({"name":"test", "id":"5"})", |
| HandleRequest("/privet/v3/commands/execute", kInput)); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsStatus) { |
| const char kInput[] = R"({"id": "5"})"; |
| base::DictionaryValue command; |
| LoadTestJson(kInput, &command); |
| LoadTestJson(R"({"name":"test"})", &command); |
| EXPECT_CALL(cloud_, GetCommand(_, _, _)) |
| .WillOnce(WithArgs<2>(Invoke( |
| [&command](const CloudDelegate::CommandDoneCallback& callback) { |
| callback.Run(command, nullptr); |
| }))); |
| |
| EXPECT_JSON_EQ(R"({"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", R"({"id": "15"})")); |
| } |
| |
| TEST_F(PrivetHandlerTestWithAuth, CommandsCancel) { |
| const char kExpected[] = R"({"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", R"({"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", R"({"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 |