blob: dfb61cc8c4e0bba5cb65080ddd262b4c6ce2cd44 [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>
8#include <base/values.h>
Alex Vakulenkocf0b33a2014-08-20 15:02:10 -07009#include <chromeos/bind_lambda.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070010#include <chromeos/http/http_request.h>
11#include <chromeos/http/http_transport_fake.h>
Anton Muhin332df192014-11-22 05:59:14 +040012#include <chromeos/key_value_store.h>
Alex Vakulenko3aeea1c2014-08-20 16:33:12 -070013#include <chromeos/mime_utils.h>
Alex Vakulenko8e34d392014-04-29 11:02:56 -070014#include <gtest/gtest.h>
15
Alex Vakulenko1f30a622014-07-23 11:13:15 -070016#include "buffet/commands/command_manager.h"
Alex Vakulenko45109442014-07-29 11:07:10 -070017#include "buffet/commands/unittest_utils.h"
Alex Vakulenko8e34d392014-04-29 11:02:56 -070018#include "buffet/device_registration_storage_keys.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
Alex Vakulenkocca20932014-08-20 17:35:12 -070023using chromeos::http::request_header::kAuthorization;
24using chromeos::http::fake::ServerRequest;
25using chromeos::http::fake::ServerResponse;
26
27namespace buffet {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070028
29namespace {
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";
57
58} // namespace test_data
59
60// Fill in the storage with default environment information (URLs, etc).
61void InitDefaultStorage(base::DictionaryValue* data) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070062 data->SetString(storage_keys::kRefreshToken, "");
63 data->SetString(storage_keys::kDeviceId, "");
Alex Vakulenko8e34d392014-04-29 11:02:56 -070064 data->SetString(storage_keys::kRobotAccount, "");
Nathan Bullock02ca28b2015-02-11 16:22:16 -050065 data->SetString(storage_keys::kDisplayName, "");
66 data->SetString(storage_keys::kDescription, "");
67 data->SetString(storage_keys::kLocation, "");
Alex Vakulenko8e34d392014-04-29 11:02:56 -070068}
69
70// Add the test device registration information.
71void SetDefaultDeviceRegistration(base::DictionaryValue* data) {
72 data->SetString(storage_keys::kRefreshToken, test_data::kRefreshToken);
73 data->SetString(storage_keys::kDeviceId, test_data::kDeviceId);
74 data->SetString(storage_keys::kRobotAccount, test_data::kRobotAccountEmail);
75}
76
Alex Vakulenkocca20932014-08-20 17:35:12 -070077void OAuth2Handler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070078 base::DictionaryValue json;
79 if (request.GetFormField("grant_type") == "refresh_token") {
80 // Refresh device access token.
81 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
82 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
83 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
84 json.SetString("access_token", test_data::kAccessToken);
85 } else if (request.GetFormField("grant_type") == "authorization_code") {
86 // Obtain access token.
87 std::string code = request.GetFormField("code");
88 if (code == test_data::kUserAccountAuthCode) {
89 // Get user access token.
90 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
91 EXPECT_EQ(test_data::kClientSecret,
92 request.GetFormField("client_secret"));
93 EXPECT_EQ("urn:ietf:wg:oauth:2.0:oob",
94 request.GetFormField("redirect_uri"));
95 json.SetString("access_token", test_data::kUserAccessToken);
96 json.SetString("token_type", "Bearer");
97 json.SetString("refresh_token", test_data::kUserRefreshToken);
98 } else if (code == test_data::kRobotAccountAuthCode) {
99 // Get device access token.
100 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
101 EXPECT_EQ(test_data::kClientSecret,
102 request.GetFormField("client_secret"));
103 EXPECT_EQ("oob", request.GetFormField("redirect_uri"));
104 EXPECT_EQ("https://www.googleapis.com/auth/clouddevices",
105 request.GetFormField("scope"));
106 json.SetString("access_token", test_data::kAccessToken);
107 json.SetString("token_type", "Bearer");
108 json.SetString("refresh_token", test_data::kRefreshToken);
109 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700110 FAIL() << "Unexpected authorization code";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700111 }
112 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700113 FAIL() << "Unexpected grant type";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700114 }
115 json.SetInteger("expires_in", 3600);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700116 response->ReplyJson(chromeos::http::status_code::Ok, &json);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700117}
118
Nathan Bullock24d189f2015-02-26 13:09:18 -0500119void OAuth2HandlerFail(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", "unable_to_authenticate");
127 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
128}
129
130void OAuth2HandlerDeregister(const ServerRequest& request,
131 ServerResponse* response) {
132 base::DictionaryValue json;
133 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
134 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
135 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
136 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
137 json.SetString("error", "invalid_grant");
138 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
139}
140
Alex Vakulenkocca20932014-08-20 17:35:12 -0700141void DeviceInfoHandler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700142 std::string auth = "Bearer ";
143 auth += test_data::kAccessToken;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700144 EXPECT_EQ(auth,
145 request.GetHeader(chromeos::http::request_header::kAuthorization));
146 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700147 {"channel.supportedType", "xmpp"},
148 {"deviceKind", "vendor"},
149 {"id", test_data::kDeviceId},
150 {"kind", "clouddevices#device"},
151 });
152}
153
Alex Vakulenkocca20932014-08-20 17:35:12 -0700154void FinalizeTicketHandler(const ServerRequest& request,
155 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700156 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
157 EXPECT_TRUE(request.GetData().empty());
158
Alex Vakulenkocca20932014-08-20 17:35:12 -0700159 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700160 {"id", test_data::kClaimTicketId},
161 {"kind", "clouddevices#registrationTicket"},
162 {"oauthClientId", test_data::kClientId},
163 {"userEmail", "user@email.com"},
164 {"deviceDraft.id", test_data::kDeviceId},
165 {"deviceDraft.kind", "clouddevices#device"},
166 {"deviceDraft.channel.supportedType", "xmpp"},
167 {"robotAccountEmail", test_data::kRobotAccountEmail},
168 {"robotAccountAuthorizationCode", test_data::kRobotAccountAuthCode},
169 });
170}
171
172} // anonymous namespace
173
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500174// This is a helper class that allows the unit tests to access private
175// methods and data since TestHelper is declared as a friend to
176// DeviceRegistrationInfo.
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700177class DeviceRegistrationInfo::TestHelper {
178 public:
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500179 static bool Save(DeviceRegistrationInfo* info) {
180 return info->Save();
181 }
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700182};
183
184class DeviceRegistrationInfoTest : public ::testing::Test {
185 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -0700186 void SetUp() override {
Alex Vakulenko45109442014-07-29 11:07:10 -0700187 InitDefaultStorage(&data_);
188 storage_ = std::make_shared<MemStorage>();
189 storage_->Save(&data_);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700190 transport_ = std::make_shared<chromeos::http::fake::Transport>();
Alex Vakulenko45109442014-07-29 11:07:10 -0700191 command_manager_ = std::make_shared<CommandManager>();
Alex Vakulenko57123b22014-10-28 13:50:16 -0700192 state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
Christopher Wiley583d64b2015-03-24 14:30:17 -0700193 chromeos::KeyValueStore config_store;
194 config_store.SetString("client_id", test_data::kClientId);
195 config_store.SetString("client_secret", test_data::kClientSecret);
196 config_store.SetString("api_key", test_data::kApiKey);
197 config_store.SetString("device_kind", "vendor");
198 config_store.SetString("name", "coffee_pot");
199 config_store.SetString("default_display_name", "Coffee Pot");
200 config_store.SetString("default_description", "Easy to clean");
201 config_store.SetString("default_location", "Kitchen");
202 config_store.SetString("model_id", "AAA");
203 config_store.SetString("oauth_url", test_data::kOAuthURL);
204 config_store.SetString("service_url", test_data::kServiceURL);
205 std::unique_ptr<BuffetConfig> config{new BuffetConfig};
206 config->Load(config_store);
Christopher Wileyc900e482015-02-15 15:42:04 -0800207 auto mock_callback = base::Bind(
208 &DeviceRegistrationInfoTest::OnRegistrationStatusChange,
209 base::Unretained(this));
Alex Vakulenko45109442014-07-29 11:07:10 -0700210 dev_reg_ = std::unique_ptr<DeviceRegistrationInfo>(
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700211 new DeviceRegistrationInfo(command_manager_, state_manager_,
Christopher Wiley583d64b2015-03-24 14:30:17 -0700212 std::move(config),
Christopher Wileyc900e482015-02-15 15:42:04 -0800213 transport_, storage_,
214 mock_callback));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700215 }
216
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700217 MOCK_METHOD0(OnRegistrationStatusChange, void());
Christopher Wileyc900e482015-02-15 15:42:04 -0800218
Alex Vakulenko45109442014-07-29 11:07:10 -0700219 base::DictionaryValue data_;
220 std::shared_ptr<MemStorage> storage_;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700221 std::shared_ptr<chromeos::http::fake::Transport> transport_;
Alex Vakulenko45109442014-07-29 11:07:10 -0700222 std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
223 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko57123b22014-10-28 13:50:16 -0700224 testing::NiceMock<MockStateChangeQueueInterface> mock_state_change_queue_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700225 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700226};
227
228////////////////////////////////////////////////////////////////////////////////
229TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700230 EXPECT_TRUE(dev_reg_->Load());
231 EXPECT_EQ(test_data::kServiceURL, dev_reg_->GetServiceURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700232 std::string url = test_data::kServiceURL;
233 url += "registrationTickets";
Alex Vakulenko45109442014-07-29 11:07:10 -0700234 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets"));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700235 url += "?key=";
236 url += test_data::kApiKey;
Alex Vakulenko45109442014-07-29 11:07:10 -0700237 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700238 {"key", test_data::kApiKey}
239 }));
240 url += "&restart=true";
Alex Vakulenko45109442014-07-29 11:07:10 -0700241 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700242 {"key", test_data::kApiKey},
243 {"restart", "true"},
244 }));
245}
246
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500247TEST_F(DeviceRegistrationInfoTest, VerifySave) {
248 base::DictionaryValue data;
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500249 data.SetString(storage_keys::kRefreshToken, "d");
250 data.SetString(storage_keys::kDeviceId, "e");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500251 data.SetString(storage_keys::kRobotAccount, "h");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500252 data.SetString(storage_keys::kDisplayName, "k");
253 data.SetString(storage_keys::kDescription, "l");
254 data.SetString(storage_keys::kLocation, "m");
255
256 storage_->Save(&data);
257
258 // This test isn't really trying to test Load, it is just the easiest
259 // way to initialize the properties in dev_reg_.
260 EXPECT_TRUE(dev_reg_->Load());
261
262 // Clear the storage to get a clean test.
263 base::DictionaryValue empty;
264 storage_->Save(&empty);
265 EXPECT_TRUE(DeviceRegistrationInfo::TestHelper::Save(dev_reg_.get()));
266 EXPECT_TRUE(storage_->Load()->Equals(&data));
267}
268
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700269TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700270 EXPECT_TRUE(dev_reg_->Load());
271 EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700272 std::string url = test_data::kOAuthURL;
273 url += "auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fclouddevices&";
274 url += "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
275 url += "response_type=code&";
276 url += "client_id=";
277 url += test_data::kClientId;
Alex Vakulenko45109442014-07-29 11:07:10 -0700278 EXPECT_EQ(url, dev_reg_->GetOAuthURL("auth", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700279 {"scope", "https://www.googleapis.com/auth/clouddevices"},
280 {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
281 {"response_type", "code"},
282 {"client_id", test_data::kClientId}
283 }));
284}
285
286TEST_F(DeviceRegistrationInfoTest, CheckRegistration) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700287 EXPECT_TRUE(dev_reg_->Load());
288 EXPECT_FALSE(dev_reg_->CheckRegistration(nullptr));
289 EXPECT_EQ(0, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700290
Alex Vakulenko45109442014-07-29 11:07:10 -0700291 SetDefaultDeviceRegistration(&data_);
292 storage_->Save(&data_);
293 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700294
Alex Vakulenkocca20932014-08-20 17:35:12 -0700295 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
296 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700297 base::Bind(OAuth2Handler));
298 transport_->ResetRequestCount();
299 EXPECT_TRUE(dev_reg_->CheckRegistration(nullptr));
300 EXPECT_EQ(1, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700301}
302
Nathan Bullock24d189f2015-02-26 13:09:18 -0500303TEST_F(DeviceRegistrationInfoTest, CheckAuthenticationFailure) {
304 SetDefaultDeviceRegistration(&data_);
305 storage_->Save(&data_);
306 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700307 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500308
309 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
310 chromeos::http::request_type::kPost,
311 base::Bind(OAuth2HandlerFail));
312 transport_->ResetRequestCount();
313 chromeos::ErrorPtr error;
314 EXPECT_FALSE(dev_reg_->CheckRegistration(&error));
315 EXPECT_EQ(1, transport_->GetRequestCount());
316 EXPECT_TRUE(error->HasError(buffet::kErrorDomainOAuth2,
317 "unable_to_authenticate"));
Vitaly Bukab055f152015-03-12 13:41:43 -0700318 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500319}
320
321TEST_F(DeviceRegistrationInfoTest, CheckDeregistration) {
322 SetDefaultDeviceRegistration(&data_);
323 storage_->Save(&data_);
324 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700325 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500326
327 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
328 chromeos::http::request_type::kPost,
329 base::Bind(OAuth2HandlerDeregister));
330 transport_->ResetRequestCount();
331 chromeos::ErrorPtr error;
332 EXPECT_FALSE(dev_reg_->CheckRegistration(&error));
333 EXPECT_EQ(1, transport_->GetRequestCount());
334 EXPECT_TRUE(error->HasError(buffet::kErrorDomainOAuth2,
335 "invalid_grant"));
336 EXPECT_EQ(RegistrationStatus::kInvalidCredentials,
337 dev_reg_->GetRegistrationStatus());
338}
339
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700340TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700341 SetDefaultDeviceRegistration(&data_);
342 storage_->Save(&data_);
343 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700344
Alex Vakulenkocca20932014-08-20 17:35:12 -0700345 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
346 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700347 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700348 transport_->AddHandler(dev_reg_->GetDeviceURL(),
349 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700350 base::Bind(DeviceInfoHandler));
351 transport_->ResetRequestCount();
352 auto device_info = dev_reg_->GetDeviceInfo(nullptr);
353 EXPECT_EQ(2, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700354 EXPECT_NE(nullptr, device_info.get());
355 base::DictionaryValue* dict = nullptr;
356 EXPECT_TRUE(device_info->GetAsDictionary(&dict));
357 std::string id;
358 EXPECT_TRUE(dict->GetString("id", &id));
359 EXPECT_EQ(test_data::kDeviceId, id);
360}
361
362TEST_F(DeviceRegistrationInfoTest, GetDeviceId) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700363 SetDefaultDeviceRegistration(&data_);
364 storage_->Save(&data_);
365 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700366
Alex Vakulenkocca20932014-08-20 17:35:12 -0700367 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
368 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700369 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700370 transport_->AddHandler(dev_reg_->GetDeviceURL(),
371 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700372 base::Bind(DeviceInfoHandler));
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700373 EXPECT_EQ(test_data::kDeviceId, dev_reg_->GetDeviceId());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700374}
375
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400376TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700377 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700378
Anton Muhina4803142014-09-24 19:30:45 +0400379 auto update_ticket = [](const ServerRequest& request,
Alex Vakulenkocca20932014-08-20 17:35:12 -0700380 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700381 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
382 auto json = request.GetDataAsJson();
383 EXPECT_NE(nullptr, json.get());
384 std::string value;
Anton Muhina4803142014-09-24 19:30:45 +0400385 EXPECT_TRUE(json->GetString("id", &value));
386 EXPECT_EQ(test_data::kClaimTicketId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700387 EXPECT_TRUE(json->GetString("deviceDraft.channel.supportedType", &value));
388 EXPECT_EQ("xmpp", value);
389 EXPECT_TRUE(json->GetString("oauthClientId", &value));
390 EXPECT_EQ(test_data::kClientId, value);
391 EXPECT_TRUE(json->GetString("deviceDraft.deviceKind", &value));
392 EXPECT_EQ("vendor", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800393 EXPECT_TRUE(json->GetString("deviceDraft.description", &value));
394 EXPECT_EQ("Easy to clean", value);
395 EXPECT_TRUE(json->GetString("deviceDraft.location", &value));
396 EXPECT_EQ("Kitchen", value);
Vitaly Buka6522ab62015-02-19 10:26:31 -0800397 EXPECT_TRUE(json->GetString("deviceDraft.modelManifestId", &value));
398 EXPECT_EQ("AAA", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800399 EXPECT_TRUE(json->GetString("deviceDraft.displayName", &value));
400 EXPECT_EQ("Coffee Pot", value);
Alex Vakulenko45109442014-07-29 11:07:10 -0700401 base::DictionaryValue* commandDefs = nullptr;
402 EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
403 EXPECT_FALSE(commandDefs->empty());
404 EXPECT_EQ("{'base':{'reboot':{'parameters':{"
405 "'delay':{'minimum':10,'type':'integer'}}}},"
406 "'robot':{'_jump':{'parameters':{"
407 "'_height':{'type':'integer'}}}}}",
408 buffet::unittests::ValueToString(commandDefs));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700409
410 base::DictionaryValue json_resp;
411 json_resp.SetString("id", test_data::kClaimTicketId);
412 json_resp.SetString("kind", "clouddevices#registrationTicket");
413 json_resp.SetString("oauthClientId", test_data::kClientId);
414 base::DictionaryValue* device_draft = nullptr;
415 EXPECT_TRUE(json->GetDictionary("deviceDraft", &device_draft));
416 device_draft = device_draft->DeepCopy();
417 device_draft->SetString("id", test_data::kDeviceId);
418 device_draft->SetString("kind", "clouddevices#device");
419 json_resp.Set("deviceDraft", device_draft);
420
Alex Vakulenkocca20932014-08-20 17:35:12 -0700421 response->ReplyJson(chromeos::http::status_code::Ok, &json_resp);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700422 };
423
Alex Vakulenko45109442014-07-29 11:07:10 -0700424 auto json_base = buffet::unittests::CreateDictionaryValue(R"({
425 'base': {
426 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400427 'parameters': {'delay': 'integer'},
428 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700429 },
430 'shutdown': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400431 'parameters': {},
432 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700433 }
434 }
435 })");
436 EXPECT_TRUE(command_manager_->LoadBaseCommands(*json_base, nullptr));
437 auto json_cmds = buffet::unittests::CreateDictionaryValue(R"({
438 'base': {
439 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400440 'parameters': {'delay': {'minimum': 10}},
441 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700442 }
443 },
444 'robot': {
445 '_jump': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400446 'parameters': {'_height': 'integer'},
447 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700448 }
449 }
450 })");
451 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
452
Anton Muhina4803142014-09-24 19:30:45 +0400453 transport_->AddHandler(dev_reg_->GetServiceURL(
454 std::string("registrationTickets/") + test_data::kClaimTicketId),
455 chromeos::http::request_type::kPatch,
456 base::Bind(update_ticket));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700457 std::string ticket_url =
Alex Vakulenko45109442014-07-29 11:07:10 -0700458 dev_reg_->GetServiceURL("registrationTickets/" +
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700459 std::string(test_data::kClaimTicketId));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700460 transport_->AddHandler(ticket_url + "/finalize",
461 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700462 base::Bind(FinalizeTicketHandler));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700463
Alex Vakulenkocca20932014-08-20 17:35:12 -0700464 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
465 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700466 base::Bind(OAuth2Handler));
Alex Vakulenko45109442014-07-29 11:07:10 -0700467 storage_->reset_save_count();
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400468
469 std::map<std::string, std::string> params;
470 params["ticket_id"] = test_data::kClaimTicketId;
471 std::string device_id = dev_reg_->RegisterDevice(params, nullptr);
472
473 EXPECT_EQ(test_data::kDeviceId, device_id);
Alex Vakulenko45109442014-07-29 11:07:10 -0700474 EXPECT_EQ(1,
475 storage_->save_count()); // The device info must have been saved.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400476 EXPECT_EQ(3, transport_->GetRequestCount());
Vitaly Bukab055f152015-03-12 13:41:43 -0700477 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700478
479 // Validate the device info saved to storage...
Alex Vakulenko45109442014-07-29 11:07:10 -0700480 auto storage_data = storage_->Load();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700481 base::DictionaryValue* dict = nullptr;
482 EXPECT_TRUE(storage_data->GetAsDictionary(&dict));
483 std::string value;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700484 EXPECT_TRUE(dict->GetString(storage_keys::kDeviceId, &value));
485 EXPECT_EQ(test_data::kDeviceId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700486 EXPECT_TRUE(dict->GetString(storage_keys::kRefreshToken, &value));
487 EXPECT_EQ(test_data::kRefreshToken, value);
488 EXPECT_TRUE(dict->GetString(storage_keys::kRobotAccount, &value));
489 EXPECT_EQ(test_data::kRobotAccountEmail, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700490}
491
Christopher Wileyc900e482015-02-15 15:42:04 -0800492TEST_F(DeviceRegistrationInfoTest, OOBRegistrationStatus) {
493 // After we've been initialized, we should be either offline or unregistered,
494 // depending on whether or not we've found credentials.
495 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700496 EXPECT_EQ(RegistrationStatus::kUnconfigured,
Christopher Wileyc900e482015-02-15 15:42:04 -0800497 dev_reg_->GetRegistrationStatus());
498 // Put some credentials into our state, make sure we call that offline.
499 SetDefaultDeviceRegistration(&data_);
500 storage_->Save(&data_);
501 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700502 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Christopher Wileyc900e482015-02-15 15:42:04 -0800503}
504
Alex Vakulenkocca20932014-08-20 17:35:12 -0700505} // namespace buffet