blob: c791355d42c27ed195489ca60d8102c35ea095bb [file] [log] [blame]
Alex Vakulenko8e34d392014-04-29 11:02:56 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Deymof6cbe322014-11-10 19:55:35 -08005#include "buffet/device_registration_info.h"
6
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>
Alex Vakulenkocf0b33a2014-08-20 15:02:10 -070010#include <chromeos/bind_lambda.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070011#include <chromeos/http/http_request.h>
12#include <chromeos/http/http_transport_fake.h>
Anton Muhin332df192014-11-22 05:59:14 +040013#include <chromeos/key_value_store.h>
Alex Vakulenko3aeea1c2014-08-20 16:33:12 -070014#include <chromeos/mime_utils.h>
Alex Vakulenko8e34d392014-04-29 11:02:56 -070015#include <gtest/gtest.h>
16
Alex Vakulenko1f30a622014-07-23 11:13:15 -070017#include "buffet/commands/command_manager.h"
Alex Vakulenko45109442014-07-29 11:07:10 -070018#include "buffet/commands/unittest_utils.h"
Alex Vakulenko57123b22014-10-28 13:50:16 -070019#include "buffet/states/mock_state_change_queue_interface.h"
Alex Vakulenko07216fe2014-09-19 15:31:09 -070020#include "buffet/states/state_manager.h"
Christopher Wiley006e94e2014-05-02 13:44:48 -070021#include "buffet/storage_impls.h"
Alex Vakulenko8e34d392014-04-29 11:02:56 -070022
Vitaly Buka32005de2015-05-01 12:33:31 -070023namespace buffet {
24
Alex Vakulenkocca20932014-08-20 17:35:12 -070025using chromeos::http::request_header::kAuthorization;
26using chromeos::http::fake::ServerRequest;
27using chromeos::http::fake::ServerResponse;
28
Alex Vakulenko8e34d392014-04-29 11:02:56 -070029namespace {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070030
31namespace test_data {
32
33const char kServiceURL[] = "http://gcd.server.com/";
34const char kOAuthURL[] = "http://oauth.server.com/";
35const char kApiKey[] = "GOadRdTf9FERf0k4w6EFOof56fUJ3kFDdFL3d7f";
36const char kClientId[] = "123543821385-sfjkjshdkjhfk234sdfsdfkskd"
37 "fkjh7f.apps.googleusercontent.com";
38const char kClientSecret[] = "5sdGdGlfolGlrFKfdFlgP6FG";
39const char kDeviceId[] = "4a7ea2d1-b331-1e1f-b206-e863c7635196";
40const char kClaimTicketId[] = "RTcUE";
41const char kAccessToken[] = "ya29.1.AADtN_V-dLUM-sVZ0qVjG9Dxm5NgdS9J"
42 "Mx_JLUqhC9bED_YFjzHZtYt65ZzXCS35NMAeaVZ"
43 "Dei530-w0yE2urpQ";
44const char kRefreshToken[] = "1/zQmxR6PKNvhcxf9SjXUrCjcmCrcqRKXctc6cp"
45 "1nI-GQ";
46const char kRobotAccountAuthCode[] = "4/Mf_ujEhPejVhOq-OxW9F5cSOnWzx."
47 "YgciVjTYGscRshQV0ieZDAqiTIjMigI";
48const char kRobotAccountEmail[] = "6ed0b3f54f9bd619b942f4ad2441c252@"
49 "clouddevices.gserviceaccount.com";
50const char kUserAccountAuthCode[] = "2/sd_GD1TGFKpJOLJ34-0g5fK0fflp.GlT"
51 "I0F5g7hNtFgj5HFGOf8FlGK9eflO";
52const char kUserAccessToken[] = "sd56.4.FGDjG_F-gFGF-dFG6gGOG9Dxm5NgdS9"
53 "JMx_JLUqhC9bED_YFjLKjlkjLKJlkjLKjlKJea"
54 "VZDei530-w0yE2urpQ";
55const char kUserRefreshToken[] = "1/zQLKjlKJlkLkLKjLkjLKjLkjLjLkjl0ftc6"
56 "cp1nI-GQ";
Alex Vakulenko8e34d392014-04-29 11:02:56 -070057} // namespace test_data
58
Alex Vakulenko8e34d392014-04-29 11:02:56 -070059// Add the test device registration information.
60void SetDefaultDeviceRegistration(base::DictionaryValue* data) {
Vitaly Bukacad2e332015-05-14 23:33:32 -070061 data->SetString("refresh_token", test_data::kRefreshToken);
62 data->SetString("device_id", test_data::kDeviceId);
63 data->SetString("robot_account", test_data::kRobotAccountEmail);
Alex Vakulenko8e34d392014-04-29 11:02:56 -070064}
65
Alex Vakulenkocca20932014-08-20 17:35:12 -070066void OAuth2Handler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070067 base::DictionaryValue json;
68 if (request.GetFormField("grant_type") == "refresh_token") {
69 // Refresh device access token.
70 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
71 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
72 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
73 json.SetString("access_token", test_data::kAccessToken);
74 } else if (request.GetFormField("grant_type") == "authorization_code") {
75 // Obtain access token.
76 std::string code = request.GetFormField("code");
77 if (code == test_data::kUserAccountAuthCode) {
78 // Get user access token.
79 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
80 EXPECT_EQ(test_data::kClientSecret,
81 request.GetFormField("client_secret"));
82 EXPECT_EQ("urn:ietf:wg:oauth:2.0:oob",
83 request.GetFormField("redirect_uri"));
84 json.SetString("access_token", test_data::kUserAccessToken);
85 json.SetString("token_type", "Bearer");
86 json.SetString("refresh_token", test_data::kUserRefreshToken);
87 } else if (code == test_data::kRobotAccountAuthCode) {
88 // Get device access token.
89 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
90 EXPECT_EQ(test_data::kClientSecret,
91 request.GetFormField("client_secret"));
92 EXPECT_EQ("oob", request.GetFormField("redirect_uri"));
93 EXPECT_EQ("https://www.googleapis.com/auth/clouddevices",
94 request.GetFormField("scope"));
95 json.SetString("access_token", test_data::kAccessToken);
96 json.SetString("token_type", "Bearer");
97 json.SetString("refresh_token", test_data::kRefreshToken);
98 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -070099 FAIL() << "Unexpected authorization code";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700100 }
101 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700102 FAIL() << "Unexpected grant type";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700103 }
104 json.SetInteger("expires_in", 3600);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700105 response->ReplyJson(chromeos::http::status_code::Ok, &json);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700106}
107
Nathan Bullock24d189f2015-02-26 13:09:18 -0500108void OAuth2HandlerFail(const ServerRequest& request,
109 ServerResponse* response) {
110 base::DictionaryValue json;
111 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
112 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
113 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
114 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
115 json.SetString("error", "unable_to_authenticate");
116 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
117}
118
119void OAuth2HandlerDeregister(const ServerRequest& request,
120 ServerResponse* response) {
121 base::DictionaryValue json;
122 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
123 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
124 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
125 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
126 json.SetString("error", "invalid_grant");
127 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
128}
129
Alex Vakulenkocca20932014-08-20 17:35:12 -0700130void DeviceInfoHandler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700131 std::string auth = "Bearer ";
132 auth += test_data::kAccessToken;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700133 EXPECT_EQ(auth,
134 request.GetHeader(chromeos::http::request_header::kAuthorization));
135 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700136 {"channel.supportedType", "xmpp"},
137 {"deviceKind", "vendor"},
138 {"id", test_data::kDeviceId},
139 {"kind", "clouddevices#device"},
140 });
141}
142
Alex Vakulenkocca20932014-08-20 17:35:12 -0700143void FinalizeTicketHandler(const ServerRequest& request,
144 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700145 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
146 EXPECT_TRUE(request.GetData().empty());
147
Alex Vakulenkocca20932014-08-20 17:35:12 -0700148 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700149 {"id", test_data::kClaimTicketId},
150 {"kind", "clouddevices#registrationTicket"},
151 {"oauthClientId", test_data::kClientId},
152 {"userEmail", "user@email.com"},
153 {"deviceDraft.id", test_data::kDeviceId},
154 {"deviceDraft.kind", "clouddevices#device"},
155 {"deviceDraft.channel.supportedType", "xmpp"},
156 {"robotAccountEmail", test_data::kRobotAccountEmail},
157 {"robotAccountAuthorizationCode", test_data::kRobotAccountAuthCode},
158 });
159}
160
161} // anonymous namespace
162
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700163class DeviceRegistrationInfoTest : public ::testing::Test {
164 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -0700165 void SetUp() override {
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700166 std::unique_ptr<StorageInterface> storage{new MemStorage};
167 storage_ = storage.get();
168 storage->Save(data_);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700169 transport_ = std::make_shared<chromeos::http::fake::Transport>();
Vitaly Bukaae0f3a12015-05-11 16:27:30 -0700170 command_manager_ = std::make_shared<CommandManager>();
Alex Vakulenko57123b22014-10-28 13:50:16 -0700171 state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700172
173 std::unique_ptr<BuffetConfig> config{new BuffetConfig{std::move(storage)}};
174 config_ = config.get();
175 dev_reg_ = std::unique_ptr<DeviceRegistrationInfo>(
176 new DeviceRegistrationInfo(command_manager_, state_manager_,
177 std::move(config), transport_, true));
178
179 ReloadConfig();
180 }
181
182 void ReloadConfig() {
Christopher Wiley583d64b2015-03-24 14:30:17 -0700183 chromeos::KeyValueStore config_store;
184 config_store.SetString("client_id", test_data::kClientId);
185 config_store.SetString("client_secret", test_data::kClientSecret);
186 config_store.SetString("api_key", test_data::kApiKey);
187 config_store.SetString("device_kind", "vendor");
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700188 config_store.SetString("name", "Coffee Pot");
Vitaly Buka867b0882015-04-16 10:03:26 -0700189 config_store.SetString("description", "Easy to clean");
190 config_store.SetString("location", "Kitchen");
Vitaly Buka4a3a9a22015-05-13 16:06:01 -0700191 config_store.SetString("local_anonymous_access_role", "viewer");
Vitaly Buka867b0882015-04-16 10:03:26 -0700192 config_store.SetString("model_id", "AAAAA");
Christopher Wiley583d64b2015-03-24 14:30:17 -0700193 config_store.SetString("oauth_url", test_data::kOAuthURL);
194 config_store.SetString("service_url", test_data::kServiceURL);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700195 config_->Load(config_store);
196 dev_reg_->Start();
197 }
198
199 void PublishCommands(const base::ListValue& commands) {
200 return dev_reg_->PublishCommands(commands);
201 }
202
203 bool CheckRegistration(chromeos::ErrorPtr* error) const {
204 return dev_reg_->CheckRegistration(error);
205 }
206
207 RegistrationStatus GetRegistrationStatus() const {
208 return dev_reg_->registration_status_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700209 }
210
Alex Vakulenko45109442014-07-29 11:07:10 -0700211 base::DictionaryValue data_;
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700212 StorageInterface* storage_{nullptr};
213 BuffetConfig* config_{nullptr};
Alex Vakulenkocca20932014-08-20 17:35:12 -0700214 std::shared_ptr<chromeos::http::fake::Transport> transport_;
Alex Vakulenko45109442014-07-29 11:07:10 -0700215 std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
216 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko57123b22014-10-28 13:50:16 -0700217 testing::NiceMock<MockStateChangeQueueInterface> mock_state_change_queue_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700218 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700219};
220
221////////////////////////////////////////////////////////////////////////////////
222TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700223 EXPECT_EQ(test_data::kServiceURL, dev_reg_->GetServiceURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700224 std::string url = test_data::kServiceURL;
225 url += "registrationTickets";
Alex Vakulenko45109442014-07-29 11:07:10 -0700226 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets"));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700227 url += "?key=";
228 url += test_data::kApiKey;
Alex Vakulenko45109442014-07-29 11:07:10 -0700229 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700230 {"key", test_data::kApiKey}
231 }));
232 url += "&restart=true";
Alex Vakulenko45109442014-07-29 11:07:10 -0700233 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700234 {"key", test_data::kApiKey},
235 {"restart", "true"},
236 }));
237}
238
239TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700240 EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700241 std::string url = test_data::kOAuthURL;
242 url += "auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fclouddevices&";
243 url += "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
244 url += "response_type=code&";
245 url += "client_id=";
246 url += test_data::kClientId;
Alex Vakulenko45109442014-07-29 11:07:10 -0700247 EXPECT_EQ(url, dev_reg_->GetOAuthURL("auth", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700248 {"scope", "https://www.googleapis.com/auth/clouddevices"},
249 {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
250 {"response_type", "code"},
251 {"client_id", test_data::kClientId}
252 }));
253}
254
255TEST_F(DeviceRegistrationInfoTest, CheckRegistration) {
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700256 EXPECT_FALSE(CheckRegistration(nullptr));
Alex Vakulenko45109442014-07-29 11:07:10 -0700257 EXPECT_EQ(0, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700258
Alex Vakulenko45109442014-07-29 11:07:10 -0700259 SetDefaultDeviceRegistration(&data_);
Vitaly Buka56363222015-05-13 15:09:21 -0700260 storage_->Save(data_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700261 ReloadConfig();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700262
Alex Vakulenkocca20932014-08-20 17:35:12 -0700263 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
264 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700265 base::Bind(OAuth2Handler));
266 transport_->ResetRequestCount();
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700267 EXPECT_TRUE(CheckRegistration(nullptr));
Alex Vakulenko45109442014-07-29 11:07:10 -0700268 EXPECT_EQ(1, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700269}
270
Nathan Bullock24d189f2015-02-26 13:09:18 -0500271TEST_F(DeviceRegistrationInfoTest, CheckAuthenticationFailure) {
272 SetDefaultDeviceRegistration(&data_);
Vitaly Buka56363222015-05-13 15:09:21 -0700273 storage_->Save(data_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700274 ReloadConfig();
275 EXPECT_EQ(RegistrationStatus::kConnecting, GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500276
277 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
278 chromeos::http::request_type::kPost,
279 base::Bind(OAuth2HandlerFail));
280 transport_->ResetRequestCount();
281 chromeos::ErrorPtr error;
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700282 EXPECT_FALSE(CheckRegistration(&error));
Nathan Bullock24d189f2015-02-26 13:09:18 -0500283 EXPECT_EQ(1, transport_->GetRequestCount());
Vitaly Buka32005de2015-05-01 12:33:31 -0700284 EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "unable_to_authenticate"));
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700285 EXPECT_EQ(RegistrationStatus::kConnecting, GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500286}
287
288TEST_F(DeviceRegistrationInfoTest, CheckDeregistration) {
289 SetDefaultDeviceRegistration(&data_);
Vitaly Buka56363222015-05-13 15:09:21 -0700290 storage_->Save(data_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700291 ReloadConfig();
292 EXPECT_EQ(RegistrationStatus::kConnecting, GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500293
294 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
295 chromeos::http::request_type::kPost,
296 base::Bind(OAuth2HandlerDeregister));
297 transport_->ResetRequestCount();
298 chromeos::ErrorPtr error;
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700299 EXPECT_FALSE(CheckRegistration(&error));
Nathan Bullock24d189f2015-02-26 13:09:18 -0500300 EXPECT_EQ(1, transport_->GetRequestCount());
Vitaly Buka32005de2015-05-01 12:33:31 -0700301 EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "invalid_grant"));
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700302 EXPECT_EQ(RegistrationStatus::kInvalidCredentials, GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500303}
304
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700305TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700306 SetDefaultDeviceRegistration(&data_);
Vitaly Buka56363222015-05-13 15:09:21 -0700307 storage_->Save(data_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700308 ReloadConfig();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700309
Alex Vakulenkocca20932014-08-20 17:35:12 -0700310 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
311 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700312 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700313 transport_->AddHandler(dev_reg_->GetDeviceURL(),
314 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700315 base::Bind(DeviceInfoHandler));
316 transport_->ResetRequestCount();
317 auto device_info = dev_reg_->GetDeviceInfo(nullptr);
318 EXPECT_EQ(2, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700319 EXPECT_NE(nullptr, device_info.get());
320 base::DictionaryValue* dict = nullptr;
321 EXPECT_TRUE(device_info->GetAsDictionary(&dict));
322 std::string id;
323 EXPECT_TRUE(dict->GetString("id", &id));
324 EXPECT_EQ(test_data::kDeviceId, id);
325}
326
327TEST_F(DeviceRegistrationInfoTest, GetDeviceId) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700328 SetDefaultDeviceRegistration(&data_);
Vitaly Buka56363222015-05-13 15:09:21 -0700329 storage_->Save(data_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700330 ReloadConfig();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700331
Alex Vakulenkocca20932014-08-20 17:35:12 -0700332 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
333 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700334 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700335 transport_->AddHandler(dev_reg_->GetDeviceURL(),
336 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700337 base::Bind(DeviceInfoHandler));
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700338 EXPECT_EQ(test_data::kDeviceId, config_->device_id());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700339}
340
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400341TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
Anton Muhina4803142014-09-24 19:30:45 +0400342 auto update_ticket = [](const ServerRequest& request,
Alex Vakulenkocca20932014-08-20 17:35:12 -0700343 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700344 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
345 auto json = request.GetDataAsJson();
346 EXPECT_NE(nullptr, json.get());
347 std::string value;
Anton Muhina4803142014-09-24 19:30:45 +0400348 EXPECT_TRUE(json->GetString("id", &value));
349 EXPECT_EQ(test_data::kClaimTicketId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700350 EXPECT_TRUE(json->GetString("deviceDraft.channel.supportedType", &value));
Alex Vakulenkod05725f2015-05-27 15:48:19 -0700351 EXPECT_EQ("pull", value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700352 EXPECT_TRUE(json->GetString("oauthClientId", &value));
353 EXPECT_EQ(test_data::kClientId, value);
354 EXPECT_TRUE(json->GetString("deviceDraft.deviceKind", &value));
355 EXPECT_EQ("vendor", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800356 EXPECT_TRUE(json->GetString("deviceDraft.description", &value));
357 EXPECT_EQ("Easy to clean", value);
358 EXPECT_TRUE(json->GetString("deviceDraft.location", &value));
359 EXPECT_EQ("Kitchen", value);
Vitaly Buka6522ab62015-02-19 10:26:31 -0800360 EXPECT_TRUE(json->GetString("deviceDraft.modelManifestId", &value));
Vitaly Buka867b0882015-04-16 10:03:26 -0700361 EXPECT_EQ("AAAAA", value);
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700362 EXPECT_TRUE(json->GetString("deviceDraft.name", &value));
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800363 EXPECT_EQ("Coffee Pot", value);
Alex Vakulenko45109442014-07-29 11:07:10 -0700364 base::DictionaryValue* commandDefs = nullptr;
365 EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
366 EXPECT_FALSE(commandDefs->empty());
Vitaly Buka7c82d292015-05-03 18:08:12 -0700367
368 auto expected = R"({
369 'base': {
370 'reboot': {
371 'parameters': {
372 'delay': {
373 'minimum': 10,
374 'type': 'integer'
375 }
Vitaly Buka6fed0532015-05-14 16:57:23 -0700376 },
377 'minimalRole': 'user'
Vitaly Buka7c82d292015-05-03 18:08:12 -0700378 }
379 },
380 'robot': {
381 '_jump': {
382 'parameters': {
383 '_height': {
384 'type': 'integer'
385 }
Vitaly Buka6fed0532015-05-14 16:57:23 -0700386 },
387 'minimalRole': 'user'
Vitaly Buka7c82d292015-05-03 18:08:12 -0700388 }
389 }
390 })";
391 EXPECT_JSON_EQ(expected, *commandDefs);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700392
393 base::DictionaryValue json_resp;
394 json_resp.SetString("id", test_data::kClaimTicketId);
395 json_resp.SetString("kind", "clouddevices#registrationTicket");
396 json_resp.SetString("oauthClientId", test_data::kClientId);
397 base::DictionaryValue* device_draft = nullptr;
398 EXPECT_TRUE(json->GetDictionary("deviceDraft", &device_draft));
399 device_draft = device_draft->DeepCopy();
400 device_draft->SetString("id", test_data::kDeviceId);
401 device_draft->SetString("kind", "clouddevices#device");
402 json_resp.Set("deviceDraft", device_draft);
403
Alex Vakulenkocca20932014-08-20 17:35:12 -0700404 response->ReplyJson(chromeos::http::status_code::Ok, &json_resp);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700405 };
406
Vitaly Buka32005de2015-05-01 12:33:31 -0700407 auto json_base = unittests::CreateDictionaryValue(R"({
Alex Vakulenko45109442014-07-29 11:07:10 -0700408 'base': {
409 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400410 'parameters': {'delay': 'integer'},
Vitaly Buka6fed0532015-05-14 16:57:23 -0700411 'minimalRole': 'user',
Anton Muhin71fb9d52014-11-21 22:22:39 +0400412 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700413 },
414 'shutdown': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400415 'parameters': {},
Vitaly Buka6fed0532015-05-14 16:57:23 -0700416 'minimalRole': 'user',
Anton Muhin71fb9d52014-11-21 22:22:39 +0400417 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700418 }
419 }
420 })");
421 EXPECT_TRUE(command_manager_->LoadBaseCommands(*json_base, nullptr));
Vitaly Buka32005de2015-05-01 12:33:31 -0700422 auto json_cmds = unittests::CreateDictionaryValue(R"({
Alex Vakulenko45109442014-07-29 11:07:10 -0700423 'base': {
424 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400425 'parameters': {'delay': {'minimum': 10}},
Vitaly Buka6fed0532015-05-14 16:57:23 -0700426 'minimalRole': 'user',
Anton Muhin71fb9d52014-11-21 22:22:39 +0400427 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700428 }
429 },
430 'robot': {
431 '_jump': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400432 'parameters': {'_height': 'integer'},
Vitaly Buka6fed0532015-05-14 16:57:23 -0700433 'minimalRole': 'user',
Anton Muhin71fb9d52014-11-21 22:22:39 +0400434 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700435 }
436 }
437 })");
438 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
439
Anton Muhina4803142014-09-24 19:30:45 +0400440 transport_->AddHandler(dev_reg_->GetServiceURL(
441 std::string("registrationTickets/") + test_data::kClaimTicketId),
442 chromeos::http::request_type::kPatch,
443 base::Bind(update_ticket));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700444 std::string ticket_url =
Alex Vakulenko45109442014-07-29 11:07:10 -0700445 dev_reg_->GetServiceURL("registrationTickets/" +
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700446 std::string(test_data::kClaimTicketId));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700447 transport_->AddHandler(ticket_url + "/finalize",
448 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700449 base::Bind(FinalizeTicketHandler));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700450
Alex Vakulenkocca20932014-08-20 17:35:12 -0700451 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
452 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700453 base::Bind(OAuth2Handler));
Vitaly Bukacad2e332015-05-14 23:33:32 -0700454 std::string device_id =
455 dev_reg_->RegisterDevice(test_data::kClaimTicketId, nullptr);
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400456
457 EXPECT_EQ(test_data::kDeviceId, device_id);
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400458 EXPECT_EQ(3, transport_->GetRequestCount());
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700459 EXPECT_EQ(RegistrationStatus::kConnecting, GetRegistrationStatus());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700460
461 // Validate the device info saved to storage...
Alex Vakulenko45109442014-07-29 11:07:10 -0700462 auto storage_data = storage_->Load();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700463 base::DictionaryValue* dict = nullptr;
464 EXPECT_TRUE(storage_data->GetAsDictionary(&dict));
465 std::string value;
Vitaly Bukacad2e332015-05-14 23:33:32 -0700466 EXPECT_TRUE(dict->GetString("device_id", &value));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700467 EXPECT_EQ(test_data::kDeviceId, value);
Vitaly Bukacad2e332015-05-14 23:33:32 -0700468 EXPECT_TRUE(dict->GetString("refresh_token", &value));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700469 EXPECT_EQ(test_data::kRefreshToken, value);
Vitaly Bukacad2e332015-05-14 23:33:32 -0700470 EXPECT_TRUE(dict->GetString("robot_account", &value));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700471 EXPECT_EQ(test_data::kRobotAccountEmail, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700472}
473
Christopher Wileyc900e482015-02-15 15:42:04 -0800474TEST_F(DeviceRegistrationInfoTest, OOBRegistrationStatus) {
475 // After we've been initialized, we should be either offline or unregistered,
476 // depending on whether or not we've found credentials.
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700477 EXPECT_EQ(RegistrationStatus::kUnconfigured, GetRegistrationStatus());
Christopher Wileyc900e482015-02-15 15:42:04 -0800478 // Put some credentials into our state, make sure we call that offline.
479 SetDefaultDeviceRegistration(&data_);
Vitaly Buka56363222015-05-13 15:09:21 -0700480 storage_->Save(data_);
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700481 ReloadConfig();
482 EXPECT_EQ(RegistrationStatus::kConnecting, GetRegistrationStatus());
Christopher Wileyc900e482015-02-15 15:42:04 -0800483}
484
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700485TEST_F(DeviceRegistrationInfoTest, UpdateCommand) {
Vitaly Buka32005de2015-05-01 12:33:31 -0700486 auto json_cmds = unittests::CreateDictionaryValue(R"({
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700487 'robot': {
488 '_jump': {
489 'parameters': {'_height': 'integer'},
Vitaly Buka6fed0532015-05-14 16:57:23 -0700490 'results': {'status': 'string'},
491 'minimalRole': 'user'
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700492 }
493 }
494 })");
495 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
496
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700497 const std::string command_url = dev_reg_->GetServiceURL("commands/1234");
498
Vitaly Buka32005de2015-05-01 12:33:31 -0700499 auto commands_json = unittests::CreateValue(R"([{
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700500 'name':'robot._jump',
501 'id':'1234',
Vitaly Buka6fed0532015-05-14 16:57:23 -0700502 'parameters': {'_height': 100},
503 'minimalRole': 'user'
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700504 }])");
505 ASSERT_NE(nullptr, commands_json.get());
506 const base::ListValue* command_list = nullptr;
507 ASSERT_TRUE(commands_json->GetAsList(&command_list));
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700508 PublishCommands(*command_list);
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700509 auto command = command_manager_->FindCommand("1234");
510 ASSERT_NE(nullptr, command);
511 StringPropType string_type;
512 native_types::Object results{
513 {"status", string_type.CreateValue(std::string{"Ok"}, nullptr)}
514 };
515
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700516 // UpdateCommand when setting command results.
517 auto update_command_results = [](const ServerRequest& request,
518 ServerResponse* response) {
519 EXPECT_EQ(R"({"results":{"status":"Ok"}})",
520 request.GetDataAsNormalizedJsonString());
Alex Vakulenkob211c102015-04-21 11:43:23 -0700521 response->ReplyJson(chromeos::http::status_code::Ok,
522 chromeos::http::FormFieldList{});
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700523 };
524
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700525 transport_->AddHandler(command_url,
526 chromeos::http::request_type::kPatch,
527 base::Bind(update_command_results));
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700528
529 command->SetResults(results);
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700530
531 // UpdateCommand when setting command progress.
532 int count = 0; // This will be called twice...
533 auto update_command_progress = [&count](const ServerRequest& request,
534 ServerResponse* response) {
535 if (count++ == 0) {
536 EXPECT_EQ(R"({"state":"inProgress"})",
537 request.GetDataAsNormalizedJsonString());
538 } else {
539 EXPECT_EQ(R"({"progress":{"progress":18}})",
540 request.GetDataAsNormalizedJsonString());
541 }
Alex Vakulenkob211c102015-04-21 11:43:23 -0700542 response->ReplyJson(chromeos::http::status_code::Ok,
543 chromeos::http::FormFieldList{});
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700544 };
545
546 transport_->AddHandler(command_url,
547 chromeos::http::request_type::kPatch,
548 base::Bind(update_command_progress));
549
Vitaly Buka4129dfa2015-04-29 12:16:58 -0700550 native_types::Object progress{
551 {"progress", unittests::make_int_prop_value(18)}};
552 command->SetProgress(progress);
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700553
554 // UpdateCommand when changing command status.
555 auto update_command_state = [](const ServerRequest& request,
556 ServerResponse* response) {
557 EXPECT_EQ(R"({"state":"cancelled"})",
558 request.GetDataAsNormalizedJsonString());
Alex Vakulenkob211c102015-04-21 11:43:23 -0700559 response->ReplyJson(chromeos::http::status_code::Ok,
560 chromeos::http::FormFieldList{});
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700561 };
562
563 transport_->AddHandler(command_url,
564 chromeos::http::request_type::kPatch,
565 base::Bind(update_command_state));
566
567 command->Cancel();
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700568}
569
570
Alex Vakulenkocca20932014-08-20 17:35:12 -0700571} // namespace buffet