blob: f2fe4c45b51061a634dd3caafbc19e409ac134e8 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenko8e34d392014-04-29 11:02:56 -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/device_registration_info.h"
Alex Deymof6cbe322014-11-10 19:55:35 -08006
Alex Vakulenko8e34d392014-04-29 11:02:56 -07007#include <base/json/json_reader.h>
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -07008#include <base/json/json_writer.h>
Alex Vakulenko8e34d392014-04-29 11:02:56 -07009#include <base/values.h>
10#include <gtest/gtest.h>
Vitaly Bukaff1d1862015-10-07 20:40:36 -070011#include <weave/provider/test/fake_task_runner.h>
Vitaly Buka1e363672015-09-25 14:01:16 -070012#include <weave/provider/test/mock_config_store.h>
13#include <weave/provider/test/mock_http_client.h>
Alex Vakulenko8a05beb2015-11-24 17:13:20 -080014#include <weave/test/unittest_utils.h>
Alex Vakulenko8e34d392014-04-29 11:02:56 -070015
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020016#include "src/bind_lambda.h"
17#include "src/commands/command_manager.h"
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020018#include "src/http_constants.h"
19#include "src/states/mock_state_change_queue_interface.h"
20#include "src/states/state_manager.h"
Alex Vakulenko8e34d392014-04-29 11:02:56 -070021
Vitaly Buka6b61e572015-08-05 23:16:13 -070022using testing::_;
Vitaly Buka10206182015-08-05 11:17:43 -070023using testing::AtLeast;
24using testing::Invoke;
25using testing::InvokeWithoutArgs;
26using testing::Mock;
Vitaly Buka6b61e572015-08-05 23:16:13 -070027using testing::Return;
Vitaly Buka10206182015-08-05 11:17:43 -070028using testing::ReturnRef;
29using testing::ReturnRefOfCopy;
Vitaly Bukac11a17d2015-08-15 10:36:10 -070030using testing::SaveArg;
Vitaly Buka6b61e572015-08-05 23:16:13 -070031using testing::StrictMock;
Vitaly Buka10206182015-08-05 11:17:43 -070032using testing::WithArgs;
Vitaly Buka6b61e572015-08-05 23:16:13 -070033
Vitaly Bukab6f015a2015-07-09 14:59:23 -070034namespace weave {
Vitaly Buka32005de2015-05-01 12:33:31 -070035
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -070036using test::CreateDictionaryValue;
37using test::CreateValue;
Vitaly Buka1e363672015-09-25 14:01:16 -070038using provider::test::MockHttpClient;
39using provider::test::MockHttpClientResponse;
40using provider::HttpClient;
Alex Vakulenkocca20932014-08-20 17:35:12 -070041
Alex Vakulenko8e34d392014-04-29 11:02:56 -070042namespace {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070043
44namespace test_data {
45
Vitaly Bukaa647c852015-07-06 14:51:01 -070046const char kServiceURL[] = "http://gcd.server.com/";
47const char kOAuthURL[] = "http://oauth.server.com/";
48const char kApiKey[] = "GOadRdTf9FERf0k4w6EFOof56fUJ3kFDdFL3d7f";
49const char kClientId[] =
50 "123543821385-sfjkjshdkjhfk234sdfsdfkskd"
51 "fkjh7f.apps.googleusercontent.com";
52const char kClientSecret[] = "5sdGdGlfolGlrFKfdFlgP6FG";
53const char kDeviceId[] = "4a7ea2d1-b331-1e1f-b206-e863c7635196";
54const char kClaimTicketId[] = "RTcUE";
55const char kAccessToken[] =
56 "ya29.1.AADtN_V-dLUM-sVZ0qVjG9Dxm5NgdS9J"
57 "Mx_JLUqhC9bED_YFjzHZtYt65ZzXCS35NMAeaVZ"
58 "Dei530-w0yE2urpQ";
59const char kRefreshToken[] =
60 "1/zQmxR6PKNvhcxf9SjXUrCjcmCrcqRKXctc6cp"
61 "1nI-GQ";
62const char kRobotAccountAuthCode[] =
63 "4/Mf_ujEhPejVhOq-OxW9F5cSOnWzx."
64 "YgciVjTYGscRshQV0ieZDAqiTIjMigI";
65const char kRobotAccountEmail[] =
66 "6ed0b3f54f9bd619b942f4ad2441c252@"
67 "clouddevices.gserviceaccount.com";
Vitaly Buka10206182015-08-05 11:17:43 -070068
Alex Vakulenko8e34d392014-04-29 11:02:56 -070069} // namespace test_data
70
Vitaly Buka10206182015-08-05 11:17:43 -070071std::string GetFormField(const std::string& data, const std::string& name) {
72 EXPECT_FALSE(data.empty());
Vitaly Buka7d556392015-08-13 20:06:48 -070073 for (const auto& i : WebParamsDecode(data)) {
Vitaly Buka10206182015-08-05 11:17:43 -070074 if (i.first == name)
75 return i.second;
Alex Vakulenko8e34d392014-04-29 11:02:56 -070076 }
Vitaly Buka10206182015-08-05 11:17:43 -070077 return {};
Alex Vakulenko8e34d392014-04-29 11:02:56 -070078}
79
Vitaly Buka17280372015-10-10 17:11:47 -070080std::unique_ptr<HttpClient::Response> ReplyWithJson(int status_code,
81 const base::Value& json) {
Vitaly Buka10206182015-08-05 11:17:43 -070082 std::string text;
83 base::JSONWriter::WriteWithOptions(
84 json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &text);
85
Vitaly Buka17280372015-10-10 17:11:47 -070086 std::unique_ptr<MockHttpClientResponse> response{
87 new StrictMock<MockHttpClientResponse>};
Vitaly Buka10206182015-08-05 11:17:43 -070088 EXPECT_CALL(*response, GetStatusCode())
89 .Times(AtLeast(1))
90 .WillRepeatedly(Return(status_code));
91 EXPECT_CALL(*response, GetContentType())
92 .Times(AtLeast(1))
Vitaly Buka815b6032015-08-06 11:06:25 -070093 .WillRepeatedly(Return(http::kJsonUtf8));
Vitaly Buka10206182015-08-05 11:17:43 -070094 EXPECT_CALL(*response, GetData())
95 .Times(AtLeast(1))
Vitaly Buka4774df22015-10-09 12:36:22 -070096 .WillRepeatedly(Return(text));
Vitaly Buka17280372015-10-10 17:11:47 -070097 return std::move(response);
Nathan Bullock24d189f2015-02-26 13:09:18 -050098}
99
Vitaly Buka10206182015-08-05 11:17:43 -0700100std::pair<std::string, std::string> GetAuthHeader() {
Vitaly Buka815b6032015-08-06 11:06:25 -0700101 return {http::kAuthorization,
102 std::string("Bearer ") + test_data::kAccessToken};
103}
104
105std::pair<std::string, std::string> GetJsonHeader() {
106 return {http::kContentType, http::kJsonUtf8};
107}
108
109std::pair<std::string, std::string> GetFormHeader() {
110 return {http::kContentType, http::kWwwFormUrlEncoded};
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700111}
112
113} // anonymous namespace
114
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700115class DeviceRegistrationInfoTest : public ::testing::Test {
116 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -0700117 void SetUp() override {
Vitaly Buka6b61e572015-08-05 23:16:13 -0700118 EXPECT_CALL(mock_state_change_queue_, GetLastStateChangeId())
119 .WillRepeatedly(Return(0));
120 EXPECT_CALL(mock_state_change_queue_, MockAddOnStateUpdatedCallback(_))
121 .WillRepeatedly(Return(nullptr));
122
Vitaly Bukaae0f3a12015-05-11 16:27:30 -0700123 command_manager_ = std::make_shared<CommandManager>();
Alex Vakulenko57123b22014-10-28 13:50:16 -0700124 state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700125
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700126 std::unique_ptr<Config> config{new Config{&config_store_}};
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700127 config_ = config.get();
Vitaly Buka10206182015-08-05 11:17:43 -0700128 dev_reg_.reset(new DeviceRegistrationInfo{command_manager_, state_manager_,
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700129 std::move(config), &task_runner_,
Vitaly Buka1e363672015-09-25 14:01:16 -0700130 &http_client_, nullptr});
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700131
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700132 ReloadDefaults();
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700133 }
134
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700135 void ReloadDefaults() {
136 EXPECT_CALL(config_store_, LoadDefaults(_))
137 .WillOnce(Invoke([](Settings* settings) {
138 settings->client_id = test_data::kClientId;
139 settings->client_secret = test_data::kClientSecret;
140 settings->api_key = test_data::kApiKey;
Vitaly Bukaa05eadb2015-09-29 16:38:24 -0700141 settings->oem_name = "Coffee Pot Maker";
142 settings->model_name = "Pot v1";
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700143 settings->name = "Coffee Pot";
144 settings->description = "Easy to clean";
145 settings->location = "Kitchen";
Vitaly Bukab624bc42015-09-29 19:13:55 -0700146 settings->local_anonymous_access_role = AuthScope::kViewer;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700147 settings->model_id = "AAAAA";
148 settings->oauth_url = test_data::kOAuthURL;
149 settings->service_url = test_data::kServiceURL;
150 return true;
151 }));
152 config_->Load();
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700153 dev_reg_->Start();
154 }
155
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700156 void ReloadSettings() {
157 base::DictionaryValue dict;
158 dict.SetString("refresh_token", test_data::kRefreshToken);
Johan Euphrosine312c2f52015-09-29 00:04:29 -0700159 dict.SetString("cloud_id", test_data::kDeviceId);
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700160 dict.SetString("robot_account", test_data::kRobotAccountEmail);
161 std::string json_string;
162 base::JSONWriter::WriteWithOptions(
163 dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
164 EXPECT_CALL(config_store_, LoadSettings()).WillOnce(Return(json_string));
165 ReloadDefaults();
166 }
167
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700168 void PublishCommands(const base::ListValue& commands) {
Vitaly Buka74763422015-10-11 00:39:52 -0700169 dev_reg_->PublishCommands(commands, nullptr);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700170 }
171
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700172 bool RefreshAccessToken(ErrorPtr* error) const {
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700173 bool succeeded = false;
Vitaly Buka74763422015-10-11 00:39:52 -0700174 auto callback = [&succeeded, &error](ErrorPtr in_error) {
175 if (error) {
Vitaly Bukaf7f52d42015-10-10 22:43:55 -0700176 *error = std::move(in_error);
Vitaly Buka74763422015-10-11 00:39:52 -0700177 return;
178 }
179 succeeded = true;
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700180 };
Vitaly Buka74763422015-10-11 00:39:52 -0700181 dev_reg_->RefreshAccessToken(base::Bind(callback));
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700182 return succeeded;
183 }
184
Vitaly Bukaa647c852015-07-06 14:51:01 -0700185 void SetAccessToken() { dev_reg_->access_token_ = test_data::kAccessToken; }
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700186
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700187 GcdState GetGcdState() const { return dev_reg_->GetGcdState(); }
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700188
Vitaly Buka672634b2015-11-20 09:49:30 -0800189 bool HaveRegistrationCredentials() const {
190 return dev_reg_->HaveRegistrationCredentials();
191 }
192
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700193 provider::test::FakeTaskRunner task_runner_;
Vitaly Buka1e363672015-09-25 14:01:16 -0700194 provider::test::MockConfigStore config_store_;
Vitaly Buka10206182015-08-05 11:17:43 -0700195 StrictMock<MockHttpClient> http_client_;
Alex Vakulenko45109442014-07-29 11:07:10 -0700196 base::DictionaryValue data_;
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700197 Config* config_{nullptr};
Alex Vakulenko45109442014-07-29 11:07:10 -0700198 std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
199 std::shared_ptr<CommandManager> command_manager_;
Vitaly Buka6b61e572015-08-05 23:16:13 -0700200 StrictMock<MockStateChangeQueueInterface> mock_state_change_queue_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700201 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700202};
203
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700204TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700205 EXPECT_EQ(test_data::kServiceURL, dev_reg_->GetServiceURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700206 std::string url = test_data::kServiceURL;
207 url += "registrationTickets";
Alex Vakulenko45109442014-07-29 11:07:10 -0700208 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets"));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700209 url += "?key=";
210 url += test_data::kApiKey;
Vitaly Bukaa647c852015-07-06 14:51:01 -0700211 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets",
212 {{"key", test_data::kApiKey}}));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700213 url += "&restart=true";
Vitaly Bukaa647c852015-07-06 14:51:01 -0700214 EXPECT_EQ(url, dev_reg_->GetServiceURL(
215 "registrationTickets",
216 {
217 {"key", test_data::kApiKey}, {"restart", "true"},
218 }));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700219}
220
221TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700222 EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700223 std::string url = test_data::kOAuthURL;
Vitaly Buka88272d52015-11-17 17:04:01 -0800224 url += "auth?redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700225 url += "response_type=code&";
226 url += "client_id=";
227 url += test_data::kClientId;
Vitaly Bukaa647c852015-07-06 14:51:01 -0700228 EXPECT_EQ(url, dev_reg_->GetOAuthURL(
Vitaly Bukac27390d2015-11-19 14:42:35 -0800229 "auth", {{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
230 {"response_type", "code"},
231 {"client_id", test_data::kClientId}}));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700232}
233
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700234TEST_F(DeviceRegistrationInfoTest, HaveRegistrationCredentials) {
Vitaly Buka672634b2015-11-20 09:49:30 -0800235 EXPECT_FALSE(HaveRegistrationCredentials());
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700236 ReloadSettings();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700237
Vitaly Buka1a42e142015-10-10 18:15:15 -0700238 EXPECT_CALL(
239 http_client_,
240 SendRequest(HttpClient::Method::kPost, dev_reg_->GetOAuthURL("token"),
Vitaly Buka74763422015-10-11 00:39:52 -0700241 HttpClient::Headers{GetFormHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700242 .WillOnce(WithArgs<3, 4>(Invoke([](
243 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700244 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka10206182015-08-05 11:17:43 -0700245 EXPECT_EQ("refresh_token", GetFormField(data, "grant_type"));
246 EXPECT_EQ(test_data::kRefreshToken,
247 GetFormField(data, "refresh_token"));
248 EXPECT_EQ(test_data::kClientId, GetFormField(data, "client_id"));
249 EXPECT_EQ(test_data::kClientSecret,
250 GetFormField(data, "client_secret"));
251
252 base::DictionaryValue json;
253 json.SetString("access_token", test_data::kAccessToken);
254 json.SetInteger("expires_in", 3600);
255
Vitaly Buka74763422015-10-11 00:39:52 -0700256 callback.Run(ReplyWithJson(200, json), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700257 })));
258
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700259 EXPECT_TRUE(RefreshAccessToken(nullptr));
Vitaly Buka672634b2015-11-20 09:49:30 -0800260 EXPECT_TRUE(HaveRegistrationCredentials());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700261}
262
Nathan Bullock24d189f2015-02-26 13:09:18 -0500263TEST_F(DeviceRegistrationInfoTest, CheckAuthenticationFailure) {
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700264 ReloadSettings();
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700265 EXPECT_EQ(GcdState::kConnecting, GetGcdState());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500266
Vitaly Buka1a42e142015-10-10 18:15:15 -0700267 EXPECT_CALL(
268 http_client_,
269 SendRequest(HttpClient::Method::kPost, dev_reg_->GetOAuthURL("token"),
Vitaly Buka74763422015-10-11 00:39:52 -0700270 HttpClient::Headers{GetFormHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700271 .WillOnce(WithArgs<3, 4>(Invoke([](
272 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700273 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka10206182015-08-05 11:17:43 -0700274 EXPECT_EQ("refresh_token", GetFormField(data, "grant_type"));
275 EXPECT_EQ(test_data::kRefreshToken,
276 GetFormField(data, "refresh_token"));
277 EXPECT_EQ(test_data::kClientId, GetFormField(data, "client_id"));
278 EXPECT_EQ(test_data::kClientSecret,
279 GetFormField(data, "client_secret"));
280
281 base::DictionaryValue json;
282 json.SetString("error", "unable_to_authenticate");
Vitaly Buka74763422015-10-11 00:39:52 -0700283 callback.Run(ReplyWithJson(400, json), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700284 })));
285
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700286 ErrorPtr error;
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700287 EXPECT_FALSE(RefreshAccessToken(&error));
Vitaly Buka32005de2015-05-01 12:33:31 -0700288 EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "unable_to_authenticate"));
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700289 EXPECT_EQ(GcdState::kConnecting, GetGcdState());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500290}
291
292TEST_F(DeviceRegistrationInfoTest, CheckDeregistration) {
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700293 ReloadSettings();
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700294 EXPECT_EQ(GcdState::kConnecting, GetGcdState());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500295
Vitaly Buka1a42e142015-10-10 18:15:15 -0700296 EXPECT_CALL(
297 http_client_,
298 SendRequest(HttpClient::Method::kPost, dev_reg_->GetOAuthURL("token"),
Vitaly Buka74763422015-10-11 00:39:52 -0700299 HttpClient::Headers{GetFormHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700300 .WillOnce(WithArgs<3, 4>(Invoke([](
301 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700302 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka10206182015-08-05 11:17:43 -0700303 EXPECT_EQ("refresh_token", GetFormField(data, "grant_type"));
304 EXPECT_EQ(test_data::kRefreshToken,
305 GetFormField(data, "refresh_token"));
306 EXPECT_EQ(test_data::kClientId, GetFormField(data, "client_id"));
307 EXPECT_EQ(test_data::kClientSecret,
308 GetFormField(data, "client_secret"));
309
310 base::DictionaryValue json;
311 json.SetString("error", "invalid_grant");
Vitaly Buka74763422015-10-11 00:39:52 -0700312 callback.Run(ReplyWithJson(400, json), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700313 })));
314
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700315 ErrorPtr error;
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700316 EXPECT_FALSE(RefreshAccessToken(&error));
Vitaly Buka32005de2015-05-01 12:33:31 -0700317 EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "invalid_grant"));
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700318 EXPECT_EQ(GcdState::kInvalidCredentials, GetGcdState());
Vitaly Buka672634b2015-11-20 09:49:30 -0800319 EXPECT_EQ(test_data::kDeviceId, dev_reg_->GetSettings().cloud_id);
Nathan Bullock24d189f2015-02-26 13:09:18 -0500320}
321
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700322TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700323 ReloadSettings();
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700324 SetAccessToken();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700325
Vitaly Buka74763422015-10-11 00:39:52 -0700326 EXPECT_CALL(
327 http_client_,
328 SendRequest(HttpClient::Method::kGet, dev_reg_->GetDeviceURL(),
329 HttpClient::Headers{GetAuthHeader(), GetJsonHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700330 .WillOnce(WithArgs<3, 4>(
331 Invoke([](const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700332 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka17280372015-10-10 17:11:47 -0700333 base::DictionaryValue json;
334 json.SetString("channel.supportedType", "xmpp");
335 json.SetString("deviceKind", "vendor");
336 json.SetString("id", test_data::kDeviceId);
Vitaly Buka88272d52015-11-17 17:04:01 -0800337 json.SetString("kind", "weave#device");
Vitaly Buka74763422015-10-11 00:39:52 -0700338 callback.Run(ReplyWithJson(200, json), nullptr);
Vitaly Buka17280372015-10-10 17:11:47 -0700339 })));
Vitaly Buka10206182015-08-05 11:17:43 -0700340
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700341 bool succeeded = false;
Vitaly Buka74763422015-10-11 00:39:52 -0700342 auto callback = [&succeeded, this](const base::DictionaryValue& info,
343 ErrorPtr error) {
344 EXPECT_FALSE(error);
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700345 std::string id;
346 EXPECT_TRUE(info.GetString("id", &id));
347 EXPECT_EQ(test_data::kDeviceId, id);
348 succeeded = true;
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700349 };
Vitaly Buka74763422015-10-11 00:39:52 -0700350 dev_reg_->GetDeviceInfo(base::Bind(callback));
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700351 EXPECT_TRUE(succeeded);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700352}
353
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400354TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
Vitaly Buka10206182015-08-05 11:17:43 -0700355 auto json_cmds = CreateDictionaryValue(R"({
Alex Vakulenko45109442014-07-29 11:07:10 -0700356 'base': {
357 'reboot': {
Alex Vakulenko7e894da2015-11-23 11:47:49 -0800358 'parameters': {'delay': {'minimum': 10, 'type': 'integer'}},
359 'minimalRole': 'user'
Alex Vakulenko45109442014-07-29 11:07:10 -0700360 }
361 },
362 'robot': {
363 '_jump': {
Alex Vakulenko7e894da2015-11-23 11:47:49 -0800364 'parameters': {'_height': {'type': 'integer'}},
365 'minimalRole': 'user'
Alex Vakulenko45109442014-07-29 11:07:10 -0700366 }
367 }
368 })");
Vitaly Buka453c4dd2015-10-04 18:01:50 -0700369 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, nullptr));
Alex Vakulenko45109442014-07-29 11:07:10 -0700370
Vitaly Buka10206182015-08-05 11:17:43 -0700371 std::string ticket_url = dev_reg_->GetServiceURL("registrationTickets/") +
372 test_data::kClaimTicketId;
Vitaly Buka1a42e142015-10-10 18:15:15 -0700373 EXPECT_CALL(http_client_,
374 SendRequest(HttpClient::Method::kPatch,
375 ticket_url + "?key=" + test_data::kApiKey,
Vitaly Buka74763422015-10-11 00:39:52 -0700376 HttpClient::Headers{GetJsonHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700377 .WillOnce(WithArgs<3, 4>(Invoke([](
378 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700379 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -0700380 auto json = test::CreateDictionaryValue(data);
Vitaly Buka10206182015-08-05 11:17:43 -0700381 EXPECT_NE(nullptr, json.get());
382 std::string value;
383 EXPECT_TRUE(json->GetString("id", &value));
384 EXPECT_EQ(test_data::kClaimTicketId, value);
385 EXPECT_TRUE(
386 json->GetString("deviceDraft.channel.supportedType", &value));
387 EXPECT_EQ("pull", value);
388 EXPECT_TRUE(json->GetString("oauthClientId", &value));
389 EXPECT_EQ(test_data::kClientId, value);
Vitaly Buka10206182015-08-05 11:17:43 -0700390 EXPECT_TRUE(json->GetString("deviceDraft.description", &value));
391 EXPECT_EQ("Easy to clean", value);
392 EXPECT_TRUE(json->GetString("deviceDraft.location", &value));
393 EXPECT_EQ("Kitchen", value);
394 EXPECT_TRUE(json->GetString("deviceDraft.modelManifestId", &value));
395 EXPECT_EQ("AAAAA", value);
396 EXPECT_TRUE(json->GetString("deviceDraft.name", &value));
397 EXPECT_EQ("Coffee Pot", value);
398 base::DictionaryValue* commandDefs = nullptr;
399 EXPECT_TRUE(
400 json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
401 EXPECT_FALSE(commandDefs->empty());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700402
Vitaly Buka10206182015-08-05 11:17:43 -0700403 auto expected = R"({
404 'base': {
405 'reboot': {
406 'parameters': {
407 'delay': {
408 'minimum': 10,
409 'type': 'integer'
410 }
411 },
412 'minimalRole': 'user'
413 }
414 },
415 'robot': {
416 '_jump': {
417 'parameters': {
418 '_height': {
419 'type': 'integer'
420 }
421 },
422 'minimalRole': 'user'
423 }
424 }
425 })";
426 EXPECT_JSON_EQ(expected, *commandDefs);
427
428 base::DictionaryValue json_resp;
429 json_resp.SetString("id", test_data::kClaimTicketId);
Vitaly Buka88272d52015-11-17 17:04:01 -0800430 json_resp.SetString("kind", "weave#registrationTicket");
Vitaly Buka10206182015-08-05 11:17:43 -0700431 json_resp.SetString("oauthClientId", test_data::kClientId);
432 base::DictionaryValue* device_draft = nullptr;
433 EXPECT_TRUE(json->GetDictionary("deviceDraft", &device_draft));
434 device_draft = device_draft->DeepCopy();
435 device_draft->SetString("id", test_data::kDeviceId);
Vitaly Buka88272d52015-11-17 17:04:01 -0800436 device_draft->SetString("kind", "weave#device");
Vitaly Buka10206182015-08-05 11:17:43 -0700437 json_resp.Set("deviceDraft", device_draft);
438
Vitaly Buka74763422015-10-11 00:39:52 -0700439 callback.Run(ReplyWithJson(200, json_resp), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700440 })));
441
442 EXPECT_CALL(http_client_,
Vitaly Buka1a42e142015-10-10 18:15:15 -0700443 SendRequest(HttpClient::Method::kPost,
Vitaly Buka17280372015-10-10 17:11:47 -0700444 ticket_url + "/finalize?key=" + test_data::kApiKey,
Vitaly Buka74763422015-10-11 00:39:52 -0700445 HttpClient::Headers{}, _, _))
446 .WillOnce(WithArgs<4>(
447 Invoke([](const HttpClient::SendRequestCallback& callback) {
Vitaly Buka17280372015-10-10 17:11:47 -0700448 base::DictionaryValue json;
449 json.SetString("id", test_data::kClaimTicketId);
Vitaly Buka88272d52015-11-17 17:04:01 -0800450 json.SetString("kind", "weave#registrationTicket");
Vitaly Buka17280372015-10-10 17:11:47 -0700451 json.SetString("oauthClientId", test_data::kClientId);
452 json.SetString("userEmail", "user@email.com");
453 json.SetString("deviceDraft.id", test_data::kDeviceId);
Vitaly Buka88272d52015-11-17 17:04:01 -0800454 json.SetString("deviceDraft.kind", "weave#device");
Vitaly Buka17280372015-10-10 17:11:47 -0700455 json.SetString("deviceDraft.channel.supportedType", "xmpp");
456 json.SetString("robotAccountEmail", test_data::kRobotAccountEmail);
457 json.SetString("robotAccountAuthorizationCode",
458 test_data::kRobotAccountAuthCode);
Vitaly Buka74763422015-10-11 00:39:52 -0700459 callback.Run(ReplyWithJson(200, json), nullptr);
Vitaly Buka17280372015-10-10 17:11:47 -0700460 })));
Vitaly Buka10206182015-08-05 11:17:43 -0700461
Vitaly Buka1a42e142015-10-10 18:15:15 -0700462 EXPECT_CALL(
463 http_client_,
464 SendRequest(HttpClient::Method::kPost, dev_reg_->GetOAuthURL("token"),
Vitaly Buka74763422015-10-11 00:39:52 -0700465 HttpClient::Headers{GetFormHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700466 .WillOnce(WithArgs<3, 4>(Invoke([](
467 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700468 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka10206182015-08-05 11:17:43 -0700469 EXPECT_EQ("authorization_code", GetFormField(data, "grant_type"));
470 EXPECT_EQ(test_data::kRobotAccountAuthCode, GetFormField(data, "code"));
471 EXPECT_EQ(test_data::kClientId, GetFormField(data, "client_id"));
472 EXPECT_EQ(test_data::kClientSecret,
473 GetFormField(data, "client_secret"));
Vitaly Buka10206182015-08-05 11:17:43 -0700474 EXPECT_EQ("oob", GetFormField(data, "redirect_uri"));
Vitaly Buka10206182015-08-05 11:17:43 -0700475
476 base::DictionaryValue json;
477 json.SetString("access_token", test_data::kAccessToken);
478 json.SetString("token_type", "Bearer");
479 json.SetString("refresh_token", test_data::kRefreshToken);
480 json.SetInteger("expires_in", 3600);
481
Vitaly Buka74763422015-10-11 00:39:52 -0700482 callback.Run(ReplyWithJson(200, json), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700483 })));
484
Vitaly Buka12870bd2015-10-08 23:49:39 -0700485 bool done = false;
486 dev_reg_->RegisterDevice(
Vitaly Buka74763422015-10-11 00:39:52 -0700487 test_data::kClaimTicketId, base::Bind([this, &done](ErrorPtr error) {
488 EXPECT_FALSE(error);
Vitaly Buka12870bd2015-10-08 23:49:39 -0700489 done = true;
490 task_runner_.Break();
491 EXPECT_EQ(GcdState::kConnecting, GetGcdState());
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400492
Vitaly Buka12870bd2015-10-08 23:49:39 -0700493 // Validate the device info saved to storage...
494 EXPECT_EQ(test_data::kDeviceId, dev_reg_->GetSettings().cloud_id);
495 EXPECT_EQ(test_data::kRefreshToken,
496 dev_reg_->GetSettings().refresh_token);
497 EXPECT_EQ(test_data::kRobotAccountEmail,
498 dev_reg_->GetSettings().robot_account);
Vitaly Buka74763422015-10-11 00:39:52 -0700499 }));
Vitaly Buka12870bd2015-10-08 23:49:39 -0700500 task_runner_.Run();
501 EXPECT_TRUE(done);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700502}
503
Christopher Wileyc900e482015-02-15 15:42:04 -0800504TEST_F(DeviceRegistrationInfoTest, OOBRegistrationStatus) {
Vitaly Buka10206182015-08-05 11:17:43 -0700505 // After we've been initialized, we should be either offline or
506 // unregistered, depending on whether or not we've found credentials.
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700507 EXPECT_EQ(GcdState::kUnconfigured, GetGcdState());
Christopher Wileyc900e482015-02-15 15:42:04 -0800508 // Put some credentials into our state, make sure we call that offline.
Vitaly Bukac11a17d2015-08-15 10:36:10 -0700509 ReloadSettings();
Vitaly Bukac3c6dab2015-10-01 19:41:02 -0700510 EXPECT_EQ(GcdState::kConnecting, GetGcdState());
Christopher Wileyc900e482015-02-15 15:42:04 -0800511}
512
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700513class DeviceRegistrationInfoUpdateCommandTest
514 : public DeviceRegistrationInfoTest {
515 protected:
516 void SetUp() override {
517 DeviceRegistrationInfoTest::SetUp();
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700518
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700519 ReloadSettings();
520 SetAccessToken();
521
522 auto json_cmds = CreateDictionaryValue(R"({
523 'robot': {
524 '_jump': {
525 'parameters': {'_height': 'integer'},
526 'progress': {'progress': 'integer'},
527 'results': {'status': 'string'},
528 'minimalRole': 'user'
529 }
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700530 }
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700531 })");
532 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, nullptr));
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700533
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700534 command_url_ = dev_reg_->GetServiceURL("commands/1234");
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700535
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700536 auto commands_json = CreateValue(R"([{
537 'name':'robot._jump',
538 'id':'1234',
539 'parameters': {'_height': 100},
540 'minimalRole': 'user'
541 }])");
542 ASSERT_NE(nullptr, commands_json.get());
543 const base::ListValue* command_list = nullptr;
544 ASSERT_TRUE(commands_json->GetAsList(&command_list));
545 PublishCommands(*command_list);
546 command_ = command_manager_->FindCommand("1234");
547 ASSERT_NE(nullptr, command_);
548 }
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700549
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700550 void TearDown() override {
551 task_runner_.RunOnce();
552 DeviceRegistrationInfoTest::TearDown();
553 }
554
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700555 Command* command_{nullptr};
556 std::string command_url_;
557};
558
559TEST_F(DeviceRegistrationInfoUpdateCommandTest, SetProgress) {
Vitaly Buka74763422015-10-11 00:39:52 -0700560 EXPECT_CALL(
561 http_client_,
562 SendRequest(HttpClient::Method::kPatch, command_url_,
563 HttpClient::Headers{GetAuthHeader(), GetJsonHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700564 .WillOnce(WithArgs<3, 4>(Invoke([](
565 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700566 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka17280372015-10-10 17:11:47 -0700567 EXPECT_JSON_EQ((R"({"state":"inProgress","progress":{"progress":18}})"),
Vitaly Buka10206182015-08-05 11:17:43 -0700568 *CreateDictionaryValue(data));
569 base::DictionaryValue json;
Vitaly Buka74763422015-10-11 00:39:52 -0700570 callback.Run(ReplyWithJson(200, json), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700571 })));
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700572 EXPECT_TRUE(command_->SetProgress(*CreateDictionaryValue("{'progress':18}"),
573 nullptr));
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700574}
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700575
Vitaly Buka2f548972015-10-08 19:34:49 -0700576TEST_F(DeviceRegistrationInfoUpdateCommandTest, Complete) {
Vitaly Buka74763422015-10-11 00:39:52 -0700577 EXPECT_CALL(
578 http_client_,
579 SendRequest(HttpClient::Method::kPatch, command_url_,
580 HttpClient::Headers{GetAuthHeader(), GetJsonHeader()}, _, _))
Vitaly Bukaf0a3b222015-10-16 01:49:36 -0700581 .WillOnce(WithArgs<3, 4>(
582 Invoke([](const std::string& data,
583 const HttpClient::SendRequestCallback& callback) {
584 EXPECT_JSON_EQ(R"({"state":"done", "results":{"status":"Ok"}})",
585 *CreateDictionaryValue(data));
586 base::DictionaryValue json;
587 callback.Run(ReplyWithJson(200, json), nullptr);
588 })));
Vitaly Buka2f548972015-10-08 19:34:49 -0700589 EXPECT_TRUE(
590 command_->Complete(*CreateDictionaryValue("{'status': 'Ok'}"), nullptr));
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700591}
592
593TEST_F(DeviceRegistrationInfoUpdateCommandTest, Cancel) {
Vitaly Buka74763422015-10-11 00:39:52 -0700594 EXPECT_CALL(
595 http_client_,
596 SendRequest(HttpClient::Method::kPatch, command_url_,
597 HttpClient::Headers{GetAuthHeader(), GetJsonHeader()}, _, _))
Vitaly Buka17280372015-10-10 17:11:47 -0700598 .WillOnce(WithArgs<3, 4>(Invoke([](
599 const std::string& data,
Vitaly Buka74763422015-10-11 00:39:52 -0700600 const HttpClient::SendRequestCallback& callback) {
Vitaly Buka10206182015-08-05 11:17:43 -0700601 EXPECT_JSON_EQ(R"({"state":"cancelled"})",
602 *CreateDictionaryValue(data));
603 base::DictionaryValue json;
Vitaly Buka74763422015-10-11 00:39:52 -0700604 callback.Run(ReplyWithJson(200, json), nullptr);
Vitaly Buka10206182015-08-05 11:17:43 -0700605 })));
Vitaly Buka47a1f6f2015-10-07 18:09:57 -0700606 EXPECT_TRUE(command_->Cancel(nullptr));
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700607}
608
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700609} // namespace weave