blob: 2912fb64fb034cefb9c4093a0080e3711f234bbb [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) {
62 data->SetString(storage_keys::kClientId, test_data::kClientId);
63 data->SetString(storage_keys::kClientSecret, test_data::kClientSecret);
64 data->SetString(storage_keys::kApiKey, test_data::kApiKey);
65 data->SetString(storage_keys::kRefreshToken, "");
66 data->SetString(storage_keys::kDeviceId, "");
67 data->SetString(storage_keys::kOAuthURL, test_data::kOAuthURL);
68 data->SetString(storage_keys::kServiceURL, test_data::kServiceURL);
69 data->SetString(storage_keys::kRobotAccount, "");
Nathan Bullock02ca28b2015-02-11 16:22:16 -050070 data->SetString(storage_keys::kDeviceKind, "");
71 data->SetString(storage_keys::kName, "");
72 data->SetString(storage_keys::kDisplayName, "");
73 data->SetString(storage_keys::kDescription, "");
74 data->SetString(storage_keys::kLocation, "");
Vitaly Buka6522ab62015-02-19 10:26:31 -080075 data->SetString(storage_keys::kModelId, "");
Alex Vakulenko8e34d392014-04-29 11:02:56 -070076}
77
78// Add the test device registration information.
79void SetDefaultDeviceRegistration(base::DictionaryValue* data) {
80 data->SetString(storage_keys::kRefreshToken, test_data::kRefreshToken);
81 data->SetString(storage_keys::kDeviceId, test_data::kDeviceId);
82 data->SetString(storage_keys::kRobotAccount, test_data::kRobotAccountEmail);
83}
84
Alex Vakulenkocca20932014-08-20 17:35:12 -070085void OAuth2Handler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070086 base::DictionaryValue json;
87 if (request.GetFormField("grant_type") == "refresh_token") {
88 // Refresh device access token.
89 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
90 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
91 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
92 json.SetString("access_token", test_data::kAccessToken);
93 } else if (request.GetFormField("grant_type") == "authorization_code") {
94 // Obtain access token.
95 std::string code = request.GetFormField("code");
96 if (code == test_data::kUserAccountAuthCode) {
97 // Get user access token.
98 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
99 EXPECT_EQ(test_data::kClientSecret,
100 request.GetFormField("client_secret"));
101 EXPECT_EQ("urn:ietf:wg:oauth:2.0:oob",
102 request.GetFormField("redirect_uri"));
103 json.SetString("access_token", test_data::kUserAccessToken);
104 json.SetString("token_type", "Bearer");
105 json.SetString("refresh_token", test_data::kUserRefreshToken);
106 } else if (code == test_data::kRobotAccountAuthCode) {
107 // Get device access token.
108 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
109 EXPECT_EQ(test_data::kClientSecret,
110 request.GetFormField("client_secret"));
111 EXPECT_EQ("oob", request.GetFormField("redirect_uri"));
112 EXPECT_EQ("https://www.googleapis.com/auth/clouddevices",
113 request.GetFormField("scope"));
114 json.SetString("access_token", test_data::kAccessToken);
115 json.SetString("token_type", "Bearer");
116 json.SetString("refresh_token", test_data::kRefreshToken);
117 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700118 FAIL() << "Unexpected authorization code";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700119 }
120 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700121 FAIL() << "Unexpected grant type";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700122 }
123 json.SetInteger("expires_in", 3600);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700124 response->ReplyJson(chromeos::http::status_code::Ok, &json);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700125}
126
Nathan Bullock24d189f2015-02-26 13:09:18 -0500127void OAuth2HandlerFail(const ServerRequest& request,
128 ServerResponse* response) {
129 base::DictionaryValue json;
130 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
131 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
132 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
133 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
134 json.SetString("error", "unable_to_authenticate");
135 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
136}
137
138void OAuth2HandlerDeregister(const ServerRequest& request,
139 ServerResponse* response) {
140 base::DictionaryValue json;
141 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
142 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
143 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
144 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
145 json.SetString("error", "invalid_grant");
146 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
147}
148
Alex Vakulenkocca20932014-08-20 17:35:12 -0700149void DeviceInfoHandler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700150 std::string auth = "Bearer ";
151 auth += test_data::kAccessToken;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700152 EXPECT_EQ(auth,
153 request.GetHeader(chromeos::http::request_header::kAuthorization));
154 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700155 {"channel.supportedType", "xmpp"},
156 {"deviceKind", "vendor"},
157 {"id", test_data::kDeviceId},
158 {"kind", "clouddevices#device"},
159 });
160}
161
Alex Vakulenkocca20932014-08-20 17:35:12 -0700162void FinalizeTicketHandler(const ServerRequest& request,
163 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700164 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
165 EXPECT_TRUE(request.GetData().empty());
166
Alex Vakulenkocca20932014-08-20 17:35:12 -0700167 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700168 {"id", test_data::kClaimTicketId},
169 {"kind", "clouddevices#registrationTicket"},
170 {"oauthClientId", test_data::kClientId},
171 {"userEmail", "user@email.com"},
172 {"deviceDraft.id", test_data::kDeviceId},
173 {"deviceDraft.kind", "clouddevices#device"},
174 {"deviceDraft.channel.supportedType", "xmpp"},
175 {"robotAccountEmail", test_data::kRobotAccountEmail},
176 {"robotAccountAuthorizationCode", test_data::kRobotAccountAuthCode},
177 });
178}
179
180} // anonymous namespace
181
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500182// This is a helper class that allows the unit tests to access private
183// methods and data since TestHelper is declared as a friend to
184// DeviceRegistrationInfo.
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700185class DeviceRegistrationInfo::TestHelper {
186 public:
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500187 static bool Save(DeviceRegistrationInfo* info) {
188 return info->Save();
189 }
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700190};
191
192class DeviceRegistrationInfoTest : public ::testing::Test {
193 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -0700194 void SetUp() override {
Alex Vakulenko45109442014-07-29 11:07:10 -0700195 InitDefaultStorage(&data_);
196 storage_ = std::make_shared<MemStorage>();
197 storage_->Save(&data_);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700198 transport_ = std::make_shared<chromeos::http::fake::Transport>();
Alex Vakulenko45109442014-07-29 11:07:10 -0700199 command_manager_ = std::make_shared<CommandManager>();
Alex Vakulenko57123b22014-10-28 13:50:16 -0700200 state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
Anton Muhin332df192014-11-22 05:59:14 +0400201 std::unique_ptr<chromeos::KeyValueStore> config_store{
202 new chromeos::KeyValueStore};
203 config_store->SetString("client_id", test_data::kClientId);
204 config_store->SetString("client_secret", test_data::kClientSecret);
205 config_store->SetString("api_key", test_data::kApiKey);
206 config_store->SetString("device_kind", "vendor");
207 config_store->SetString("name", "coffee_pot");
208 config_store->SetString("display_name", "Coffee Pot");
209 config_store->SetString("description", "Easy to clean");
210 config_store->SetString("location", "Kitchen");
Vitaly Buka6522ab62015-02-19 10:26:31 -0800211 config_store->SetString("model_id", "AAA");
Anton Muhin332df192014-11-22 05:59:14 +0400212 config_store->SetString("oauth_url", test_data::kOAuthURL);
213 config_store->SetString("service_url", test_data::kServiceURL);
Christopher Wileyc900e482015-02-15 15:42:04 -0800214 auto mock_callback = base::Bind(
215 &DeviceRegistrationInfoTest::OnRegistrationStatusChange,
216 base::Unretained(this));
Alex Vakulenko45109442014-07-29 11:07:10 -0700217 dev_reg_ = std::unique_ptr<DeviceRegistrationInfo>(
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700218 new DeviceRegistrationInfo(command_manager_, state_manager_,
Anton Muhin332df192014-11-22 05:59:14 +0400219 std::move(config_store),
Christopher Wileyc900e482015-02-15 15:42:04 -0800220 transport_, storage_,
221 mock_callback));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700222 }
223
Christopher Wileyc900e482015-02-15 15:42:04 -0800224 MOCK_METHOD1(OnRegistrationStatusChange, void(RegistrationStatus));
225
Alex Vakulenko45109442014-07-29 11:07:10 -0700226 base::DictionaryValue data_;
227 std::shared_ptr<MemStorage> storage_;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700228 std::shared_ptr<chromeos::http::fake::Transport> transport_;
Alex Vakulenko45109442014-07-29 11:07:10 -0700229 std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
230 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko57123b22014-10-28 13:50:16 -0700231 testing::NiceMock<MockStateChangeQueueInterface> mock_state_change_queue_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700232 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700233};
234
235////////////////////////////////////////////////////////////////////////////////
236TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700237 EXPECT_TRUE(dev_reg_->Load());
238 EXPECT_EQ(test_data::kServiceURL, dev_reg_->GetServiceURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700239 std::string url = test_data::kServiceURL;
240 url += "registrationTickets";
Alex Vakulenko45109442014-07-29 11:07:10 -0700241 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets"));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700242 url += "?key=";
243 url += test_data::kApiKey;
Alex Vakulenko45109442014-07-29 11:07:10 -0700244 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700245 {"key", test_data::kApiKey}
246 }));
247 url += "&restart=true";
Alex Vakulenko45109442014-07-29 11:07:10 -0700248 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700249 {"key", test_data::kApiKey},
250 {"restart", "true"},
251 }));
252}
253
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500254TEST_F(DeviceRegistrationInfoTest, VerifySave) {
255 base::DictionaryValue data;
256 data.SetString(storage_keys::kClientId, "a");
257 data.SetString(storage_keys::kClientSecret, "b");
258 data.SetString(storage_keys::kApiKey, "c");
259 data.SetString(storage_keys::kRefreshToken, "d");
260 data.SetString(storage_keys::kDeviceId, "e");
261 data.SetString(storage_keys::kOAuthURL, "f");
262 data.SetString(storage_keys::kServiceURL, "g");
263 data.SetString(storage_keys::kRobotAccount, "h");
264 data.SetString(storage_keys::kDeviceKind, "i");
265 data.SetString(storage_keys::kName, "j");
266 data.SetString(storage_keys::kDisplayName, "k");
267 data.SetString(storage_keys::kDescription, "l");
268 data.SetString(storage_keys::kLocation, "m");
Vitaly Buka6522ab62015-02-19 10:26:31 -0800269 data.SetString(storage_keys::kModelId, "n");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500270
271 storage_->Save(&data);
272
273 // This test isn't really trying to test Load, it is just the easiest
274 // way to initialize the properties in dev_reg_.
275 EXPECT_TRUE(dev_reg_->Load());
276
277 // Clear the storage to get a clean test.
278 base::DictionaryValue empty;
279 storage_->Save(&empty);
280 EXPECT_TRUE(DeviceRegistrationInfo::TestHelper::Save(dev_reg_.get()));
281 EXPECT_TRUE(storage_->Load()->Equals(&data));
282}
283
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700284TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700285 EXPECT_TRUE(dev_reg_->Load());
286 EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700287 std::string url = test_data::kOAuthURL;
288 url += "auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fclouddevices&";
289 url += "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
290 url += "response_type=code&";
291 url += "client_id=";
292 url += test_data::kClientId;
Alex Vakulenko45109442014-07-29 11:07:10 -0700293 EXPECT_EQ(url, dev_reg_->GetOAuthURL("auth", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700294 {"scope", "https://www.googleapis.com/auth/clouddevices"},
295 {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
296 {"response_type", "code"},
297 {"client_id", test_data::kClientId}
298 }));
299}
300
301TEST_F(DeviceRegistrationInfoTest, CheckRegistration) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700302 EXPECT_TRUE(dev_reg_->Load());
303 EXPECT_FALSE(dev_reg_->CheckRegistration(nullptr));
304 EXPECT_EQ(0, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700305
Alex Vakulenko45109442014-07-29 11:07:10 -0700306 SetDefaultDeviceRegistration(&data_);
307 storage_->Save(&data_);
308 EXPECT_TRUE(dev_reg_->Load());
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));
313 transport_->ResetRequestCount();
314 EXPECT_TRUE(dev_reg_->CheckRegistration(nullptr));
315 EXPECT_EQ(1, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700316}
317
Nathan Bullock24d189f2015-02-26 13:09:18 -0500318TEST_F(DeviceRegistrationInfoTest, CheckAuthenticationFailure) {
319 SetDefaultDeviceRegistration(&data_);
320 storage_->Save(&data_);
321 EXPECT_TRUE(dev_reg_->Load());
322 EXPECT_EQ(RegistrationStatus::kOffline,
323 dev_reg_->GetRegistrationStatus());
324
325 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
326 chromeos::http::request_type::kPost,
327 base::Bind(OAuth2HandlerFail));
328 transport_->ResetRequestCount();
329 chromeos::ErrorPtr error;
330 EXPECT_FALSE(dev_reg_->CheckRegistration(&error));
331 EXPECT_EQ(1, transport_->GetRequestCount());
332 EXPECT_TRUE(error->HasError(buffet::kErrorDomainOAuth2,
333 "unable_to_authenticate"));
334 EXPECT_EQ(RegistrationStatus::kOffline,
335 dev_reg_->GetRegistrationStatus());
336}
337
338TEST_F(DeviceRegistrationInfoTest, CheckDeregistration) {
339 SetDefaultDeviceRegistration(&data_);
340 storage_->Save(&data_);
341 EXPECT_TRUE(dev_reg_->Load());
342 EXPECT_EQ(RegistrationStatus::kOffline,
343 dev_reg_->GetRegistrationStatus());
344
345 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
346 chromeos::http::request_type::kPost,
347 base::Bind(OAuth2HandlerDeregister));
348 transport_->ResetRequestCount();
349 chromeos::ErrorPtr error;
350 EXPECT_FALSE(dev_reg_->CheckRegistration(&error));
351 EXPECT_EQ(1, transport_->GetRequestCount());
352 EXPECT_TRUE(error->HasError(buffet::kErrorDomainOAuth2,
353 "invalid_grant"));
354 EXPECT_EQ(RegistrationStatus::kInvalidCredentials,
355 dev_reg_->GetRegistrationStatus());
356}
357
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700358TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700359 SetDefaultDeviceRegistration(&data_);
360 storage_->Save(&data_);
361 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700362
Alex Vakulenkocca20932014-08-20 17:35:12 -0700363 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
364 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700365 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700366 transport_->AddHandler(dev_reg_->GetDeviceURL(),
367 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700368 base::Bind(DeviceInfoHandler));
369 transport_->ResetRequestCount();
370 auto device_info = dev_reg_->GetDeviceInfo(nullptr);
371 EXPECT_EQ(2, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700372 EXPECT_NE(nullptr, device_info.get());
373 base::DictionaryValue* dict = nullptr;
374 EXPECT_TRUE(device_info->GetAsDictionary(&dict));
375 std::string id;
376 EXPECT_TRUE(dict->GetString("id", &id));
377 EXPECT_EQ(test_data::kDeviceId, id);
378}
379
380TEST_F(DeviceRegistrationInfoTest, GetDeviceId) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700381 SetDefaultDeviceRegistration(&data_);
382 storage_->Save(&data_);
383 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700384
Alex Vakulenkocca20932014-08-20 17:35:12 -0700385 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
386 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700387 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700388 transport_->AddHandler(dev_reg_->GetDeviceURL(),
389 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700390 base::Bind(DeviceInfoHandler));
391 std::string id = dev_reg_->GetDeviceId(nullptr);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700392 EXPECT_EQ(test_data::kDeviceId, id);
393}
394
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400395TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700396 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700397
Anton Muhina4803142014-09-24 19:30:45 +0400398 auto update_ticket = [](const ServerRequest& request,
Alex Vakulenkocca20932014-08-20 17:35:12 -0700399 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700400 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
401 auto json = request.GetDataAsJson();
402 EXPECT_NE(nullptr, json.get());
403 std::string value;
Anton Muhina4803142014-09-24 19:30:45 +0400404 EXPECT_TRUE(json->GetString("id", &value));
405 EXPECT_EQ(test_data::kClaimTicketId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700406 EXPECT_TRUE(json->GetString("deviceDraft.channel.supportedType", &value));
407 EXPECT_EQ("xmpp", value);
408 EXPECT_TRUE(json->GetString("oauthClientId", &value));
409 EXPECT_EQ(test_data::kClientId, value);
410 EXPECT_TRUE(json->GetString("deviceDraft.deviceKind", &value));
411 EXPECT_EQ("vendor", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800412 EXPECT_TRUE(json->GetString("deviceDraft.description", &value));
413 EXPECT_EQ("Easy to clean", value);
414 EXPECT_TRUE(json->GetString("deviceDraft.location", &value));
415 EXPECT_EQ("Kitchen", value);
Vitaly Buka6522ab62015-02-19 10:26:31 -0800416 EXPECT_TRUE(json->GetString("deviceDraft.modelManifestId", &value));
417 EXPECT_EQ("AAA", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800418 EXPECT_TRUE(json->GetString("deviceDraft.displayName", &value));
419 EXPECT_EQ("Coffee Pot", value);
Alex Vakulenko45109442014-07-29 11:07:10 -0700420 base::DictionaryValue* commandDefs = nullptr;
421 EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
422 EXPECT_FALSE(commandDefs->empty());
423 EXPECT_EQ("{'base':{'reboot':{'parameters':{"
424 "'delay':{'minimum':10,'type':'integer'}}}},"
425 "'robot':{'_jump':{'parameters':{"
426 "'_height':{'type':'integer'}}}}}",
427 buffet::unittests::ValueToString(commandDefs));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700428
429 base::DictionaryValue json_resp;
430 json_resp.SetString("id", test_data::kClaimTicketId);
431 json_resp.SetString("kind", "clouddevices#registrationTicket");
432 json_resp.SetString("oauthClientId", test_data::kClientId);
433 base::DictionaryValue* device_draft = nullptr;
434 EXPECT_TRUE(json->GetDictionary("deviceDraft", &device_draft));
435 device_draft = device_draft->DeepCopy();
436 device_draft->SetString("id", test_data::kDeviceId);
437 device_draft->SetString("kind", "clouddevices#device");
438 json_resp.Set("deviceDraft", device_draft);
439
Alex Vakulenkocca20932014-08-20 17:35:12 -0700440 response->ReplyJson(chromeos::http::status_code::Ok, &json_resp);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700441 };
442
Alex Vakulenko45109442014-07-29 11:07:10 -0700443 auto json_base = buffet::unittests::CreateDictionaryValue(R"({
444 'base': {
445 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400446 'parameters': {'delay': 'integer'},
447 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700448 },
449 'shutdown': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400450 'parameters': {},
451 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700452 }
453 }
454 })");
455 EXPECT_TRUE(command_manager_->LoadBaseCommands(*json_base, nullptr));
456 auto json_cmds = buffet::unittests::CreateDictionaryValue(R"({
457 'base': {
458 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400459 'parameters': {'delay': {'minimum': 10}},
460 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700461 }
462 },
463 'robot': {
464 '_jump': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400465 'parameters': {'_height': 'integer'},
466 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700467 }
468 }
469 })");
470 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
471
Anton Muhina4803142014-09-24 19:30:45 +0400472 transport_->AddHandler(dev_reg_->GetServiceURL(
473 std::string("registrationTickets/") + test_data::kClaimTicketId),
474 chromeos::http::request_type::kPatch,
475 base::Bind(update_ticket));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700476 std::string ticket_url =
Alex Vakulenko45109442014-07-29 11:07:10 -0700477 dev_reg_->GetServiceURL("registrationTickets/" +
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700478 std::string(test_data::kClaimTicketId));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700479 transport_->AddHandler(ticket_url + "/finalize",
480 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700481 base::Bind(FinalizeTicketHandler));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700482
Alex Vakulenkocca20932014-08-20 17:35:12 -0700483 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
484 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700485 base::Bind(OAuth2Handler));
Alex Vakulenko45109442014-07-29 11:07:10 -0700486 storage_->reset_save_count();
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400487
488 std::map<std::string, std::string> params;
489 params["ticket_id"] = test_data::kClaimTicketId;
490 std::string device_id = dev_reg_->RegisterDevice(params, nullptr);
491
492 EXPECT_EQ(test_data::kDeviceId, device_id);
Alex Vakulenko45109442014-07-29 11:07:10 -0700493 EXPECT_EQ(1,
494 storage_->save_count()); // The device info must have been saved.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400495 EXPECT_EQ(3, transport_->GetRequestCount());
Christopher Wileyc900e482015-02-15 15:42:04 -0800496 EXPECT_EQ(RegistrationStatus::kRegistered, dev_reg_->GetRegistrationStatus());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700497
498 // Validate the device info saved to storage...
Alex Vakulenko45109442014-07-29 11:07:10 -0700499 auto storage_data = storage_->Load();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700500 base::DictionaryValue* dict = nullptr;
501 EXPECT_TRUE(storage_data->GetAsDictionary(&dict));
502 std::string value;
503 EXPECT_TRUE(dict->GetString(storage_keys::kApiKey, &value));
504 EXPECT_EQ(test_data::kApiKey, value);
505 EXPECT_TRUE(dict->GetString(storage_keys::kClientId, &value));
506 EXPECT_EQ(test_data::kClientId, value);
507 EXPECT_TRUE(dict->GetString(storage_keys::kClientSecret, &value));
508 EXPECT_EQ(test_data::kClientSecret, value);
509 EXPECT_TRUE(dict->GetString(storage_keys::kDeviceId, &value));
510 EXPECT_EQ(test_data::kDeviceId, value);
511 EXPECT_TRUE(dict->GetString(storage_keys::kOAuthURL, &value));
512 EXPECT_EQ(test_data::kOAuthURL, value);
513 EXPECT_TRUE(dict->GetString(storage_keys::kRefreshToken, &value));
514 EXPECT_EQ(test_data::kRefreshToken, value);
515 EXPECT_TRUE(dict->GetString(storage_keys::kRobotAccount, &value));
516 EXPECT_EQ(test_data::kRobotAccountEmail, value);
517 EXPECT_TRUE(dict->GetString(storage_keys::kServiceURL, &value));
518 EXPECT_EQ(test_data::kServiceURL, value);
519}
520
Christopher Wileyc900e482015-02-15 15:42:04 -0800521TEST_F(DeviceRegistrationInfoTest, OOBRegistrationStatus) {
522 // After we've been initialized, we should be either offline or unregistered,
523 // depending on whether or not we've found credentials.
524 EXPECT_TRUE(dev_reg_->Load());
525 EXPECT_EQ(RegistrationStatus::kUnregistered,
526 dev_reg_->GetRegistrationStatus());
527 // Put some credentials into our state, make sure we call that offline.
528 SetDefaultDeviceRegistration(&data_);
529 storage_->Save(&data_);
530 EXPECT_TRUE(dev_reg_->Load());
531 EXPECT_EQ(RegistrationStatus::kOffline, dev_reg_->GetRegistrationStatus());
532}
533
Alex Vakulenkocca20932014-08-20 17:35:12 -0700534} // namespace buffet