buffet: Add GCD device draft record to device registration
Use the command definitions provided by Command Manager in
device registration record sent to GCD server.
BUG=chromium:396716
TEST=USE=buffet P2_TEST_FILTER="buffet::*" FEATURES=test emerge-link platform2
Change-Id: If9109bfee8862d9252cdb03301a4362492064809
Reviewed-on: https://chromium-review.googlesource.com/210146
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/commands/command_dictionary.cc b/buffet/commands/command_dictionary.cc
index dcba8c9..e011a23 100644
--- a/buffet/commands/command_dictionary.cc
+++ b/buffet/commands/command_dictionary.cc
@@ -145,6 +145,34 @@
return true;
}
+std::unique_ptr<base::DictionaryValue> CommandDictionary::GetCommandsAsJson(
+ bool full_schema, ErrorPtr* error) const {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
+ for (const auto& pair : definitions_) {
+ std::unique_ptr<base::DictionaryValue> definition =
+ pair.second->GetParameters()->ToJson(full_schema, error);
+ if (!definition) {
+ dict.reset();
+ return dict;
+ }
+ auto cmd_name_parts = string_utils::SplitAtFirst(pair.first, '.');
+ std::string package_name = cmd_name_parts.first;
+ std::string command_name = cmd_name_parts.second;
+ base::DictionaryValue* package = nullptr;
+ if (!dict->GetDictionaryWithoutPathExpansion(package_name, &package)) {
+ // If this is the first time we encounter this package, create a JSON
+ // object for it.
+ package = new base::DictionaryValue;
+ dict->SetWithoutPathExpansion(package_name, package);
+ }
+ base::DictionaryValue* command_def = new base::DictionaryValue;
+ command_def->SetWithoutPathExpansion(
+ commands::attributes::kCommand_Parameters, definition.release());
+ package->SetWithoutPathExpansion(command_name, command_def);
+ }
+ return dict;
+}
+
const CommandDefinition* CommandDictionary::FindCommand(
const std::string& command_name) const {
auto pair = definitions_.find(command_name);
diff --git a/buffet/commands/command_dictionary.h b/buffet/commands/command_dictionary.h
index 78f2cee..b656684 100644
--- a/buffet/commands/command_dictionary.h
+++ b/buffet/commands/command_dictionary.h
@@ -54,6 +54,13 @@
bool LoadCommands(const base::DictionaryValue& json,
const std::string& category,
const CommandDictionary* base_commands, ErrorPtr* error);
+ // Converts all the command definitions to a JSON object for CDD/Device
+ // draft. |full_schema| specifies whether full command definitions must
+ // be generated (true) for CDD or only overrides from the base schema (false).
+ // Returns empty unique_ptr in case of an error and fills in the additional
+ // error details in |error|.
+ std::unique_ptr<base::DictionaryValue> GetCommandsAsJson(
+ bool full_schema, ErrorPtr* error) const;
// Returns the number of command definitions in the dictionary.
size_t GetSize() const { return definitions_.size(); }
// Checks if the dictionary has no command definitions.
diff --git a/buffet/commands/command_dictionary_unittest.cc b/buffet/commands/command_dictionary_unittest.cc
index 0aeab50..30d185f 100644
--- a/buffet/commands/command_dictionary_unittest.cc
+++ b/buffet/commands/command_dictionary_unittest.cc
@@ -165,3 +165,46 @@
error->GetFirstError()->GetMessage());
error.reset();
}
+
+TEST(CommandDictionary, GetCommandsAsJson) {
+ auto json_base = CreateDictionaryValue(R"({
+ 'base': {
+ 'reboot': {
+ 'parameters': {'delay': {'maximum': 100}}
+ },
+ 'shutdown': {
+ 'parameters': {}
+ }
+ }
+ })");
+ buffet::CommandDictionary base_dict;
+ base_dict.LoadCommands(*json_base, "base", nullptr, nullptr);
+
+ auto json = buffet::unittests::CreateDictionaryValue(R"({
+ 'base': {
+ 'reboot': {
+ 'parameters': {'delay': {'minimum': 10}}
+ }
+ },
+ 'robot': {
+ '_jump': {
+ 'parameters': {'_height': 'integer'}
+ }
+ }
+ })");
+ buffet::CommandDictionary dict;
+ dict.LoadCommands(*json, "device", &base_dict, nullptr);
+
+ json = dict.GetCommandsAsJson(false, nullptr);
+ EXPECT_NE(nullptr, json.get());
+ EXPECT_EQ("{'base':{'reboot':{'parameters':{'delay':{'minimum':10}}}},"
+ "'robot':{'_jump':{'parameters':{'_height':'integer'}}}}",
+ buffet::unittests::ValueToString(json.get()));
+
+ json = dict.GetCommandsAsJson(true, nullptr);
+ EXPECT_NE(nullptr, json.get());
+ EXPECT_EQ("{'base':{'reboot':{'parameters':{'delay':{"
+ "'maximum':100,'minimum':10,'type':'integer'}}}},"
+ "'robot':{'_jump':{'parameters':{'_height':{'type':'integer'}}}}}",
+ buffet::unittests::ValueToString(json.get()));
+}
diff --git a/buffet/device_registration_info.cc b/buffet/device_registration_info.cc
index 0ec3de7..6c21429 100644
--- a/buffet/device_registration_info.cc
+++ b/buffet/device_registration_info.cc
@@ -11,6 +11,8 @@
#include <base/json/json_writer.h>
#include <base/values.h>
+#include "buffet/commands/command_definition.h"
+#include "buffet/commands/command_manager.h"
#include "buffet/data_encoding.h"
#include "buffet/device_registration_storage_keys.h"
#include "buffet/http_transport_curl.h"
@@ -356,36 +358,18 @@
if (!CheckParam(storage_keys::kServiceURL, service_url_, error))
return std::string();
- std::vector<std::pair<std::string, std::vector<std::string>>> commands = {
- {"SetDeviceConfiguration", {"data"}}
- };
+ std::unique_ptr<base::DictionaryValue> commands =
+ command_manager_->GetCommandDictionary().GetCommandsAsJson(true, error);
+ if (!commands)
+ return std::string();
base::DictionaryValue req_json;
- base::ListValue* set_device_configuration_params = new base::ListValue;
- base::DictionaryValue* param1 = new base::DictionaryValue;
- param1->SetString("name", "data");
- set_device_configuration_params->Append(param1);
-
- base::ListValue* vendor_commands = new base::ListValue;
- for (const auto& pair : commands) {
- base::ListValue* params = new base::ListValue;
- for (const auto& param_name : pair.second) {
- base::DictionaryValue* param = new base::DictionaryValue;
- param->SetString("name", param_name);
- params->Append(param);
- }
- base::DictionaryValue* command = new base::DictionaryValue;
- command->SetString("name", pair.first);
- command->Set("parameter", params);
- vendor_commands->Append(command);
- }
-
req_json.SetString("oauthClientId", client_id_);
req_json.SetString("deviceDraft.deviceKind", device_kind_);
req_json.SetString("deviceDraft.systemName", system_name_);
req_json.SetString("deviceDraft.displayName", display_name_);
req_json.SetString("deviceDraft.channel.supportedType", "xmpp");
- req_json.Set("deviceDraft.commands.base.vendorCommands", vendor_commands);
+ req_json.Set("deviceDraft.commandDefs", commands.release());
std::string url = GetServiceURL("registrationTickets", {{"key", api_key_}});
auto resp_json = http::ParseJsonResponse(
diff --git a/buffet/device_registration_info_unittest.cc b/buffet/device_registration_info_unittest.cc
index b8059cd..5f5d8ca 100644
--- a/buffet/device_registration_info_unittest.cc
+++ b/buffet/device_registration_info_unittest.cc
@@ -8,6 +8,7 @@
#include "buffet/bind_lambda.h"
#include "buffet/commands/command_manager.h"
+#include "buffet/commands/unittest_utils.h"
#include "buffet/device_registration_info.h"
#include "buffet/device_registration_storage_keys.h"
#include "buffet/http_request.h"
@@ -157,50 +158,51 @@
class DeviceRegistrationInfoTest : public ::testing::Test {
protected:
virtual void SetUp() override {
- InitDefaultStorage(&data);
- storage = std::make_shared<MemStorage>();
- storage->Save(&data);
- transport = std::make_shared<fake::Transport>();
- dev_reg = std::unique_ptr<DeviceRegistrationInfo>(
- new DeviceRegistrationInfo(std::make_shared<CommandManager>(),
- transport, storage));
+ InitDefaultStorage(&data_);
+ storage_ = std::make_shared<MemStorage>();
+ storage_->Save(&data_);
+ transport_ = std::make_shared<fake::Transport>();
+ command_manager_ = std::make_shared<CommandManager>();
+ dev_reg_ = std::unique_ptr<DeviceRegistrationInfo>(
+ new DeviceRegistrationInfo(command_manager_, transport_, storage_));
}
- base::DictionaryValue data;
- std::shared_ptr<MemStorage> storage;
- std::shared_ptr<fake::Transport> transport;
- std::unique_ptr<DeviceRegistrationInfo> dev_reg;
+ base::DictionaryValue data_;
+ std::shared_ptr<MemStorage> storage_;
+ std::shared_ptr<fake::Transport> transport_;
+ std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
+ std::shared_ptr<CommandManager> command_manager_;
};
////////////////////////////////////////////////////////////////////////////////
TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
- EXPECT_TRUE(dev_reg->Load());
- EXPECT_EQ(test_data::kServiceURL, dev_reg->GetServiceURL());
+ EXPECT_TRUE(dev_reg_->Load());
+ EXPECT_EQ(test_data::kServiceURL, dev_reg_->GetServiceURL());
std::string url = test_data::kServiceURL;
url += "registrationTickets";
- EXPECT_EQ(url, dev_reg->GetServiceURL("registrationTickets"));
+ EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets"));
url += "?key=";
url += test_data::kApiKey;
- EXPECT_EQ(url, dev_reg->GetServiceURL("registrationTickets", {
+ EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
{"key", test_data::kApiKey}
}));
url += "&restart=true";
- EXPECT_EQ(url, dev_reg->GetServiceURL("registrationTickets", {
+ EXPECT_EQ(url, dev_reg_->GetServiceURL("registrationTickets", {
{"key", test_data::kApiKey},
{"restart", "true"},
}));
}
TEST_F(DeviceRegistrationInfoTest, GetOAuthURL) {
- EXPECT_TRUE(dev_reg->Load());
- EXPECT_EQ(test_data::kOAuthURL, dev_reg->GetOAuthURL());
+ EXPECT_TRUE(dev_reg_->Load());
+ EXPECT_EQ(test_data::kOAuthURL, dev_reg_->GetOAuthURL());
std::string url = test_data::kOAuthURL;
url += "auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fclouddevices&";
url += "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&";
url += "response_type=code&";
url += "client_id=";
url += test_data::kClientId;
- EXPECT_EQ(url, dev_reg->GetOAuthURL("auth", {
+ EXPECT_EQ(url, dev_reg_->GetOAuthURL("auth", {
{"scope", "https://www.googleapis.com/auth/clouddevices"},
{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
{"response_type", "code"},
@@ -209,33 +211,33 @@
}
TEST_F(DeviceRegistrationInfoTest, CheckRegistration) {
- EXPECT_TRUE(dev_reg->Load());
- EXPECT_FALSE(dev_reg->CheckRegistration(nullptr));
- EXPECT_EQ(0, transport->GetRequestCount());
+ EXPECT_TRUE(dev_reg_->Load());
+ EXPECT_FALSE(dev_reg_->CheckRegistration(nullptr));
+ EXPECT_EQ(0, transport_->GetRequestCount());
- SetDefaultDeviceRegistration(&data);
- storage->Save(&data);
- EXPECT_TRUE(dev_reg->Load());
+ SetDefaultDeviceRegistration(&data_);
+ storage_->Save(&data_);
+ EXPECT_TRUE(dev_reg_->Load());
- transport->AddHandler(dev_reg->GetOAuthURL("token"), request_type::kPost,
- base::Bind(OAuth2Handler));
- transport->ResetRequestCount();
- EXPECT_TRUE(dev_reg->CheckRegistration(nullptr));
- EXPECT_EQ(1, transport->GetRequestCount());
+ transport_->AddHandler(dev_reg_->GetOAuthURL("token"), request_type::kPost,
+ base::Bind(OAuth2Handler));
+ transport_->ResetRequestCount();
+ EXPECT_TRUE(dev_reg_->CheckRegistration(nullptr));
+ EXPECT_EQ(1, transport_->GetRequestCount());
}
TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) {
- SetDefaultDeviceRegistration(&data);
- storage->Save(&data);
- EXPECT_TRUE(dev_reg->Load());
+ SetDefaultDeviceRegistration(&data_);
+ storage_->Save(&data_);
+ EXPECT_TRUE(dev_reg_->Load());
- transport->AddHandler(dev_reg->GetOAuthURL("token"), request_type::kPost,
- base::Bind(OAuth2Handler));
- transport->AddHandler(dev_reg->GetDeviceURL(), request_type::kGet,
- base::Bind(DeviceInfoHandler));
- transport->ResetRequestCount();
- auto device_info = dev_reg->GetDeviceInfo(nullptr);
- EXPECT_EQ(2, transport->GetRequestCount());
+ transport_->AddHandler(dev_reg_->GetOAuthURL("token"), request_type::kPost,
+ base::Bind(OAuth2Handler));
+ transport_->AddHandler(dev_reg_->GetDeviceURL(), request_type::kGet,
+ base::Bind(DeviceInfoHandler));
+ transport_->ResetRequestCount();
+ auto device_info = dev_reg_->GetDeviceInfo(nullptr);
+ EXPECT_EQ(2, transport_->GetRequestCount());
EXPECT_NE(nullptr, device_info.get());
base::DictionaryValue* dict = nullptr;
EXPECT_TRUE(device_info->GetAsDictionary(&dict));
@@ -245,20 +247,20 @@
}
TEST_F(DeviceRegistrationInfoTest, GetDeviceId) {
- SetDefaultDeviceRegistration(&data);
- storage->Save(&data);
- EXPECT_TRUE(dev_reg->Load());
+ SetDefaultDeviceRegistration(&data_);
+ storage_->Save(&data_);
+ EXPECT_TRUE(dev_reg_->Load());
- transport->AddHandler(dev_reg->GetOAuthURL("token"), request_type::kPost,
- base::Bind(OAuth2Handler));
- transport->AddHandler(dev_reg->GetDeviceURL(), request_type::kGet,
- base::Bind(DeviceInfoHandler));
- std::string id = dev_reg->GetDeviceId(nullptr);
+ transport_->AddHandler(dev_reg_->GetOAuthURL("token"), request_type::kPost,
+ base::Bind(OAuth2Handler));
+ transport_->AddHandler(dev_reg_->GetDeviceURL(), request_type::kGet,
+ base::Bind(DeviceInfoHandler));
+ std::string id = dev_reg_->GetDeviceId(nullptr);
EXPECT_EQ(test_data::kDeviceId, id);
}
TEST_F(DeviceRegistrationInfoTest, StartRegistration) {
- EXPECT_TRUE(dev_reg->Load());
+ EXPECT_TRUE(dev_reg_->Load());
auto create_ticket = [](const fake::ServerRequest& request,
fake::ServerResponse* response) {
@@ -272,6 +274,14 @@
EXPECT_EQ(test_data::kClientId, value);
EXPECT_TRUE(json->GetString("deviceDraft.deviceKind", &value));
EXPECT_EQ("vendor", value);
+ base::DictionaryValue* commandDefs = nullptr;
+ EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
+ EXPECT_FALSE(commandDefs->empty());
+ EXPECT_EQ("{'base':{'reboot':{'parameters':{"
+ "'delay':{'minimum':10,'type':'integer'}}}},"
+ "'robot':{'_jump':{'parameters':{"
+ "'_height':{'type':'integer'}}}}}",
+ buffet::unittests::ValueToString(commandDefs));
base::DictionaryValue json_resp;
json_resp.SetString("id", test_data::kClaimTicketId);
@@ -287,11 +297,36 @@
response->ReplyJson(status_code::Ok, &json_resp);
};
- transport->AddHandler(dev_reg->GetServiceURL("registrationTickets"),
- request_type::kPost,
- base::Bind(create_ticket));
+ auto json_base = buffet::unittests::CreateDictionaryValue(R"({
+ 'base': {
+ 'reboot': {
+ 'parameters': {'delay': 'integer'}
+ },
+ 'shutdown': {
+ 'parameters': {}
+ }
+ }
+ })");
+ EXPECT_TRUE(command_manager_->LoadBaseCommands(*json_base, nullptr));
+ auto json_cmds = buffet::unittests::CreateDictionaryValue(R"({
+ 'base': {
+ 'reboot': {
+ 'parameters': {'delay': {'minimum': 10}}
+ }
+ },
+ 'robot': {
+ '_jump': {
+ 'parameters': {'_height': 'integer'}
+ }
+ }
+ })");
+ EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, "", nullptr));
+
+ transport_->AddHandler(dev_reg_->GetServiceURL("registrationTickets"),
+ request_type::kPost,
+ base::Bind(create_ticket));
std::map<std::string, std::shared_ptr<base::Value>> params;
- std::string json_resp = dev_reg->StartRegistration(params, nullptr);
+ std::string json_resp = dev_reg_->StartRegistration(params, nullptr);
auto json = std::unique_ptr<base::Value>(base::JSONReader::Read(json_resp));
EXPECT_NE(nullptr, json.get());
base::DictionaryValue* dict = nullptr;
@@ -304,26 +339,27 @@
TEST_F(DeviceRegistrationInfoTest, FinishRegistration_NoAuth) {
// Test finalizing ticket with no user authorization token.
// This assumes that a client would patch in their email separately.
- EXPECT_TRUE(dev_reg->Load());
+ EXPECT_TRUE(dev_reg_->Load());
// General ticket finalization handler.
std::string ticket_url =
- dev_reg->GetServiceURL("registrationTickets/" +
+ dev_reg_->GetServiceURL("registrationTickets/" +
std::string(test_data::kClaimTicketId));
- transport->AddHandler(ticket_url + "/finalize", request_type::kPost,
- base::Bind(FinalizeTicketHandler));
+ transport_->AddHandler(ticket_url + "/finalize", request_type::kPost,
+ base::Bind(FinalizeTicketHandler));
- transport->AddHandler(dev_reg->GetOAuthURL("token"), request_type::kPost,
- base::Bind(OAuth2Handler));
+ transport_->AddHandler(dev_reg_->GetOAuthURL("token"), request_type::kPost,
+ base::Bind(OAuth2Handler));
- storage->reset_save_count();
- DeviceRegistrationInfo::TestHelper::SetTestTicketId(dev_reg.get());
- EXPECT_TRUE(dev_reg->FinishRegistration("", nullptr));
- EXPECT_EQ(1, storage->save_count()); // The device info must have been saved.
- EXPECT_EQ(2, transport->GetRequestCount());
+ storage_->reset_save_count();
+ DeviceRegistrationInfo::TestHelper::SetTestTicketId(dev_reg_.get());
+ EXPECT_TRUE(dev_reg_->FinishRegistration("", nullptr));
+ EXPECT_EQ(1,
+ storage_->save_count()); // The device info must have been saved.
+ EXPECT_EQ(2, transport_->GetRequestCount());
// Validate the device info saved to storage...
- auto storage_data = storage->Load();
+ auto storage_data = storage_->Load();
base::DictionaryValue* dict = nullptr;
EXPECT_TRUE(storage_data->GetAsDictionary(&dict));
std::string value;
@@ -347,17 +383,17 @@
TEST_F(DeviceRegistrationInfoTest, FinishRegistration_Auth) {
// Test finalizing ticket with user authorization token.
- EXPECT_TRUE(dev_reg->Load());
+ EXPECT_TRUE(dev_reg_->Load());
// General ticket finalization handler.
std::string ticket_url =
- dev_reg->GetServiceURL("registrationTickets/" +
+ dev_reg_->GetServiceURL("registrationTickets/" +
std::string(test_data::kClaimTicketId));
- transport->AddHandler(ticket_url + "/finalize", request_type::kPost,
- base::Bind(FinalizeTicketHandler));
+ transport_->AddHandler(ticket_url + "/finalize", request_type::kPost,
+ base::Bind(FinalizeTicketHandler));
- transport->AddHandler(dev_reg->GetOAuthURL("token"), request_type::kPost,
- base::Bind(OAuth2Handler));
+ transport_->AddHandler(dev_reg_->GetOAuthURL("token"), request_type::kPost,
+ base::Bind(OAuth2Handler));
// Handle patching in the user email onto the device record.
auto email_patch_handler = [](const fake::ServerRequest& request,
@@ -382,13 +418,14 @@
{"deviceDraft.channel.supportedType", "xmpp"},
});
};
- transport->AddHandler(ticket_url, request_type::kPatch,
- base::Bind(email_patch_handler));
+ transport_->AddHandler(ticket_url, request_type::kPatch,
+ base::Bind(email_patch_handler));
- storage->reset_save_count();
- DeviceRegistrationInfo::TestHelper::SetTestTicketId(dev_reg.get());
- EXPECT_TRUE(dev_reg->FinishRegistration(test_data::kUserAccountAuthCode,
+ storage_->reset_save_count();
+ DeviceRegistrationInfo::TestHelper::SetTestTicketId(dev_reg_.get());
+ EXPECT_TRUE(dev_reg_->FinishRegistration(test_data::kUserAccountAuthCode,
nullptr));
- EXPECT_EQ(1, storage->save_count()); // The device info must have been saved.
- EXPECT_EQ(4, transport->GetRequestCount());
+ EXPECT_EQ(1,
+ storage_->save_count()); // The device info must have been saved.
+ EXPECT_EQ(4, transport_->GetRequestCount());
}