blob: c800052d2817d5db10357d8627a8a08df73d1236 [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 Vakulenko8e34d392014-04-29 11:02:56 -070019#include "buffet/device_registration_storage_keys.h"
Alex Vakulenko57123b22014-10-28 13:50:16 -070020#include "buffet/states/mock_state_change_queue_interface.h"
Alex Vakulenko07216fe2014-09-19 15:31:09 -070021#include "buffet/states/state_manager.h"
Christopher Wiley006e94e2014-05-02 13:44:48 -070022#include "buffet/storage_impls.h"
Alex Vakulenko8e34d392014-04-29 11:02:56 -070023
Alex Vakulenkocca20932014-08-20 17:35:12 -070024using chromeos::http::request_header::kAuthorization;
25using chromeos::http::fake::ServerRequest;
26using chromeos::http::fake::ServerResponse;
27
28namespace buffet {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070029
30namespace {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070031
32namespace test_data {
33
34const char kServiceURL[] = "http://gcd.server.com/";
35const char kOAuthURL[] = "http://oauth.server.com/";
36const char kApiKey[] = "GOadRdTf9FERf0k4w6EFOof56fUJ3kFDdFL3d7f";
37const char kClientId[] = "123543821385-sfjkjshdkjhfk234sdfsdfkskd"
38 "fkjh7f.apps.googleusercontent.com";
39const char kClientSecret[] = "5sdGdGlfolGlrFKfdFlgP6FG";
40const char kDeviceId[] = "4a7ea2d1-b331-1e1f-b206-e863c7635196";
41const char kClaimTicketId[] = "RTcUE";
42const char kAccessToken[] = "ya29.1.AADtN_V-dLUM-sVZ0qVjG9Dxm5NgdS9J"
43 "Mx_JLUqhC9bED_YFjzHZtYt65ZzXCS35NMAeaVZ"
44 "Dei530-w0yE2urpQ";
45const char kRefreshToken[] = "1/zQmxR6PKNvhcxf9SjXUrCjcmCrcqRKXctc6cp"
46 "1nI-GQ";
47const char kRobotAccountAuthCode[] = "4/Mf_ujEhPejVhOq-OxW9F5cSOnWzx."
48 "YgciVjTYGscRshQV0ieZDAqiTIjMigI";
49const char kRobotAccountEmail[] = "6ed0b3f54f9bd619b942f4ad2441c252@"
50 "clouddevices.gserviceaccount.com";
51const char kUserAccountAuthCode[] = "2/sd_GD1TGFKpJOLJ34-0g5fK0fflp.GlT"
52 "I0F5g7hNtFgj5HFGOf8FlGK9eflO";
53const char kUserAccessToken[] = "sd56.4.FGDjG_F-gFGF-dFG6gGOG9Dxm5NgdS9"
54 "JMx_JLUqhC9bED_YFjLKjlkjLKJlkjLKjlKJea"
55 "VZDei530-w0yE2urpQ";
56const char kUserRefreshToken[] = "1/zQLKjlKJlkLkLKjLkjLKjLkjLjLkjl0ftc6"
57 "cp1nI-GQ";
58
59} // namespace test_data
60
61// Fill in the storage with default environment information (URLs, etc).
62void InitDefaultStorage(base::DictionaryValue* data) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070063 data->SetString(storage_keys::kRefreshToken, "");
64 data->SetString(storage_keys::kDeviceId, "");
Alex Vakulenko8e34d392014-04-29 11:02:56 -070065 data->SetString(storage_keys::kRobotAccount, "");
Alex Vakulenko468f7f32015-04-08 10:42:45 -070066 data->SetString(storage_keys::kName, "");
Nathan Bullock02ca28b2015-02-11 16:22:16 -050067 data->SetString(storage_keys::kDescription, "");
68 data->SetString(storage_keys::kLocation, "");
Alex Vakulenko8e34d392014-04-29 11:02:56 -070069}
70
71// Add the test device registration information.
72void SetDefaultDeviceRegistration(base::DictionaryValue* data) {
73 data->SetString(storage_keys::kRefreshToken, test_data::kRefreshToken);
74 data->SetString(storage_keys::kDeviceId, test_data::kDeviceId);
75 data->SetString(storage_keys::kRobotAccount, test_data::kRobotAccountEmail);
76}
77
Alex Vakulenkocca20932014-08-20 17:35:12 -070078void OAuth2Handler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070079 base::DictionaryValue json;
80 if (request.GetFormField("grant_type") == "refresh_token") {
81 // Refresh device access token.
82 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
83 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
84 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
85 json.SetString("access_token", test_data::kAccessToken);
86 } else if (request.GetFormField("grant_type") == "authorization_code") {
87 // Obtain access token.
88 std::string code = request.GetFormField("code");
89 if (code == test_data::kUserAccountAuthCode) {
90 // Get user access token.
91 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
92 EXPECT_EQ(test_data::kClientSecret,
93 request.GetFormField("client_secret"));
94 EXPECT_EQ("urn:ietf:wg:oauth:2.0:oob",
95 request.GetFormField("redirect_uri"));
96 json.SetString("access_token", test_data::kUserAccessToken);
97 json.SetString("token_type", "Bearer");
98 json.SetString("refresh_token", test_data::kUserRefreshToken);
99 } else if (code == test_data::kRobotAccountAuthCode) {
100 // Get device access token.
101 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
102 EXPECT_EQ(test_data::kClientSecret,
103 request.GetFormField("client_secret"));
104 EXPECT_EQ("oob", request.GetFormField("redirect_uri"));
105 EXPECT_EQ("https://www.googleapis.com/auth/clouddevices",
106 request.GetFormField("scope"));
107 json.SetString("access_token", test_data::kAccessToken);
108 json.SetString("token_type", "Bearer");
109 json.SetString("refresh_token", test_data::kRefreshToken);
110 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700111 FAIL() << "Unexpected authorization code";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700112 }
113 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700114 FAIL() << "Unexpected grant type";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700115 }
116 json.SetInteger("expires_in", 3600);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700117 response->ReplyJson(chromeos::http::status_code::Ok, &json);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700118}
119
Nathan Bullock24d189f2015-02-26 13:09:18 -0500120void OAuth2HandlerFail(const ServerRequest& request,
121 ServerResponse* response) {
122 base::DictionaryValue json;
123 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
124 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
125 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
126 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
127 json.SetString("error", "unable_to_authenticate");
128 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
129}
130
131void OAuth2HandlerDeregister(const ServerRequest& request,
132 ServerResponse* response) {
133 base::DictionaryValue json;
134 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
135 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
136 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
137 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
138 json.SetString("error", "invalid_grant");
139 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
140}
141
Alex Vakulenkocca20932014-08-20 17:35:12 -0700142void DeviceInfoHandler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700143 std::string auth = "Bearer ";
144 auth += test_data::kAccessToken;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700145 EXPECT_EQ(auth,
146 request.GetHeader(chromeos::http::request_header::kAuthorization));
147 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700148 {"channel.supportedType", "xmpp"},
149 {"deviceKind", "vendor"},
150 {"id", test_data::kDeviceId},
151 {"kind", "clouddevices#device"},
152 });
153}
154
Alex Vakulenkocca20932014-08-20 17:35:12 -0700155void FinalizeTicketHandler(const ServerRequest& request,
156 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700157 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
158 EXPECT_TRUE(request.GetData().empty());
159
Alex Vakulenkocca20932014-08-20 17:35:12 -0700160 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700161 {"id", test_data::kClaimTicketId},
162 {"kind", "clouddevices#registrationTicket"},
163 {"oauthClientId", test_data::kClientId},
164 {"userEmail", "user@email.com"},
165 {"deviceDraft.id", test_data::kDeviceId},
166 {"deviceDraft.kind", "clouddevices#device"},
167 {"deviceDraft.channel.supportedType", "xmpp"},
168 {"robotAccountEmail", test_data::kRobotAccountEmail},
169 {"robotAccountAuthorizationCode", test_data::kRobotAccountAuthCode},
170 });
171}
172
173} // anonymous namespace
174
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500175// This is a helper class that allows the unit tests to access private
176// methods and data since TestHelper is declared as a friend to
177// DeviceRegistrationInfo.
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700178class DeviceRegistrationInfo::TestHelper {
179 public:
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500180 static bool Save(DeviceRegistrationInfo* info) {
181 return info->Save();
182 }
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700183 static void PublishCommands(DeviceRegistrationInfo* info,
184 const base::ListValue& commands) {
185 return info->PublishCommands(commands);
186 }
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700187};
188
189class DeviceRegistrationInfoTest : public ::testing::Test {
190 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -0700191 void SetUp() override {
Alex Vakulenko45109442014-07-29 11:07:10 -0700192 InitDefaultStorage(&data_);
193 storage_ = std::make_shared<MemStorage>();
194 storage_->Save(&data_);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700195 transport_ = std::make_shared<chromeos::http::fake::Transport>();
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700196 command_manager_ = std::make_shared<CommandManager>(nullptr);
Alex Vakulenko57123b22014-10-28 13:50:16 -0700197 state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
Christopher Wiley583d64b2015-03-24 14:30:17 -0700198 chromeos::KeyValueStore config_store;
199 config_store.SetString("client_id", test_data::kClientId);
200 config_store.SetString("client_secret", test_data::kClientSecret);
201 config_store.SetString("api_key", test_data::kApiKey);
202 config_store.SetString("device_kind", "vendor");
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700203 config_store.SetString("name", "Coffee Pot");
Christopher Wiley583d64b2015-03-24 14:30:17 -0700204 config_store.SetString("default_description", "Easy to clean");
205 config_store.SetString("default_location", "Kitchen");
206 config_store.SetString("model_id", "AAA");
207 config_store.SetString("oauth_url", test_data::kOAuthURL);
208 config_store.SetString("service_url", test_data::kServiceURL);
209 std::unique_ptr<BuffetConfig> config{new BuffetConfig};
210 config->Load(config_store);
Christopher Wileyc900e482015-02-15 15:42:04 -0800211 auto mock_callback = base::Bind(
212 &DeviceRegistrationInfoTest::OnRegistrationStatusChange,
213 base::Unretained(this));
Alex Vakulenko45109442014-07-29 11:07:10 -0700214 dev_reg_ = std::unique_ptr<DeviceRegistrationInfo>(
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700215 new DeviceRegistrationInfo(command_manager_, state_manager_,
Christopher Wiley583d64b2015-03-24 14:30:17 -0700216 std::move(config),
Christopher Wileyc900e482015-02-15 15:42:04 -0800217 transport_, storage_,
Christopher Wileyd732bd02015-04-07 11:11:18 -0700218 true,
Christopher Wileyc900e482015-02-15 15:42:04 -0800219 mock_callback));
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700220 EXPECT_CALL(*this, OnRegistrationStatusChange())
221 .Times(testing::AnyNumber());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700222 }
223
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700224 MOCK_METHOD0(OnRegistrationStatusChange, void());
Christopher Wileyc900e482015-02-15 15:42:04 -0800225
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;
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500256 data.SetString(storage_keys::kRefreshToken, "d");
257 data.SetString(storage_keys::kDeviceId, "e");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500258 data.SetString(storage_keys::kRobotAccount, "h");
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700259 data.SetString(storage_keys::kName, "k");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500260 data.SetString(storage_keys::kDescription, "l");
261 data.SetString(storage_keys::kLocation, "m");
262
263 storage_->Save(&data);
264
265 // This test isn't really trying to test Load, it is just the easiest
266 // way to initialize the properties in dev_reg_.
267 EXPECT_TRUE(dev_reg_->Load());
268
269 // Clear the storage to get a clean test.
270 base::DictionaryValue empty;
271 storage_->Save(&empty);
272 EXPECT_TRUE(DeviceRegistrationInfo::TestHelper::Save(dev_reg_.get()));
273 EXPECT_TRUE(storage_->Load()->Equals(&data));
274}
275
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700276TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700277 EXPECT_TRUE(dev_reg_->Load());
278 EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700279 std::string url = test_data::kOAuthURL;
280 url += "auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fclouddevices&";
281 url += "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
282 url += "response_type=code&";
283 url += "client_id=";
284 url += test_data::kClientId;
Alex Vakulenko45109442014-07-29 11:07:10 -0700285 EXPECT_EQ(url, dev_reg_->GetOAuthURL("auth", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700286 {"scope", "https://www.googleapis.com/auth/clouddevices"},
287 {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
288 {"response_type", "code"},
289 {"client_id", test_data::kClientId}
290 }));
291}
292
293TEST_F(DeviceRegistrationInfoTest, CheckRegistration) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700294 EXPECT_TRUE(dev_reg_->Load());
295 EXPECT_FALSE(dev_reg_->CheckRegistration(nullptr));
296 EXPECT_EQ(0, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700297
Alex Vakulenko45109442014-07-29 11:07:10 -0700298 SetDefaultDeviceRegistration(&data_);
299 storage_->Save(&data_);
300 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700301
Alex Vakulenkocca20932014-08-20 17:35:12 -0700302 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
303 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700304 base::Bind(OAuth2Handler));
305 transport_->ResetRequestCount();
306 EXPECT_TRUE(dev_reg_->CheckRegistration(nullptr));
307 EXPECT_EQ(1, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700308}
309
Nathan Bullock24d189f2015-02-26 13:09:18 -0500310TEST_F(DeviceRegistrationInfoTest, CheckAuthenticationFailure) {
311 SetDefaultDeviceRegistration(&data_);
312 storage_->Save(&data_);
313 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700314 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500315
316 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
317 chromeos::http::request_type::kPost,
318 base::Bind(OAuth2HandlerFail));
319 transport_->ResetRequestCount();
320 chromeos::ErrorPtr error;
321 EXPECT_FALSE(dev_reg_->CheckRegistration(&error));
322 EXPECT_EQ(1, transport_->GetRequestCount());
323 EXPECT_TRUE(error->HasError(buffet::kErrorDomainOAuth2,
324 "unable_to_authenticate"));
Vitaly Bukab055f152015-03-12 13:41:43 -0700325 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500326}
327
328TEST_F(DeviceRegistrationInfoTest, CheckDeregistration) {
329 SetDefaultDeviceRegistration(&data_);
330 storage_->Save(&data_);
331 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700332 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500333
334 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
335 chromeos::http::request_type::kPost,
336 base::Bind(OAuth2HandlerDeregister));
337 transport_->ResetRequestCount();
338 chromeos::ErrorPtr error;
339 EXPECT_FALSE(dev_reg_->CheckRegistration(&error));
340 EXPECT_EQ(1, transport_->GetRequestCount());
341 EXPECT_TRUE(error->HasError(buffet::kErrorDomainOAuth2,
342 "invalid_grant"));
343 EXPECT_EQ(RegistrationStatus::kInvalidCredentials,
344 dev_reg_->GetRegistrationStatus());
345}
346
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700347TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700348 SetDefaultDeviceRegistration(&data_);
349 storage_->Save(&data_);
350 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700351
Alex Vakulenkocca20932014-08-20 17:35:12 -0700352 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
353 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700354 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700355 transport_->AddHandler(dev_reg_->GetDeviceURL(),
356 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700357 base::Bind(DeviceInfoHandler));
358 transport_->ResetRequestCount();
359 auto device_info = dev_reg_->GetDeviceInfo(nullptr);
360 EXPECT_EQ(2, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700361 EXPECT_NE(nullptr, device_info.get());
362 base::DictionaryValue* dict = nullptr;
363 EXPECT_TRUE(device_info->GetAsDictionary(&dict));
364 std::string id;
365 EXPECT_TRUE(dict->GetString("id", &id));
366 EXPECT_EQ(test_data::kDeviceId, id);
367}
368
369TEST_F(DeviceRegistrationInfoTest, GetDeviceId) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700370 SetDefaultDeviceRegistration(&data_);
371 storage_->Save(&data_);
372 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700373
Alex Vakulenkocca20932014-08-20 17:35:12 -0700374 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
375 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700376 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700377 transport_->AddHandler(dev_reg_->GetDeviceURL(),
378 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700379 base::Bind(DeviceInfoHandler));
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700380 EXPECT_EQ(test_data::kDeviceId, dev_reg_->GetDeviceId());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700381}
382
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400383TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700384 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700385
Anton Muhina4803142014-09-24 19:30:45 +0400386 auto update_ticket = [](const ServerRequest& request,
Alex Vakulenkocca20932014-08-20 17:35:12 -0700387 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700388 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
389 auto json = request.GetDataAsJson();
390 EXPECT_NE(nullptr, json.get());
391 std::string value;
Anton Muhina4803142014-09-24 19:30:45 +0400392 EXPECT_TRUE(json->GetString("id", &value));
393 EXPECT_EQ(test_data::kClaimTicketId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700394 EXPECT_TRUE(json->GetString("deviceDraft.channel.supportedType", &value));
395 EXPECT_EQ("xmpp", value);
396 EXPECT_TRUE(json->GetString("oauthClientId", &value));
397 EXPECT_EQ(test_data::kClientId, value);
398 EXPECT_TRUE(json->GetString("deviceDraft.deviceKind", &value));
399 EXPECT_EQ("vendor", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800400 EXPECT_TRUE(json->GetString("deviceDraft.description", &value));
401 EXPECT_EQ("Easy to clean", value);
402 EXPECT_TRUE(json->GetString("deviceDraft.location", &value));
403 EXPECT_EQ("Kitchen", value);
Vitaly Buka6522ab62015-02-19 10:26:31 -0800404 EXPECT_TRUE(json->GetString("deviceDraft.modelManifestId", &value));
405 EXPECT_EQ("AAA", value);
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700406 EXPECT_TRUE(json->GetString("deviceDraft.name", &value));
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800407 EXPECT_EQ("Coffee Pot", value);
Alex Vakulenko45109442014-07-29 11:07:10 -0700408 base::DictionaryValue* commandDefs = nullptr;
409 EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
410 EXPECT_FALSE(commandDefs->empty());
411 EXPECT_EQ("{'base':{'reboot':{'parameters':{"
412 "'delay':{'minimum':10,'type':'integer'}}}},"
413 "'robot':{'_jump':{'parameters':{"
414 "'_height':{'type':'integer'}}}}}",
415 buffet::unittests::ValueToString(commandDefs));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700416
417 base::DictionaryValue json_resp;
418 json_resp.SetString("id", test_data::kClaimTicketId);
419 json_resp.SetString("kind", "clouddevices#registrationTicket");
420 json_resp.SetString("oauthClientId", test_data::kClientId);
421 base::DictionaryValue* device_draft = nullptr;
422 EXPECT_TRUE(json->GetDictionary("deviceDraft", &device_draft));
423 device_draft = device_draft->DeepCopy();
424 device_draft->SetString("id", test_data::kDeviceId);
425 device_draft->SetString("kind", "clouddevices#device");
426 json_resp.Set("deviceDraft", device_draft);
427
Alex Vakulenkocca20932014-08-20 17:35:12 -0700428 response->ReplyJson(chromeos::http::status_code::Ok, &json_resp);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700429 };
430
Alex Vakulenko45109442014-07-29 11:07:10 -0700431 auto json_base = buffet::unittests::CreateDictionaryValue(R"({
432 'base': {
433 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400434 'parameters': {'delay': 'integer'},
435 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700436 },
437 'shutdown': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400438 'parameters': {},
439 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700440 }
441 }
442 })");
443 EXPECT_TRUE(command_manager_->LoadBaseCommands(*json_base, nullptr));
444 auto json_cmds = buffet::unittests::CreateDictionaryValue(R"({
445 'base': {
446 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400447 'parameters': {'delay': {'minimum': 10}},
448 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700449 }
450 },
451 'robot': {
452 '_jump': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400453 'parameters': {'_height': 'integer'},
454 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700455 }
456 }
457 })");
458 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
459
Anton Muhina4803142014-09-24 19:30:45 +0400460 transport_->AddHandler(dev_reg_->GetServiceURL(
461 std::string("registrationTickets/") + test_data::kClaimTicketId),
462 chromeos::http::request_type::kPatch,
463 base::Bind(update_ticket));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700464 std::string ticket_url =
Alex Vakulenko45109442014-07-29 11:07:10 -0700465 dev_reg_->GetServiceURL("registrationTickets/" +
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700466 std::string(test_data::kClaimTicketId));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700467 transport_->AddHandler(ticket_url + "/finalize",
468 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700469 base::Bind(FinalizeTicketHandler));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700470
Alex Vakulenkocca20932014-08-20 17:35:12 -0700471 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
472 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700473 base::Bind(OAuth2Handler));
Alex Vakulenko45109442014-07-29 11:07:10 -0700474 storage_->reset_save_count();
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400475
476 std::map<std::string, std::string> params;
477 params["ticket_id"] = test_data::kClaimTicketId;
478 std::string device_id = dev_reg_->RegisterDevice(params, nullptr);
479
480 EXPECT_EQ(test_data::kDeviceId, device_id);
Alex Vakulenko45109442014-07-29 11:07:10 -0700481 EXPECT_EQ(1,
482 storage_->save_count()); // The device info must have been saved.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400483 EXPECT_EQ(3, transport_->GetRequestCount());
Vitaly Bukab055f152015-03-12 13:41:43 -0700484 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700485
486 // Validate the device info saved to storage...
Alex Vakulenko45109442014-07-29 11:07:10 -0700487 auto storage_data = storage_->Load();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700488 base::DictionaryValue* dict = nullptr;
489 EXPECT_TRUE(storage_data->GetAsDictionary(&dict));
490 std::string value;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700491 EXPECT_TRUE(dict->GetString(storage_keys::kDeviceId, &value));
492 EXPECT_EQ(test_data::kDeviceId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700493 EXPECT_TRUE(dict->GetString(storage_keys::kRefreshToken, &value));
494 EXPECT_EQ(test_data::kRefreshToken, value);
495 EXPECT_TRUE(dict->GetString(storage_keys::kRobotAccount, &value));
496 EXPECT_EQ(test_data::kRobotAccountEmail, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700497}
498
Christopher Wileyc900e482015-02-15 15:42:04 -0800499TEST_F(DeviceRegistrationInfoTest, OOBRegistrationStatus) {
500 // After we've been initialized, we should be either offline or unregistered,
501 // depending on whether or not we've found credentials.
502 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700503 EXPECT_EQ(RegistrationStatus::kUnconfigured,
Christopher Wileyc900e482015-02-15 15:42:04 -0800504 dev_reg_->GetRegistrationStatus());
505 // Put some credentials into our state, make sure we call that offline.
506 SetDefaultDeviceRegistration(&data_);
507 storage_->Save(&data_);
508 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700509 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Christopher Wileyc900e482015-02-15 15:42:04 -0800510}
511
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700512TEST_F(DeviceRegistrationInfoTest, UpdateCommand) {
513 EXPECT_TRUE(dev_reg_->Load());
514 auto json_cmds = buffet::unittests::CreateDictionaryValue(R"({
515 'robot': {
516 '_jump': {
517 'parameters': {'_height': 'integer'},
518 'results': {'status': 'string'}
519 }
520 }
521 })");
522 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
523
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700524 const std::string command_url = dev_reg_->GetServiceURL("commands/1234");
525
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700526 auto commands_json = buffet::unittests::CreateValue(R"([{
527 'name':'robot._jump',
528 'id':'1234',
529 'parameters': {'_height': 100}
530 }])");
531 ASSERT_NE(nullptr, commands_json.get());
532 const base::ListValue* command_list = nullptr;
533 ASSERT_TRUE(commands_json->GetAsList(&command_list));
534 DeviceRegistrationInfo::TestHelper::PublishCommands(dev_reg_.get(),
535 *command_list);
536 auto command = command_manager_->FindCommand("1234");
537 ASSERT_NE(nullptr, command);
538 StringPropType string_type;
539 native_types::Object results{
540 {"status", string_type.CreateValue(std::string{"Ok"}, nullptr)}
541 };
542
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700543 // UpdateCommand when setting command results.
544 auto update_command_results = [](const ServerRequest& request,
545 ServerResponse* response) {
546 EXPECT_EQ(R"({"results":{"status":"Ok"}})",
547 request.GetDataAsNormalizedJsonString());
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700548 };
549
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700550 transport_->AddHandler(command_url,
551 chromeos::http::request_type::kPatch,
552 base::Bind(update_command_results));
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700553
554 command->SetResults(results);
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700555
556 // UpdateCommand when setting command progress.
557 int count = 0; // This will be called twice...
558 auto update_command_progress = [&count](const ServerRequest& request,
559 ServerResponse* response) {
560 if (count++ == 0) {
561 EXPECT_EQ(R"({"state":"inProgress"})",
562 request.GetDataAsNormalizedJsonString());
563 } else {
564 EXPECT_EQ(R"({"progress":{"progress":18}})",
565 request.GetDataAsNormalizedJsonString());
566 }
567 };
568
569 transport_->AddHandler(command_url,
570 chromeos::http::request_type::kPatch,
571 base::Bind(update_command_progress));
572
573 command->SetProgress(18);
574
575 // UpdateCommand when changing command status.
576 auto update_command_state = [](const ServerRequest& request,
577 ServerResponse* response) {
578 EXPECT_EQ(R"({"state":"cancelled"})",
579 request.GetDataAsNormalizedJsonString());
580 };
581
582 transport_->AddHandler(command_url,
583 chromeos::http::request_type::kPatch,
584 base::Bind(update_command_state));
585
586 command->Cancel();
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700587}
588
589
Alex Vakulenkocca20932014-08-20 17:35:12 -0700590} // namespace buffet