blob: ec68b216fab8b1777459e527d13655046dad28ed [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
Vitaly Buka32005de2015-05-01 12:33:31 -070024namespace buffet {
25
Alex Vakulenkocca20932014-08-20 17:35:12 -070026using chromeos::http::request_header::kAuthorization;
27using chromeos::http::fake::ServerRequest;
28using chromeos::http::fake::ServerResponse;
29
Alex Vakulenko8e34d392014-04-29 11:02:56 -070030namespace {
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
Alex Vakulenko8e34d392014-04-29 11:02:56 -070061// Add the test device registration information.
62void SetDefaultDeviceRegistration(base::DictionaryValue* data) {
63 data->SetString(storage_keys::kRefreshToken, test_data::kRefreshToken);
64 data->SetString(storage_keys::kDeviceId, test_data::kDeviceId);
65 data->SetString(storage_keys::kRobotAccount, test_data::kRobotAccountEmail);
66}
67
Alex Vakulenkocca20932014-08-20 17:35:12 -070068void OAuth2Handler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -070069 base::DictionaryValue json;
70 if (request.GetFormField("grant_type") == "refresh_token") {
71 // Refresh device access token.
72 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
73 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
74 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
75 json.SetString("access_token", test_data::kAccessToken);
76 } else if (request.GetFormField("grant_type") == "authorization_code") {
77 // Obtain access token.
78 std::string code = request.GetFormField("code");
79 if (code == test_data::kUserAccountAuthCode) {
80 // Get user access token.
81 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
82 EXPECT_EQ(test_data::kClientSecret,
83 request.GetFormField("client_secret"));
84 EXPECT_EQ("urn:ietf:wg:oauth:2.0:oob",
85 request.GetFormField("redirect_uri"));
86 json.SetString("access_token", test_data::kUserAccessToken);
87 json.SetString("token_type", "Bearer");
88 json.SetString("refresh_token", test_data::kUserRefreshToken);
89 } else if (code == test_data::kRobotAccountAuthCode) {
90 // Get device 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("oob", request.GetFormField("redirect_uri"));
95 EXPECT_EQ("https://www.googleapis.com/auth/clouddevices",
96 request.GetFormField("scope"));
97 json.SetString("access_token", test_data::kAccessToken);
98 json.SetString("token_type", "Bearer");
99 json.SetString("refresh_token", test_data::kRefreshToken);
100 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700101 FAIL() << "Unexpected authorization code";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700102 }
103 } else {
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700104 FAIL() << "Unexpected grant type";
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700105 }
106 json.SetInteger("expires_in", 3600);
Alex Vakulenkocca20932014-08-20 17:35:12 -0700107 response->ReplyJson(chromeos::http::status_code::Ok, &json);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700108}
109
Nathan Bullock24d189f2015-02-26 13:09:18 -0500110void OAuth2HandlerFail(const ServerRequest& request,
111 ServerResponse* response) {
112 base::DictionaryValue json;
113 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
114 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
115 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
116 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
117 json.SetString("error", "unable_to_authenticate");
118 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
119}
120
121void OAuth2HandlerDeregister(const ServerRequest& request,
122 ServerResponse* response) {
123 base::DictionaryValue json;
124 EXPECT_EQ("refresh_token", request.GetFormField("grant_type"));
125 EXPECT_EQ(test_data::kRefreshToken, request.GetFormField("refresh_token"));
126 EXPECT_EQ(test_data::kClientId, request.GetFormField("client_id"));
127 EXPECT_EQ(test_data::kClientSecret, request.GetFormField("client_secret"));
128 json.SetString("error", "invalid_grant");
129 response->ReplyJson(chromeos::http::status_code::BadRequest, &json);
130}
131
Alex Vakulenkocca20932014-08-20 17:35:12 -0700132void DeviceInfoHandler(const ServerRequest& request, ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700133 std::string auth = "Bearer ";
134 auth += test_data::kAccessToken;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700135 EXPECT_EQ(auth,
136 request.GetHeader(chromeos::http::request_header::kAuthorization));
137 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700138 {"channel.supportedType", "xmpp"},
139 {"deviceKind", "vendor"},
140 {"id", test_data::kDeviceId},
141 {"kind", "clouddevices#device"},
142 });
143}
144
Alex Vakulenkocca20932014-08-20 17:35:12 -0700145void FinalizeTicketHandler(const ServerRequest& request,
146 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700147 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
148 EXPECT_TRUE(request.GetData().empty());
149
Alex Vakulenkocca20932014-08-20 17:35:12 -0700150 response->ReplyJson(chromeos::http::status_code::Ok, {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700151 {"id", test_data::kClaimTicketId},
152 {"kind", "clouddevices#registrationTicket"},
153 {"oauthClientId", test_data::kClientId},
154 {"userEmail", "user@email.com"},
155 {"deviceDraft.id", test_data::kDeviceId},
156 {"deviceDraft.kind", "clouddevices#device"},
157 {"deviceDraft.channel.supportedType", "xmpp"},
158 {"robotAccountEmail", test_data::kRobotAccountEmail},
159 {"robotAccountAuthorizationCode", test_data::kRobotAccountAuthCode},
160 });
161}
162
163} // anonymous namespace
164
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500165// This is a helper class that allows the unit tests to access private
166// methods and data since TestHelper is declared as a friend to
167// DeviceRegistrationInfo.
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700168class DeviceRegistrationInfo::TestHelper {
169 public:
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500170 static bool Save(DeviceRegistrationInfo* info) {
171 return info->Save();
172 }
Nathan Bullock5e022a32015-04-08 15:13:07 -0400173
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700174 static void PublishCommands(DeviceRegistrationInfo* info,
175 const base::ListValue& commands) {
176 return info->PublishCommands(commands);
177 }
Nathan Bullock5e022a32015-04-08 15:13:07 -0400178
179 static bool CheckRegistration(DeviceRegistrationInfo* info,
180 chromeos::ErrorPtr* error) {
181 return info->CheckRegistration(error);
182 }
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700183};
184
185class DeviceRegistrationInfoTest : public ::testing::Test {
186 protected:
Alex Vakulenko5a9e7182014-08-11 15:59:58 -0700187 void SetUp() override {
Alex Vakulenko45109442014-07-29 11:07:10 -0700188 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>();
Vitaly Bukaae0f3a12015-05-11 16:27:30 -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");
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700198 config_store.SetString("name", "Coffee Pot");
Vitaly Buka867b0882015-04-16 10:03:26 -0700199 config_store.SetString("description", "Easy to clean");
200 config_store.SetString("location", "Kitchen");
Vitaly Buka2c1029f2015-04-30 22:47:18 -0700201 config_store.SetString("anonymous_access_role", "viewer");
Vitaly Buka867b0882015-04-16 10:03:26 -0700202 config_store.SetString("model_id", "AAAAA");
Christopher Wiley583d64b2015-03-24 14:30:17 -0700203 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);
Alex Vakulenko45109442014-07-29 11:07:10 -0700207 dev_reg_ = std::unique_ptr<DeviceRegistrationInfo>(
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700208 new DeviceRegistrationInfo(command_manager_, state_manager_,
Christopher Wiley583d64b2015-03-24 14:30:17 -0700209 std::move(config),
Christopher Wileyc900e482015-02-15 15:42:04 -0800210 transport_, storage_,
Christopher Wileyd732bd02015-04-07 11:11:18 -0700211 true,
Vitaly Bukafa947062015-04-17 00:41:31 -0700212 nullptr));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700213 }
214
Alex Vakulenko45109442014-07-29 11:07:10 -0700215 base::DictionaryValue data_;
216 std::shared_ptr<MemStorage> storage_;
Alex Vakulenkocca20932014-08-20 17:35:12 -0700217 std::shared_ptr<chromeos::http::fake::Transport> transport_;
Alex Vakulenko45109442014-07-29 11:07:10 -0700218 std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
219 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko57123b22014-10-28 13:50:16 -0700220 testing::NiceMock<MockStateChangeQueueInterface> mock_state_change_queue_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700221 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700222};
223
224////////////////////////////////////////////////////////////////////////////////
225TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700226 EXPECT_TRUE(dev_reg_->Load());
227 EXPECT_EQ(test_data::kServiceURL, dev_reg_->GetServiceURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700228 std::string url = test_data::kServiceURL;
229 url += "registrationTickets";
Alex Vakulenko45109442014-07-29 11:07:10 -0700230 EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets"));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700231 url += "?key=";
232 url += test_data::kApiKey;
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 }));
236 url += "&restart=true";
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 {"restart", "true"},
240 }));
241}
242
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500243TEST_F(DeviceRegistrationInfoTest, VerifySave) {
244 base::DictionaryValue data;
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500245 data.SetString(storage_keys::kRefreshToken, "d");
246 data.SetString(storage_keys::kDeviceId, "e");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500247 data.SetString(storage_keys::kRobotAccount, "h");
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700248 data.SetString(storage_keys::kName, "k");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500249 data.SetString(storage_keys::kDescription, "l");
250 data.SetString(storage_keys::kLocation, "m");
Vitaly Buka2c1029f2015-04-30 22:47:18 -0700251 data.SetString(storage_keys::kAnonymousAccessRole, "user");
Nathan Bullock02ca28b2015-02-11 16:22:16 -0500252
253 storage_->Save(&data);
254
255 // This test isn't really trying to test Load, it is just the easiest
256 // way to initialize the properties in dev_reg_.
257 EXPECT_TRUE(dev_reg_->Load());
258
259 // Clear the storage to get a clean test.
260 base::DictionaryValue empty;
261 storage_->Save(&empty);
262 EXPECT_TRUE(DeviceRegistrationInfo::TestHelper::Save(dev_reg_.get()));
263 EXPECT_TRUE(storage_->Load()->Equals(&data));
264}
265
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700266TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700267 EXPECT_TRUE(dev_reg_->Load());
268 EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700269 std::string url = test_data::kOAuthURL;
270 url += "auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fclouddevices&";
271 url += "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
272 url += "response_type=code&";
273 url += "client_id=";
274 url += test_data::kClientId;
Alex Vakulenko45109442014-07-29 11:07:10 -0700275 EXPECT_EQ(url, dev_reg_->GetOAuthURL("auth", {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700276 {"scope", "https://www.googleapis.com/auth/clouddevices"},
277 {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
278 {"response_type", "code"},
279 {"client_id", test_data::kClientId}
280 }));
281}
282
283TEST_F(DeviceRegistrationInfoTest, CheckRegistration) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700284 EXPECT_TRUE(dev_reg_->Load());
Nathan Bullock5e022a32015-04-08 15:13:07 -0400285 EXPECT_FALSE(DeviceRegistrationInfo::TestHelper::CheckRegistration(
286 dev_reg_.get(), nullptr));
Alex Vakulenko45109442014-07-29 11:07:10 -0700287 EXPECT_EQ(0, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700288
Alex Vakulenko45109442014-07-29 11:07:10 -0700289 SetDefaultDeviceRegistration(&data_);
290 storage_->Save(&data_);
291 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700292
Alex Vakulenkocca20932014-08-20 17:35:12 -0700293 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
294 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700295 base::Bind(OAuth2Handler));
296 transport_->ResetRequestCount();
Nathan Bullock5e022a32015-04-08 15:13:07 -0400297 EXPECT_TRUE(DeviceRegistrationInfo::TestHelper::CheckRegistration(
298 dev_reg_.get(), nullptr));
Alex Vakulenko45109442014-07-29 11:07:10 -0700299 EXPECT_EQ(1, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700300}
301
Nathan Bullock24d189f2015-02-26 13:09:18 -0500302TEST_F(DeviceRegistrationInfoTest, CheckAuthenticationFailure) {
303 SetDefaultDeviceRegistration(&data_);
304 storage_->Save(&data_);
305 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700306 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500307
308 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
309 chromeos::http::request_type::kPost,
310 base::Bind(OAuth2HandlerFail));
311 transport_->ResetRequestCount();
312 chromeos::ErrorPtr error;
Nathan Bullock5e022a32015-04-08 15:13:07 -0400313 EXPECT_FALSE(DeviceRegistrationInfo::TestHelper::CheckRegistration(
314 dev_reg_.get(), &error));
Nathan Bullock24d189f2015-02-26 13:09:18 -0500315 EXPECT_EQ(1, transport_->GetRequestCount());
Vitaly Buka32005de2015-05-01 12:33:31 -0700316 EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "unable_to_authenticate"));
Vitaly Bukab055f152015-03-12 13:41:43 -0700317 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500318}
319
320TEST_F(DeviceRegistrationInfoTest, CheckDeregistration) {
321 SetDefaultDeviceRegistration(&data_);
322 storage_->Save(&data_);
323 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700324 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Nathan Bullock24d189f2015-02-26 13:09:18 -0500325
326 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
327 chromeos::http::request_type::kPost,
328 base::Bind(OAuth2HandlerDeregister));
329 transport_->ResetRequestCount();
330 chromeos::ErrorPtr error;
Nathan Bullock5e022a32015-04-08 15:13:07 -0400331 EXPECT_FALSE(DeviceRegistrationInfo::TestHelper::CheckRegistration(
332 dev_reg_.get(), &error));
Nathan Bullock24d189f2015-02-26 13:09:18 -0500333 EXPECT_EQ(1, transport_->GetRequestCount());
Vitaly Buka32005de2015-05-01 12:33:31 -0700334 EXPECT_TRUE(error->HasError(kErrorDomainOAuth2, "invalid_grant"));
Nathan Bullock24d189f2015-02-26 13:09:18 -0500335 EXPECT_EQ(RegistrationStatus::kInvalidCredentials,
336 dev_reg_->GetRegistrationStatus());
337}
338
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700339TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700340 SetDefaultDeviceRegistration(&data_);
341 storage_->Save(&data_);
342 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700343
Alex Vakulenkocca20932014-08-20 17:35:12 -0700344 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
345 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700346 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700347 transport_->AddHandler(dev_reg_->GetDeviceURL(),
348 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700349 base::Bind(DeviceInfoHandler));
350 transport_->ResetRequestCount();
351 auto device_info = dev_reg_->GetDeviceInfo(nullptr);
352 EXPECT_EQ(2, transport_->GetRequestCount());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700353 EXPECT_NE(nullptr, device_info.get());
354 base::DictionaryValue* dict = nullptr;
355 EXPECT_TRUE(device_info->GetAsDictionary(&dict));
356 std::string id;
357 EXPECT_TRUE(dict->GetString("id", &id));
358 EXPECT_EQ(test_data::kDeviceId, id);
359}
360
361TEST_F(DeviceRegistrationInfoTest, GetDeviceId) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700362 SetDefaultDeviceRegistration(&data_);
363 storage_->Save(&data_);
364 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700365
Alex Vakulenkocca20932014-08-20 17:35:12 -0700366 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
367 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700368 base::Bind(OAuth2Handler));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700369 transport_->AddHandler(dev_reg_->GetDeviceURL(),
370 chromeos::http::request_type::kGet,
Alex Vakulenko45109442014-07-29 11:07:10 -0700371 base::Bind(DeviceInfoHandler));
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700372 EXPECT_EQ(test_data::kDeviceId, dev_reg_->GetDeviceId());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700373}
374
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400375TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
Alex Vakulenko45109442014-07-29 11:07:10 -0700376 EXPECT_TRUE(dev_reg_->Load());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700377
Anton Muhina4803142014-09-24 19:30:45 +0400378 auto update_ticket = [](const ServerRequest& request,
Alex Vakulenkocca20932014-08-20 17:35:12 -0700379 ServerResponse* response) {
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700380 EXPECT_EQ(test_data::kApiKey, request.GetFormField("key"));
381 auto json = request.GetDataAsJson();
382 EXPECT_NE(nullptr, json.get());
383 std::string value;
Anton Muhina4803142014-09-24 19:30:45 +0400384 EXPECT_TRUE(json->GetString("id", &value));
385 EXPECT_EQ(test_data::kClaimTicketId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700386 EXPECT_TRUE(json->GetString("deviceDraft.channel.supportedType", &value));
387 EXPECT_EQ("xmpp", value);
388 EXPECT_TRUE(json->GetString("oauthClientId", &value));
389 EXPECT_EQ(test_data::kClientId, value);
390 EXPECT_TRUE(json->GetString("deviceDraft.deviceKind", &value));
391 EXPECT_EQ("vendor", value);
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800392 EXPECT_TRUE(json->GetString("deviceDraft.description", &value));
393 EXPECT_EQ("Easy to clean", value);
394 EXPECT_TRUE(json->GetString("deviceDraft.location", &value));
395 EXPECT_EQ("Kitchen", value);
Vitaly Buka6522ab62015-02-19 10:26:31 -0800396 EXPECT_TRUE(json->GetString("deviceDraft.modelManifestId", &value));
Vitaly Buka867b0882015-04-16 10:03:26 -0700397 EXPECT_EQ("AAAAA", value);
Alex Vakulenko468f7f32015-04-08 10:42:45 -0700398 EXPECT_TRUE(json->GetString("deviceDraft.name", &value));
Vitaly Bukad3eb19c2014-11-21 13:39:43 -0800399 EXPECT_EQ("Coffee Pot", value);
Alex Vakulenko45109442014-07-29 11:07:10 -0700400 base::DictionaryValue* commandDefs = nullptr;
401 EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
402 EXPECT_FALSE(commandDefs->empty());
Vitaly Buka7c82d292015-05-03 18:08:12 -0700403
404 auto expected = R"({
405 'base': {
406 'reboot': {
407 'parameters': {
408 'delay': {
409 'minimum': 10,
410 'type': 'integer'
411 }
412 }
413 }
414 },
415 'robot': {
416 '_jump': {
417 'parameters': {
418 '_height': {
419 'type': 'integer'
420 }
421 }
422 }
423 }
424 })";
425 EXPECT_JSON_EQ(expected, *commandDefs);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700426
427 base::DictionaryValue json_resp;
428 json_resp.SetString("id", test_data::kClaimTicketId);
429 json_resp.SetString("kind", "clouddevices#registrationTicket");
430 json_resp.SetString("oauthClientId", test_data::kClientId);
431 base::DictionaryValue* device_draft = nullptr;
432 EXPECT_TRUE(json->GetDictionary("deviceDraft", &device_draft));
433 device_draft = device_draft->DeepCopy();
434 device_draft->SetString("id", test_data::kDeviceId);
435 device_draft->SetString("kind", "clouddevices#device");
436 json_resp.Set("deviceDraft", device_draft);
437
Alex Vakulenkocca20932014-08-20 17:35:12 -0700438 response->ReplyJson(chromeos::http::status_code::Ok, &json_resp);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700439 };
440
Vitaly Buka32005de2015-05-01 12:33:31 -0700441 auto json_base = unittests::CreateDictionaryValue(R"({
Alex Vakulenko45109442014-07-29 11:07:10 -0700442 'base': {
443 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400444 'parameters': {'delay': 'integer'},
445 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700446 },
447 'shutdown': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400448 'parameters': {},
449 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700450 }
451 }
452 })");
453 EXPECT_TRUE(command_manager_->LoadBaseCommands(*json_base, nullptr));
Vitaly Buka32005de2015-05-01 12:33:31 -0700454 auto json_cmds = unittests::CreateDictionaryValue(R"({
Alex Vakulenko45109442014-07-29 11:07:10 -0700455 'base': {
456 'reboot': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400457 'parameters': {'delay': {'minimum': 10}},
458 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700459 }
460 },
461 'robot': {
462 '_jump': {
Anton Muhin71fb9d52014-11-21 22:22:39 +0400463 'parameters': {'_height': 'integer'},
464 'results': {}
Alex Vakulenko45109442014-07-29 11:07:10 -0700465 }
466 }
467 })");
468 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
469
Anton Muhina4803142014-09-24 19:30:45 +0400470 transport_->AddHandler(dev_reg_->GetServiceURL(
471 std::string("registrationTickets/") + test_data::kClaimTicketId),
472 chromeos::http::request_type::kPatch,
473 base::Bind(update_ticket));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700474 std::string ticket_url =
Alex Vakulenko45109442014-07-29 11:07:10 -0700475 dev_reg_->GetServiceURL("registrationTickets/" +
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700476 std::string(test_data::kClaimTicketId));
Alex Vakulenkocca20932014-08-20 17:35:12 -0700477 transport_->AddHandler(ticket_url + "/finalize",
478 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700479 base::Bind(FinalizeTicketHandler));
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700480
Alex Vakulenkocca20932014-08-20 17:35:12 -0700481 transport_->AddHandler(dev_reg_->GetOAuthURL("token"),
482 chromeos::http::request_type::kPost,
Alex Vakulenko45109442014-07-29 11:07:10 -0700483 base::Bind(OAuth2Handler));
Alex Vakulenko45109442014-07-29 11:07:10 -0700484 storage_->reset_save_count();
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400485
486 std::map<std::string, std::string> params;
487 params["ticket_id"] = test_data::kClaimTicketId;
488 std::string device_id = dev_reg_->RegisterDevice(params, nullptr);
489
490 EXPECT_EQ(test_data::kDeviceId, device_id);
Vitaly Bukacf5248c2015-04-30 18:49:08 -0700491 EXPECT_GT(storage_->save_count(), 1); // The state must have been saved.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400492 EXPECT_EQ(3, transport_->GetRequestCount());
Vitaly Bukab055f152015-03-12 13:41:43 -0700493 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700494
495 // Validate the device info saved to storage...
Alex Vakulenko45109442014-07-29 11:07:10 -0700496 auto storage_data = storage_->Load();
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700497 base::DictionaryValue* dict = nullptr;
498 EXPECT_TRUE(storage_data->GetAsDictionary(&dict));
499 std::string value;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700500 EXPECT_TRUE(dict->GetString(storage_keys::kDeviceId, &value));
501 EXPECT_EQ(test_data::kDeviceId, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700502 EXPECT_TRUE(dict->GetString(storage_keys::kRefreshToken, &value));
503 EXPECT_EQ(test_data::kRefreshToken, value);
504 EXPECT_TRUE(dict->GetString(storage_keys::kRobotAccount, &value));
505 EXPECT_EQ(test_data::kRobotAccountEmail, value);
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700506}
507
Christopher Wileyc900e482015-02-15 15:42:04 -0800508TEST_F(DeviceRegistrationInfoTest, OOBRegistrationStatus) {
509 // After we've been initialized, we should be either offline or unregistered,
510 // depending on whether or not we've found credentials.
511 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700512 EXPECT_EQ(RegistrationStatus::kUnconfigured,
Christopher Wileyc900e482015-02-15 15:42:04 -0800513 dev_reg_->GetRegistrationStatus());
514 // Put some credentials into our state, make sure we call that offline.
515 SetDefaultDeviceRegistration(&data_);
516 storage_->Save(&data_);
517 EXPECT_TRUE(dev_reg_->Load());
Vitaly Bukab055f152015-03-12 13:41:43 -0700518 EXPECT_EQ(RegistrationStatus::kConnecting, dev_reg_->GetRegistrationStatus());
Christopher Wileyc900e482015-02-15 15:42:04 -0800519}
520
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700521TEST_F(DeviceRegistrationInfoTest, UpdateCommand) {
522 EXPECT_TRUE(dev_reg_->Load());
Vitaly Buka32005de2015-05-01 12:33:31 -0700523 auto json_cmds = unittests::CreateDictionaryValue(R"({
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700524 'robot': {
525 '_jump': {
526 'parameters': {'_height': 'integer'},
527 'results': {'status': 'string'}
528 }
529 }
530 })");
531 EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
532
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700533 const std::string command_url = dev_reg_->GetServiceURL("commands/1234");
534
Vitaly Buka32005de2015-05-01 12:33:31 -0700535 auto commands_json = unittests::CreateValue(R"([{
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700536 'name':'robot._jump',
537 'id':'1234',
538 'parameters': {'_height': 100}
539 }])");
540 ASSERT_NE(nullptr, commands_json.get());
541 const base::ListValue* command_list = nullptr;
542 ASSERT_TRUE(commands_json->GetAsList(&command_list));
543 DeviceRegistrationInfo::TestHelper::PublishCommands(dev_reg_.get(),
544 *command_list);
545 auto command = command_manager_->FindCommand("1234");
546 ASSERT_NE(nullptr, command);
547 StringPropType string_type;
548 native_types::Object results{
549 {"status", string_type.CreateValue(std::string{"Ok"}, nullptr)}
550 };
551
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700552 // UpdateCommand when setting command results.
553 auto update_command_results = [](const ServerRequest& request,
554 ServerResponse* response) {
555 EXPECT_EQ(R"({"results":{"status":"Ok"}})",
556 request.GetDataAsNormalizedJsonString());
Alex Vakulenkob211c102015-04-21 11:43:23 -0700557 response->ReplyJson(chromeos::http::status_code::Ok,
558 chromeos::http::FormFieldList{});
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700559 };
560
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700561 transport_->AddHandler(command_url,
562 chromeos::http::request_type::kPatch,
563 base::Bind(update_command_results));
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700564
565 command->SetResults(results);
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700566
567 // UpdateCommand when setting command progress.
568 int count = 0; // This will be called twice...
569 auto update_command_progress = [&count](const ServerRequest& request,
570 ServerResponse* response) {
571 if (count++ == 0) {
572 EXPECT_EQ(R"({"state":"inProgress"})",
573 request.GetDataAsNormalizedJsonString());
574 } else {
575 EXPECT_EQ(R"({"progress":{"progress":18}})",
576 request.GetDataAsNormalizedJsonString());
577 }
Alex Vakulenkob211c102015-04-21 11:43:23 -0700578 response->ReplyJson(chromeos::http::status_code::Ok,
579 chromeos::http::FormFieldList{});
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700580 };
581
582 transport_->AddHandler(command_url,
583 chromeos::http::request_type::kPatch,
584 base::Bind(update_command_progress));
585
Vitaly Buka4129dfa2015-04-29 12:16:58 -0700586 native_types::Object progress{
587 {"progress", unittests::make_int_prop_value(18)}};
588 command->SetProgress(progress);
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700589
590 // UpdateCommand when changing command status.
591 auto update_command_state = [](const ServerRequest& request,
592 ServerResponse* response) {
593 EXPECT_EQ(R"({"state":"cancelled"})",
594 request.GetDataAsNormalizedJsonString());
Alex Vakulenkob211c102015-04-21 11:43:23 -0700595 response->ReplyJson(chromeos::http::status_code::Ok,
596 chromeos::http::FormFieldList{});
Alex Vakulenko808e2d82015-04-08 15:45:56 -0700597 };
598
599 transport_->AddHandler(command_url,
600 chromeos::http::request_type::kPatch,
601 base::Bind(update_command_state));
602
603 command->Cancel();
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -0700604}
605
606
Alex Vakulenkocca20932014-08-20 17:35:12 -0700607} // namespace buffet