Switch to use ComponentManager for traits/components
Removed the old StateManager, CommandManager and related classes
and switched over to using ComponentManager for all device trait and
component definitions as well as device state.
Change-Id: I99b99a935ba217703d31aa523a3124cca0fa3e90
Reviewed-on: https://weave-review.googlesource.com/1788
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/libweave.gypi b/libweave.gypi
index dc2e6f0..fb7dd03 100644
--- a/libweave.gypi
+++ b/libweave.gypi
@@ -7,9 +7,7 @@
'src/backoff_entry.cc',
'src/base_api_handler.cc',
'src/commands/cloud_command_proxy.cc',
- 'src/commands/command_dictionary.cc',
'src/commands/command_instance.cc',
- 'src/commands/command_manager.cc',
'src/commands/command_queue.cc',
'src/commands/schema_constants.cc',
'src/component_manager_impl.cc',
@@ -40,10 +38,7 @@
'src/privet/wifi_bootstrap_manager.cc',
'src/privet/wifi_ssid_generator.cc',
'src/registration_status.cc',
- 'src/states/error_codes.cc',
'src/states/state_change_queue.cc',
- 'src/states/state_manager.cc',
- 'src/states/state_package.cc',
'src/streams.cc',
'src/string_utils.cc',
'src/utils.cc',
@@ -61,9 +56,7 @@
'src/backoff_entry_unittest.cc',
'src/base_api_handler_unittest.cc',
'src/commands/cloud_command_proxy_unittest.cc',
- 'src/commands/command_dictionary_unittest.cc',
'src/commands/command_instance_unittest.cc',
- 'src/commands/command_manager_unittest.cc',
'src/commands/command_queue_unittest.cc',
'src/component_manager_unittest.cc',
'src/config_unittest.cc',
@@ -80,8 +73,6 @@
'src/privet/security_manager_unittest.cc',
'src/privet/wifi_ssid_generator_unittest.cc',
'src/states/state_change_queue_unittest.cc',
- 'src/states/state_manager_unittest.cc',
- 'src/states/state_package_unittest.cc',
'src/streams_unittest.cc',
'src/string_utils_unittest.cc',
'src/test/weave_testrunner.cc',
diff --git a/src/base_api_handler.cc b/src/base_api_handler.cc
index 1423dd1..6808949 100644
--- a/src/base_api_handler.cc
+++ b/src/base_api_handler.cc
@@ -13,6 +13,8 @@
namespace weave {
namespace {
+const char kBaseComponent[] = "weave";
+const char kBaseTrait[] = "base";
const char kBaseStateFirmwareVersion[] = "base.firmwareVersion";
const char kBaseStateAnonymousAccessRole[] = "base.localAnonymousAccessMaxRole";
const char kBaseStateDiscoveryEnabled[] = "base.localDiscoveryEnabled";
@@ -22,61 +24,64 @@
BaseApiHandler::BaseApiHandler(DeviceRegistrationInfo* device_info,
Device* device)
: device_info_{device_info}, device_{device} {
- device_->AddStateDefinitionsFromJson(R"({
+ device_->AddTraitDefinitionsFromJson(R"({
"base": {
- "firmwareVersion": "string",
- "localDiscoveryEnabled": "boolean",
- "localAnonymousAccessMaxRole": [ "none", "viewer", "user" ],
- "localPairingEnabled": "boolean"
+ "commands": {
+ "updateBaseConfiguration": {
+ "minimalRole": "manager",
+ "parameters": {
+ "localAnonymousAccessMaxRole": {
+ "enum": [ "none", "viewer", "user" ],
+ "type": "string"
+ },
+ "localDiscoveryEnabled": {
+ "type": "boolean"
+ },
+ "localPairingEnabled": {
+ "type": "boolean"
+ }
+ }
+ },
+ "updateDeviceInfo": {
+ "minimalRole": "manager",
+ "parameters": {
+ "description": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "state": {
+ "firmwareVersion": "string",
+ "localDiscoveryEnabled": "boolean",
+ "localAnonymousAccessMaxRole": [ "none", "viewer", "user" ],
+ "localPairingEnabled": "boolean"
+ }
}
})");
+ CHECK(device_->AddComponent(kBaseComponent, {kBaseTrait}, nullptr));
OnConfigChanged(device_->GetSettings());
const auto& settings = device_info_->GetSettings();
base::DictionaryValue state;
state.SetString(kBaseStateFirmwareVersion, settings.firmware_version);
- CHECK(device_->SetStateProperties(state, nullptr));
-
- device->AddCommandDefinitionsFromJson(R"({
- "base": {
- "updateBaseConfiguration": {
- "minimalRole": "manager",
- "parameters": {
- "localAnonymousAccessMaxRole": {
- "enum": [ "none", "viewer", "user" ],
- "type": "string"
- },
- "localDiscoveryEnabled": {
- "type": "boolean"
- },
- "localPairingEnabled": {
- "type": "boolean"
- }
- }
- },
- "updateDeviceInfo": {
- "minimalRole": "manager",
- "parameters": {
- "description": {
- "type": "string"
- },
- "location": {
- "type": "string"
- },
- "name": {
- "type": "string"
- }
- }
- }
- }
- })");
+ CHECK(device_->SetStateProperty(kBaseComponent, kBaseStateFirmwareVersion,
+ base::StringValue{settings.firmware_version},
+ nullptr));
device_->AddCommandHandler(
+ kBaseComponent,
"base.updateBaseConfiguration",
base::Bind(&BaseApiHandler::UpdateBaseConfiguration,
weak_ptr_factory_.GetWeakPtr()));
- device_->AddCommandHandler("base.updateDeviceInfo",
+ device_->AddCommandHandler(kBaseComponent, "base.updateDeviceInfo",
base::Bind(&BaseApiHandler::UpdateDeviceInfo,
weak_ptr_factory_.GetWeakPtr()));
@@ -128,7 +133,7 @@
state.SetBoolean(kBaseStateDiscoveryEnabled,
settings.local_discovery_enabled);
state.SetBoolean(kBaseStatePairingEnabled, settings.local_pairing_enabled);
- device_->SetStateProperties(state, nullptr);
+ device_->SetStateProperties(kBaseComponent, state, nullptr);
}
void BaseApiHandler::UpdateDeviceInfo(const std::weak_ptr<Command>& cmd) {
diff --git a/src/base_api_handler_unittest.cc b/src/base_api_handler_unittest.cc
index 5c6a8a5..23ef95e 100644
--- a/src/base_api_handler_unittest.cc
+++ b/src/base_api_handler_unittest.cc
@@ -12,11 +12,9 @@
#include <weave/test/mock_device.h>
#include <weave/test/unittest_utils.h>
-#include "src/commands/command_manager.h"
+#include "src/component_manager_impl.h"
#include "src/config.h"
#include "src/device_registration_info.h"
-#include "src/states/mock_state_change_queue_interface.h"
-#include "src/states/state_manager.h"
using testing::_;
using testing::AnyOf;
@@ -31,35 +29,33 @@
class BaseApiHandlerTest : public ::testing::Test {
protected:
void SetUp() override {
- EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(_, _))
- .WillRepeatedly(Return(true));
-
- command_manager_ = std::make_shared<CommandManager>();
-
- state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
-
- EXPECT_CALL(device_, AddStateDefinitionsFromJson(_))
+ EXPECT_CALL(device_, AddTraitDefinitionsFromJson(_))
.WillRepeatedly(Invoke([this](const std::string& json) {
- EXPECT_TRUE(
- state_manager_->LoadStateDefinitionFromJson(json, nullptr));
+ EXPECT_TRUE(component_manager_.LoadTraits(json, nullptr));
}));
- EXPECT_CALL(device_, SetStateProperties(_, _))
- .WillRepeatedly(
- Invoke(state_manager_.get(), &StateManager::SetProperties));
- EXPECT_CALL(device_, AddCommandDefinitionsFromJson(_))
- .WillRepeatedly(Invoke([this](const std::string& json) {
- EXPECT_TRUE(command_manager_->LoadCommands(json, nullptr));
+ EXPECT_CALL(device_, SetStateProperties(_, _, _))
+ .WillRepeatedly(Invoke(&component_manager_,
+ &ComponentManager::SetStateProperties));
+ EXPECT_CALL(device_, SetStateProperty(_, _, _, _))
+ .WillRepeatedly(Invoke(&component_manager_,
+ &ComponentManager::SetStateProperty));
+ EXPECT_CALL(device_, AddComponent(_, _, _))
+ .WillRepeatedly(Invoke([this](const std::string& name,
+ const std::vector<std::string>& traits,
+ ErrorPtr* error) {
+ return component_manager_.AddComponent("", name, traits, error);
}));
- EXPECT_CALL(device_, AddCommandHandler(AnyOf("base.updateBaseConfiguration",
+ EXPECT_CALL(device_, AddCommandHandler(_,
+ AnyOf("base.updateBaseConfiguration",
"base.updateDeviceInfo"),
_))
- .WillRepeatedly(
- Invoke(command_manager_.get(), &CommandManager::AddCommandHandler));
+ .WillRepeatedly(Invoke(&component_manager_,
+ &ComponentManager::AddCommandHandler));
std::unique_ptr<Config> config{new Config{&config_store_}};
config->Load();
- dev_reg_.reset(new DeviceRegistrationInfo(command_manager_, state_manager_,
+ dev_reg_.reset(new DeviceRegistrationInfo(&component_manager_,
std::move(config), nullptr,
&http_client_, nullptr));
@@ -70,48 +66,44 @@
}
void AddCommand(const std::string& command) {
- auto command_instance = CommandInstance::FromJson(
- test::CreateDictionaryValue(command.c_str()).get(),
- Command::Origin::kLocal, nullptr, nullptr);
- EXPECT_TRUE(!!command_instance);
-
- std::string id{base::IntToString(++command_id_)};
- command_instance->SetID(id);
- command_instance->SetComponent("device");
- command_manager_->AddCommand(std::move(command_instance));
+ std::string id;
+ auto command_instance = component_manager_.ParseCommandInstance(
+ *test::CreateDictionaryValue(command.c_str()), Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr);
+ ASSERT_NE(nullptr, command_instance.get());
+ component_manager_.AddCommand(std::move(command_instance));
EXPECT_EQ(Command::State::kDone,
- command_manager_->FindCommand(id)->GetState());
+ component_manager_.FindCommand(id)->GetState());
}
std::unique_ptr<base::DictionaryValue> GetBaseState() {
- std::unique_ptr<base::DictionaryValue> state{
- state_manager_->GetState().DeepCopy()};
- std::set<std::string> result;
- for (base::DictionaryValue::Iterator it{*state}; !it.IsAtEnd();
- it.Advance()) {
- if (it.key() != "base")
- state->Remove(it.key(), nullptr);
- }
+ std::unique_ptr<base::DictionaryValue> state;
+ std::string path = component_manager_.FindComponentWithTrait("base");
+ EXPECT_FALSE(path.empty());
+ const auto* component = component_manager_.FindComponent(path, nullptr);
+ CHECK(component);
+ const base::DictionaryValue* base_state = nullptr;
+ if (component->GetDictionary("state.base", &base_state))
+ state.reset(base_state->DeepCopy());
+ else
+ state.reset(new base::DictionaryValue);
return state;
}
provider::test::MockConfigStore config_store_;
StrictMock<provider::test::MockHttpClient> http_client_;
std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
- std::shared_ptr<CommandManager> command_manager_;
- testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue_;
- std::shared_ptr<StateManager> state_manager_;
+ ComponentManagerImpl component_manager_;
std::unique_ptr<BaseApiHandler> handler_;
StrictMock<test::MockDevice> device_;
- int command_id_{0};
};
TEST_F(BaseApiHandlerTest, Initialization) {
- const auto& command_defs =
- command_manager_->GetCommandDictionary().GetCommandsAsJson();
+ const base::DictionaryValue* trait = nullptr;
+ ASSERT_TRUE(component_manager_.GetTraits().GetDictionary("base", &trait));
auto expected = R"({
- "base": {
+ "commands": {
"updateBaseConfiguration": {
"minimalRole": "manager",
"parameters": {
@@ -141,9 +133,15 @@
}
}
}
- }
+ },
+ "state": {
+ "firmwareVersion": "string",
+ "localAnonymousAccessMaxRole": [ "none", "viewer", "user" ],
+ "localDiscoveryEnabled": "boolean",
+ "localPairingEnabled": "boolean"
+ }
})";
- EXPECT_JSON_EQ(expected, command_defs);
+ EXPECT_JSON_EQ(expected, *trait);
}
TEST_F(BaseApiHandlerTest, UpdateBaseConfiguration) {
@@ -151,6 +149,7 @@
AddCommand(R"({
'name' : 'base.updateBaseConfiguration',
+ 'component': 'weave',
'parameters': {
'localDiscoveryEnabled': false,
'localAnonymousAccessMaxRole': 'none',
@@ -162,17 +161,16 @@
EXPECT_FALSE(settings.local_pairing_enabled);
auto expected = R"({
- 'base': {
- 'firmwareVersion': 'TEST_FIRMWARE',
- 'localAnonymousAccessMaxRole': 'none',
- 'localDiscoveryEnabled': false,
- 'localPairingEnabled': false
- }
+ 'firmwareVersion': 'TEST_FIRMWARE',
+ 'localAnonymousAccessMaxRole': 'none',
+ 'localDiscoveryEnabled': false,
+ 'localPairingEnabled': false
})";
EXPECT_JSON_EQ(expected, *GetBaseState());
AddCommand(R"({
'name' : 'base.updateBaseConfiguration',
+ 'component': 'weave',
'parameters': {
'localDiscoveryEnabled': true,
'localAnonymousAccessMaxRole': 'user',
@@ -183,12 +181,10 @@
EXPECT_TRUE(settings.local_discovery_enabled);
EXPECT_TRUE(settings.local_pairing_enabled);
expected = R"({
- 'base': {
- 'firmwareVersion': 'TEST_FIRMWARE',
- 'localAnonymousAccessMaxRole': 'user',
- 'localDiscoveryEnabled': true,
- 'localPairingEnabled': true
- }
+ 'firmwareVersion': 'TEST_FIRMWARE',
+ 'localAnonymousAccessMaxRole': 'user',
+ 'localDiscoveryEnabled': true,
+ 'localPairingEnabled': true
})";
EXPECT_JSON_EQ(expected, *GetBaseState());
@@ -197,12 +193,10 @@
change.set_local_anonymous_access_role(AuthScope::kViewer);
}
expected = R"({
- 'base': {
- 'firmwareVersion': 'TEST_FIRMWARE',
- 'localAnonymousAccessMaxRole': 'viewer',
- 'localDiscoveryEnabled': true,
- 'localPairingEnabled': true
- }
+ 'firmwareVersion': 'TEST_FIRMWARE',
+ 'localAnonymousAccessMaxRole': 'viewer',
+ 'localDiscoveryEnabled': true,
+ 'localPairingEnabled': true
})";
EXPECT_JSON_EQ(expected, *GetBaseState());
}
@@ -210,6 +204,7 @@
TEST_F(BaseApiHandlerTest, UpdateDeviceInfo) {
AddCommand(R"({
'name' : 'base.updateDeviceInfo',
+ 'component': 'weave',
'parameters': {
'name': 'testName',
'description': 'testDescription',
@@ -224,6 +219,7 @@
AddCommand(R"({
'name' : 'base.updateDeviceInfo',
+ 'component': 'weave',
'parameters': {
'location': 'newLocation'
}
diff --git a/src/commands/cloud_command_proxy.cc b/src/commands/cloud_command_proxy.cc
index 3d472c7..f8f8d1f 100644
--- a/src/commands/cloud_command_proxy.cc
+++ b/src/commands/cloud_command_proxy.cc
@@ -17,15 +17,15 @@
CloudCommandProxy::CloudCommandProxy(
CommandInstance* command_instance,
CloudCommandUpdateInterface* cloud_command_updater,
- StateChangeQueueInterface* state_change_queue,
+ ComponentManager* component_manager,
std::unique_ptr<BackoffEntry> backoff_entry,
provider::TaskRunner* task_runner)
: command_instance_{command_instance},
cloud_command_updater_{cloud_command_updater},
- state_change_queue_{state_change_queue},
+ component_manager_{component_manager},
task_runner_{task_runner},
cloud_backoff_entry_{std::move(backoff_entry)} {
- callback_token_ = state_change_queue_->AddOnStateUpdatedCallback(
+ callback_token_ = component_manager_->AddServerStateUpdatedCallback(
base::Bind(&CloudCommandProxy::OnDeviceStateUpdated,
weak_ptr_factory_.GetWeakPtr()));
observer_.Add(command_instance);
@@ -67,7 +67,7 @@
void CloudCommandProxy::QueueCommandUpdate(
std::unique_ptr<base::DictionaryValue> patch) {
- UpdateID id = state_change_queue_->GetLastStateChangeId();
+ ComponentManager::UpdateID id = component_manager_->GetLastStateChangeId();
if (update_queue_.empty() || update_queue_.back().first != id) {
// If queue is currently empty or the device state has changed since the
// last patch request queued, add a new request to the queue.
@@ -158,7 +158,8 @@
SendCommandUpdate();
}
-void CloudCommandProxy::OnDeviceStateUpdated(UpdateID update_id) {
+void CloudCommandProxy::OnDeviceStateUpdated(
+ ComponentManager::UpdateID update_id) {
last_state_update_id_ = update_id;
// Try to send out any queued command updates that could be performed after
// a device state is updated.
diff --git a/src/commands/cloud_command_proxy.h b/src/commands/cloud_command_proxy.h
index ee6358f..13f4654 100644
--- a/src/commands/cloud_command_proxy.h
+++ b/src/commands/cloud_command_proxy.h
@@ -18,7 +18,7 @@
#include "src/backoff_entry.h"
#include "src/commands/cloud_command_update_interface.h"
#include "src/commands/command_instance.h"
-#include "src/states/state_change_queue_interface.h"
+#include "src/component_manager.h"
namespace weave {
@@ -33,7 +33,7 @@
public:
CloudCommandProxy(CommandInstance* command_instance,
CloudCommandUpdateInterface* cloud_command_updater,
- StateChangeQueueInterface* state_change_queue,
+ ComponentManager* component_manager,
std::unique_ptr<BackoffEntry> backoff_entry,
provider::TaskRunner* task_runner);
~CloudCommandProxy() override = default;
@@ -46,10 +46,8 @@
void OnStateChanged() override;
private:
- using UpdateID = StateChangeQueueInterface::UpdateID;
- using UpdateQueueEntry =
- std::pair<UpdateID, std::unique_ptr<base::DictionaryValue>>;
-
+ using UpdateQueueEntry = std::pair<ComponentManager::UpdateID,
+ std::unique_ptr<base::DictionaryValue>>;
// Puts a command update data into the update queue, and optionally sends an
// asynchronous request to GCD server to update the command resource, if there
// are no pending device status updates.
@@ -68,11 +66,11 @@
// Callback invoked by the device state change queue to notify of the
// successful device state update. |update_id| is the ID of the state that
// has been updated on the server.
- void OnDeviceStateUpdated(UpdateID update_id);
+ void OnDeviceStateUpdated(ComponentManager::UpdateID update_id);
CommandInstance* command_instance_;
CloudCommandUpdateInterface* cloud_command_updater_;
- StateChangeQueueInterface* state_change_queue_;
+ ComponentManager* component_manager_;
provider::TaskRunner* task_runner_{nullptr};
// Backoff for SendCommandUpdate() method.
@@ -87,11 +85,11 @@
// Callback token from the state change queue for OnDeviceStateUpdated()
// callback for ask the device state change queue to call when the state
// is updated on the server.
- StateChangeQueueInterface::Token callback_token_;
+ ComponentManager::Token callback_token_;
// Last device state update ID that has been sent out to the server
// successfully.
- UpdateID last_state_update_id_{0};
+ ComponentManager::UpdateID last_state_update_id_{0};
ScopedObserver<CommandInstance, CommandInstance::Observer> observer_{this};
diff --git a/src/commands/cloud_command_proxy_unittest.cc b/src/commands/cloud_command_proxy_unittest.cc
index c022b79..d3a9965 100644
--- a/src/commands/cloud_command_proxy_unittest.cc
+++ b/src/commands/cloud_command_proxy_unittest.cc
@@ -12,9 +12,8 @@
#include <weave/provider/test/fake_task_runner.h>
#include <weave/test/unittest_utils.h>
-#include "src/commands/command_dictionary.h"
#include "src/commands/command_instance.h"
-#include "src/states/mock_state_change_queue_interface.h"
+#include "src/mock_component_manager.h"
using testing::_;
using testing::DoAll;
@@ -66,14 +65,14 @@
class CloudCommandProxyTest : public ::testing::Test {
protected:
void SetUp() override {
- // Set up the test StateChangeQueue.
- auto callback = [this](
- const base::Callback<void(StateChangeQueueInterface::UpdateID)>& call) {
+ // Set up the test ComponentManager.
+ auto callback =
+ [this](const base::Callback<void(ComponentManager::UpdateID)>& call) {
return callbacks_.Add(call).release();
};
- EXPECT_CALL(state_change_queue_, MockAddOnStateUpdatedCallback(_))
+ EXPECT_CALL(component_manager_, MockAddServerStateUpdatedCallback(_))
.WillRepeatedly(Invoke(callback));
- EXPECT_CALL(state_change_queue_, GetLastStateChangeId())
+ EXPECT_CALL(component_manager_, GetLastStateChangeId())
.WillRepeatedly(testing::ReturnPointee(¤t_state_update_id_));
CreateCommandInstance();
@@ -102,7 +101,7 @@
// Finally construct the CloudCommandProxy we are going to test here.
std::unique_ptr<CloudCommandProxy> proxy{new CloudCommandProxy{
- command_instance_.get(), &cloud_updater_, &state_change_queue_,
+ command_instance_.get(), &cloud_updater_, &component_manager_,
std::move(backoff), &task_runner_}};
// CloudCommandProxy::CloudCommandProxy() subscribe itself to weave::Command
// notifications. When weave::Command is being destroyed it sends
@@ -110,10 +109,10 @@
proxy.release();
}
- StateChangeQueueInterface::UpdateID current_state_update_id_{0};
- base::CallbackList<void(StateChangeQueueInterface::UpdateID)> callbacks_;
+ ComponentManager::UpdateID current_state_update_id_{0};
+ base::CallbackList<void(ComponentManager::UpdateID)> callbacks_;
testing::StrictMock<MockCloudCommandUpdateInterface> cloud_updater_;
- testing::StrictMock<MockStateChangeQueueInterface> state_change_queue_;
+ testing::StrictMock<MockComponentManager> component_manager_;
testing::StrictMock<provider::test::FakeTaskRunner> task_runner_;
std::queue<base::Closure> task_queue_;
std::unique_ptr<CommandInstance> command_instance_;
diff --git a/src/commands/command_dictionary.cc b/src/commands/command_dictionary.cc
deleted file mode 100644
index f6a409d..0000000
--- a/src/commands/command_dictionary.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/commands/command_dictionary.h"
-
-#include <algorithm>
-
-#include <base/values.h>
-#include <weave/enum_to_string.h>
-
-#include "src/commands/schema_constants.h"
-#include "src/string_utils.h"
-
-namespace weave {
-
-namespace {
-const EnumToStringMap<UserRole>::Map kMap[] = {
- {UserRole::kViewer, commands::attributes::kCommand_Role_Viewer},
- {UserRole::kUser, commands::attributes::kCommand_Role_User},
- {UserRole::kOwner, commands::attributes::kCommand_Role_Owner},
- {UserRole::kManager, commands::attributes::kCommand_Role_Manager},
-};
-} // anonymous namespace
-
-template <>
-LIBWEAVE_EXPORT EnumToStringMap<UserRole>::EnumToStringMap()
- : EnumToStringMap(kMap) {}
-
-bool CommandDictionary::LoadCommands(const base::DictionaryValue& json,
- ErrorPtr* error) {
- // |json| contains a list of nested objects with the following structure:
- // {"<pkg_name>": {"<cmd_name>": {"parameters": {object_schema}}, ...}, ...}
- // Iterate over traits
- base::DictionaryValue::Iterator trait_iter(json);
- for (base::DictionaryValue::Iterator trait_iter(json);
- !trait_iter.IsAtEnd(); trait_iter.Advance()) {
- std::string trait_name = trait_iter.key();
- const base::DictionaryValue* trait_def = nullptr;
- if (!trait_iter.value().GetAsDictionary(&trait_def)) {
- Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kTypeMismatch,
- "Expecting an object for trait '%s'",
- trait_name.c_str());
- return false;
- }
- // Iterate over command definitions within the current trait.
- for (base::DictionaryValue::Iterator command_iter(*trait_def);
- !command_iter.IsAtEnd(); command_iter.Advance()) {
- std::string command_name = command_iter.key();
- if (command_name.empty()) {
- Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidCommandName,
- "Unnamed command encountered in trait '%s'",
- trait_name.c_str());
- return false;
- }
- const base::DictionaryValue* command_def_json = nullptr;
- if (!command_iter.value().GetAsDictionary(&command_def_json)) {
- Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kTypeMismatch,
- "Expecting an object for command '%s'",
- command_name.c_str());
- return false;
- }
-
- // Construct the compound command name as "trait_name.cmd_name".
- std::string full_command_name = Join(".", trait_name, command_name);
-
- // Validate the 'minimalRole' value if present. That's the only thing we
- // care about so far.
- std::string value;
- if (!command_def_json->GetString(commands::attributes::kCommand_Role,
- &value)) {
- Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidMinimalRole,
- "Missing '%s' attribute for command '%s'",
- commands::attributes::kCommand_Role,
- full_command_name.c_str());
- return false;
- }
- UserRole minimal_role;
- if (!StringToEnum(value, &minimal_role)) {
- Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidMinimalRole,
- "Invalid role '%s' for command '%s'", value.c_str(),
- full_command_name.c_str());
- return false;
- }
- // Check if we already have this command defined.
- CHECK(!definitions_.Get(full_command_name, nullptr))
- << "Definition for command '" << full_command_name
- << "' overrides an earlier definition";
- definitions_.Set(full_command_name, command_def_json->DeepCopy());
- }
- }
- return true;
-}
-
-const base::DictionaryValue& CommandDictionary::GetCommandsAsJson() const {
- return definitions_;
-}
-
-size_t CommandDictionary::GetSize() const {
- size_t size = 0;
- base::DictionaryValue::Iterator trait_iter(definitions_);
- while (!trait_iter.IsAtEnd()) {
- std::string trait_name = trait_iter.key();
- const base::DictionaryValue* trait_def = nullptr;
- CHECK(trait_iter.value().GetAsDictionary(&trait_def));
- size += trait_def->size();
- trait_iter.Advance();
- }
- return size;
-}
-
-const base::DictionaryValue* CommandDictionary::FindCommand(
- const std::string& command_name) const {
- const base::DictionaryValue* definition = nullptr;
- // Make sure the |command_name| came in form of trait_name.command_name.
- // For this, we just verify it has a single period in its name.
- if (std::count(command_name.begin(), command_name.end(), '.') != 1)
- return definition;
- definitions_.GetDictionary(command_name, &definition);
- return definition;
-}
-
-void CommandDictionary::Clear() {
- definitions_.Clear();
-}
-
-bool CommandDictionary::GetMinimalRole(const std::string& command_name,
- UserRole* minimal_role,
- ErrorPtr* error) const {
- const base::DictionaryValue* command_def = FindCommand(command_name);
- if (!command_def) {
- Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
- errors::commands::kInvalidCommandName,
- "Command definition for '%s' not found",
- command_name.c_str());
- return false;
- }
- std::string value;
- // The JSON definition has been pre-validated already in LoadCommands, so
- // just using CHECKs here.
- CHECK(command_def->GetString(commands::attributes::kCommand_Role, &value));
- CHECK(StringToEnum(value, minimal_role));
- return true;
-}
-
-} // namespace weave
diff --git a/src/commands/command_dictionary.h b/src/commands/command_dictionary.h
deleted file mode 100644
index 12f7e40..0000000
--- a/src/commands/command_dictionary.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_COMMANDS_COMMAND_DICTIONARY_H_
-#define LIBWEAVE_SRC_COMMANDS_COMMAND_DICTIONARY_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-#include <base/values.h>
-#include <weave/error.h>
-
-namespace weave {
-
-enum class UserRole {
- kViewer,
- kUser,
- kManager,
- kOwner,
-};
-
-// CommandDictionary is a wrapper around a container of command definition
-// schema. The command name is a compound name in a form of
-// "trait_name.command_name", where "trait_name" is a name of command trait such
-// as "base", "onOff", and others. So the full command name could be
-// "base.reboot", for example.
-class CommandDictionary final {
- public:
- CommandDictionary() = default;
-
- // Loads command definitions from a JSON object. This is done at the daemon
- // startup and whenever a device daemon decides to update its command list.
- // |json| is a JSON dictionary that describes the complete commands. Optional
- // Returns false on failure and |error| provides additional error information
- // when provided.
- bool LoadCommands(const base::DictionaryValue& json,
- ErrorPtr* error);
- // Converts all the command definitions to a JSON object for CDD/Device
- // draft.
- const base::DictionaryValue& GetCommandsAsJson() const;
- // Returns the number of command definitions in the dictionary.
- size_t GetSize() const;
- // Checks if the dictionary has no command definitions.
- bool IsEmpty() const { return definitions_.empty(); }
- // Remove all the command definitions from the dictionary.
- void Clear();
- // Finds a definition for the given command.
- const base::DictionaryValue* FindCommand(
- const std::string& command_name) const;
- // Determines the minimal role for the given command. Returns false if the
- // command with given name is not found.
- bool GetMinimalRole(const std::string& command_name,
- UserRole* minimal_role,
- ErrorPtr* error) const;
-
- private:
- base::DictionaryValue definitions_; // List of all available command defs.
- DISALLOW_COPY_AND_ASSIGN(CommandDictionary);
-};
-
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_COMMANDS_COMMAND_DICTIONARY_H_
diff --git a/src/commands/command_dictionary_unittest.cc b/src/commands/command_dictionary_unittest.cc
deleted file mode 100644
index 7c53935..0000000
--- a/src/commands/command_dictionary_unittest.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/commands/command_dictionary.h"
-
-#include <gtest/gtest.h>
-#include <weave/test/unittest_utils.h>
-
-namespace weave {
-
-using test::CreateDictionaryValue;
-using test::IsEqualValue;
-
-TEST(CommandDictionary, Empty) {
- CommandDictionary dict;
- EXPECT_TRUE(dict.IsEmpty());
- EXPECT_EQ(nullptr, dict.FindCommand("robot.jump"));
-}
-
-TEST(CommandDictionary, LoadCommands) {
- auto json = CreateDictionaryValue(R"({
- 'robot': {
- 'jump': {
- 'minimalRole': 'manager',
- 'parameters': {
- 'height': 'integer',
- '_jumpType': ['_withAirFlip', '_withSpin', '_withKick']
- },
- 'progress': {
- 'progress': 'integer'
- },
- 'results': {}
- }
- }
- })");
- CommandDictionary dict;
- EXPECT_TRUE(dict.LoadCommands(*json, nullptr));
- EXPECT_EQ(1u, dict.GetSize());
- EXPECT_NE(nullptr, dict.FindCommand("robot.jump"));
- json = CreateDictionaryValue(R"({
- 'base': {
- 'reboot': {
- 'minimalRole': 'owner',
- 'parameters': {'delay': 'integer'}
- },
- 'shutdown': {
- 'minimalRole': 'user'
- }
- }
- })");
- EXPECT_TRUE(dict.LoadCommands(*json, nullptr));
- EXPECT_EQ(3u, dict.GetSize());
- EXPECT_NE(nullptr, dict.FindCommand("robot.jump"));
- EXPECT_NE(nullptr, dict.FindCommand("base.reboot"));
- EXPECT_NE(nullptr, dict.FindCommand("base.shutdown"));
- EXPECT_EQ(nullptr, dict.FindCommand("foo.bar"));
-}
-
-TEST(CommandDictionary, LoadCommands_Failures) {
- CommandDictionary dict;
- ErrorPtr error;
-
- // Command definition is not an object.
- auto json = CreateDictionaryValue("{'robot':{'jump':0}}");
- EXPECT_FALSE(dict.LoadCommands(*json, &error));
- EXPECT_EQ("type_mismatch", error->GetCode());
- error.reset();
-
- // Package definition is not an object.
- json = CreateDictionaryValue("{'robot':'blah'}");
- EXPECT_FALSE(dict.LoadCommands(*json, &error));
- EXPECT_EQ("type_mismatch", error->GetCode());
- error.reset();
-
- // Empty command name.
- json = CreateDictionaryValue("{'robot':{'':{'parameters':{},'results':{}}}}");
- EXPECT_FALSE(dict.LoadCommands(*json, &error));
- EXPECT_EQ("invalid_command_name", error->GetCode());
- error.reset();
-
- // No 'minimalRole'.
- json = CreateDictionaryValue(R"({
- 'base': {
- 'reboot': {
- 'parameters': {'delay': 'integer'}
- }
- }
- })");
- EXPECT_FALSE(dict.LoadCommands(*json, &error));
- EXPECT_EQ("invalid_minimal_role", error->GetCode());
- error.reset();
-
- // Invalid 'minimalRole'.
- json = CreateDictionaryValue(R"({
- 'base': {
- 'reboot': {
- 'minimalRole': 'foo',
- 'parameters': {'delay': 'integer'}
- }
- }
- })");
- EXPECT_FALSE(dict.LoadCommands(*json, &error));
- EXPECT_EQ("invalid_minimal_role", error->GetCode());
- error.reset();
-}
-
-TEST(CommandDictionaryDeathTest, LoadCommands_Redefine) {
- // Redefine commands.
- CommandDictionary dict;
- ErrorPtr error;
- auto json =
- CreateDictionaryValue("{'robot':{'jump':{'minimalRole': 'viewer'}}}");
- dict.LoadCommands(*json, nullptr);
- ASSERT_DEATH(dict.LoadCommands(*json, &error),
- ".*Definition for command 'robot.jump' overrides an "
- "earlier definition");
-}
-
-TEST(CommandDictionary, GetMinimalRole) {
- CommandDictionary base_dict;
- auto json = CreateDictionaryValue(R"({
- 'base': {
- 'command1': {
- 'minimalRole': 'viewer',
- 'parameters': {},
- 'results': {}
- },
- 'command2': {
- 'minimalRole': 'user',
- 'parameters': {},
- 'results': {}
- },
- 'command3': {
- 'minimalRole': 'manager',
- 'parameters': {},
- 'results': {}
- },
- 'command4': {
- 'minimalRole': 'owner',
- 'parameters': {},
- 'results': {}
- }
- }
- })");
- EXPECT_TRUE(base_dict.LoadCommands(*json, nullptr));
- UserRole role;
- EXPECT_TRUE(base_dict.GetMinimalRole("base.command1", &role, nullptr));
- EXPECT_EQ(UserRole::kViewer, role);
- EXPECT_TRUE(base_dict.GetMinimalRole("base.command2", &role, nullptr));
- EXPECT_EQ(UserRole::kUser, role);
- EXPECT_TRUE(base_dict.GetMinimalRole("base.command3", &role, nullptr));
- EXPECT_EQ(UserRole::kManager, role);
- EXPECT_TRUE(base_dict.GetMinimalRole("base.command4", &role, nullptr));
- EXPECT_EQ(UserRole::kOwner, role);
- EXPECT_FALSE(base_dict.GetMinimalRole("base.command5", &role, nullptr));
-}
-
-} // namespace weave
diff --git a/src/commands/command_instance.cc b/src/commands/command_instance.cc
index 702a819..da62887 100644
--- a/src/commands/command_instance.cc
+++ b/src/commands/command_instance.cc
@@ -9,7 +9,6 @@
#include <weave/error.h>
#include <weave/export.h>
-#include "src/commands/command_dictionary.h"
#include "src/commands/command_queue.h"
#include "src/commands/schema_constants.h"
#include "src/json_error_codes.h"
diff --git a/src/commands/command_manager.cc b/src/commands/command_manager.cc
deleted file mode 100644
index 9e9852b..0000000
--- a/src/commands/command_manager.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/commands/command_manager.h"
-
-#include <base/values.h>
-#include <weave/enum_to_string.h>
-#include <weave/error.h>
-
-#include "src/commands/schema_constants.h"
-#include "src/utils.h"
-
-namespace weave {
-
-CommandManager::CommandManager() {}
-
-CommandManager::~CommandManager() {}
-
-void CommandManager::AddCommandDefChanged(const base::Closure& callback) {
- on_command_changed_.push_back(callback);
- callback.Run();
-}
-
-const CommandDictionary& CommandManager::GetCommandDictionary() const {
- return dictionary_;
-}
-
-bool CommandManager::LoadCommands(const base::DictionaryValue& dict,
- ErrorPtr* error) {
- bool result = dictionary_.LoadCommands(dict, error);
- for (const auto& cb : on_command_changed_)
- cb.Run();
- return result;
-}
-
-bool CommandManager::LoadCommands(const std::string& json,
- ErrorPtr* error) {
- std::unique_ptr<const base::DictionaryValue> dict = LoadJsonDict(json, error);
- if (!dict)
- return false;
- return LoadCommands(*dict, error);
-}
-
-void CommandManager::AddCommand(
- std::unique_ptr<CommandInstance> command_instance) {
- command_queue_.Add(std::move(command_instance));
-}
-
-bool CommandManager::AddCommand(const base::DictionaryValue& command,
- std::string* id,
- ErrorPtr* error) {
- return AddCommand(command, UserRole::kOwner, id, error);
-}
-
-bool CommandManager::AddCommand(const base::DictionaryValue& command,
- UserRole role,
- std::string* id,
- ErrorPtr* error) {
- auto command_instance = CommandInstance::FromJson(
- &command, Command::Origin::kLocal, nullptr, error);
- if (!command_instance)
- return false;
-
- UserRole minimal_role;
- if (!GetCommandDictionary().GetMinimalRole(command_instance->GetName(),
- &minimal_role, error)) {
- return false;
- }
- if (role < minimal_role) {
- Error::AddToPrintf(
- error, FROM_HERE, errors::commands::kDomain, "access_denied",
- "User role '%s' less than minimal: '%s'", EnumToString(role).c_str(),
- EnumToString(minimal_role).c_str());
- return false;
- }
-
- command_instance->SetComponent("device");
- *id = std::to_string(++next_command_id_);
- command_instance->SetID(*id);
- AddCommand(std::move(command_instance));
- return true;
-}
-
-CommandInstance* CommandManager::FindCommand(const std::string& id) {
- return command_queue_.Find(id);
-}
-
-void CommandManager::AddCommandAddedCallback(
- const CommandQueue::CommandCallback& callback) {
- command_queue_.AddCommandAddedCallback(callback);
-}
-
-void CommandManager::AddCommandRemovedCallback(
- const CommandQueue::CommandCallback& callback) {
- command_queue_.AddCommandRemovedCallback(callback);
-}
-
-void CommandManager::AddCommandHandler(
- const std::string& command_name,
- const Device::CommandHandlerCallback& callback) {
- CHECK(command_name.empty() || dictionary_.FindCommand(command_name))
- << "Command undefined: " << command_name;
- command_queue_.AddCommandHandler("device", command_name, callback);
-}
-
-} // namespace weave
diff --git a/src/commands/command_manager.h b/src/commands/command_manager.h
deleted file mode 100644
index 644c165..0000000
--- a/src/commands/command_manager.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_COMMANDS_COMMAND_MANAGER_H_
-#define LIBWEAVE_SRC_COMMANDS_COMMAND_MANAGER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/callback.h>
-#include <base/macros.h>
-#include <base/memory/weak_ptr.h>
-
-#include "src/commands/command_dictionary.h"
-#include "src/commands/command_queue.h"
-
-namespace weave {
-
-class CommandInstance;
-
-// CommandManager class that will have a list of all the device command
-// schemas as well as the live command queue of pending command instances
-// dispatched to the device.
-class CommandManager final {
- public:
- CommandManager();
-
- ~CommandManager();
-
- bool AddCommand(const base::DictionaryValue& command,
- std::string* id,
- ErrorPtr* error);
- CommandInstance* FindCommand(const std::string& id);
- void AddCommandAddedCallback(const CommandQueue::CommandCallback& callback);
- void AddCommandRemovedCallback(const CommandQueue::CommandCallback& callback);
- void AddCommandHandler(const std::string& command_name,
- const Device::CommandHandlerCallback& callback);
-
- // Sets callback which is called when command definitions is changed.
- void AddCommandDefChanged(const base::Closure& callback);
-
- // Returns the command definitions for the device.
- const CommandDictionary& GetCommandDictionary() const;
-
- // Loads device command schema.
- bool LoadCommands(const base::DictionaryValue& dict,
- ErrorPtr* error);
-
- // Same as the overload above, but takes a path to a json file to read
- // the base command definitions from.
- bool LoadCommands(const std::string& json,
- ErrorPtr* error);
-
- // Adds a new command to the command queue.
- void AddCommand(std::unique_ptr<CommandInstance> command_instance);
-
- bool AddCommand(const base::DictionaryValue& command,
- UserRole role,
- std::string* id,
- ErrorPtr* error);
-
- private:
- CommandDictionary dictionary_; // Registered definitions.
- CommandQueue command_queue_;
- std::vector<base::Callback<void()>> on_command_changed_;
- uint32_t next_command_id_{0};
-
- DISALLOW_COPY_AND_ASSIGN(CommandManager);
-};
-
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_COMMANDS_COMMAND_MANAGER_H_
diff --git a/src/commands/command_manager_unittest.cc b/src/commands/command_manager_unittest.cc
deleted file mode 100644
index 303cafa..0000000
--- a/src/commands/command_manager_unittest.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/commands/command_manager.h"
-
-#include <map>
-
-#include <base/json/json_writer.h>
-#include <gtest/gtest.h>
-#include <weave/provider/test/mock_config_store.h>
-#include <weave/test/unittest_utils.h>
-
-#include "src/bind_lambda.h"
-
-using testing::Return;
-
-namespace weave {
-
-using test::CreateDictionaryValue;
-
-namespace {
-
-const char kTestVendorCommands[] = R"({
- "robot": {
- "_jump": {
- "minimalRole": "user",
- "parameters": {"height": "integer"},
- "results": {}
- },
- "_speak": {
- "minimalRole": "user",
- "parameters": {"phrase": "string"},
- "results": {}
- }
- }
-})";
-
-const char kTestTestCommands[] = R"({
- "test": {
- "_yo": {
- "minimalRole": "user",
- "parameters": {"name": "string"},
- "results": {}
- }
- }
-})";
-
-} // namespace
-
-TEST(CommandManager, Empty) {
- CommandManager manager;
- EXPECT_TRUE(manager.GetCommandDictionary().IsEmpty());
-}
-
-TEST(CommandManager, LoadCommandsDict) {
- CommandManager manager;
- auto json = CreateDictionaryValue(kTestVendorCommands);
- EXPECT_TRUE(manager.LoadCommands(*json, nullptr));
-}
-
-TEST(CommandManager, LoadCommandsJson) {
- CommandManager manager;
-
- // Load device-supported commands.
- auto json_str = R"({
- "base": {
- "reboot": {
- "minimalRole": "user",
- "parameters": {"delay": "integer"},
- "results": {}
- }
- },
- "robot": {
- "_jump": {
- "minimalRole": "user",
- "parameters": {"height": "integer"},
- "results": {}
- }
- }
- })";
- EXPECT_TRUE(manager.LoadCommands(json_str, nullptr));
- EXPECT_EQ(2u, manager.GetCommandDictionary().GetSize());
- EXPECT_NE(nullptr, manager.GetCommandDictionary().FindCommand("base.reboot"));
- EXPECT_NE(nullptr, manager.GetCommandDictionary().FindCommand("robot._jump"));
-}
-
-TEST(CommandManager, ShouldLoadStandardAndTestDefinitions) {
- CommandManager manager;
- ASSERT_TRUE(manager.LoadCommands(kTestVendorCommands, nullptr));
- ASSERT_TRUE(manager.LoadCommands(kTestTestCommands, nullptr));
- EXPECT_EQ(3u, manager.GetCommandDictionary().GetSize());
- EXPECT_NE(nullptr, manager.GetCommandDictionary().FindCommand("robot._jump"));
- EXPECT_NE(nullptr,
- manager.GetCommandDictionary().FindCommand("robot._speak"));
- EXPECT_NE(nullptr, manager.GetCommandDictionary().FindCommand("test._yo"));
-}
-
-} // namespace weave
diff --git a/src/component_manager.h b/src/component_manager.h
index fbc18aa..5f16ac4 100644
--- a/src/component_manager.h
+++ b/src/component_manager.h
@@ -13,13 +13,19 @@
#include <base/values.h>
#include <weave/error.h>
-#include "src/commands/command_dictionary.h"
#include "src/commands/command_queue.h"
namespace weave {
class CommandInstance;
+enum class UserRole {
+ kViewer,
+ kUser,
+ kManager,
+ kOwner,
+};
+
// A simple notification record event to track component state changes.
// The |timestamp| records the time of the state change.
// |changed_properties| contains a property set with the new property values
@@ -82,13 +88,22 @@
virtual void AddComponentTreeChangedCallback(
const base::Closure& callback) = 0;
- // Parses the command definition from a json dictionary and adds it to the
- // command queue. The new command ID is returned through optional |id| param.
- virtual bool AddCommand(const base::DictionaryValue& command,
- Command::Origin command_origin,
- UserRole role,
- std::string* id,
- ErrorPtr* error) = 0;
+ // Adds a new command instance to the command queue. The command specified in
+ // |command_instance| must be fully initialized and have its name, component,
+ // id populated.
+ virtual void AddCommand(
+ std::unique_ptr<CommandInstance> command_instance) = 0;
+
+ // Parses the command definition from a json dictionary. The resulting command
+ // instance is populated with all the required fields and partially validated
+ // against syntax/schema.
+ // The new command ID is returned through optional |id| param.
+ virtual std::unique_ptr<CommandInstance> ParseCommandInstance(
+ const base::DictionaryValue& command,
+ Command::Origin command_origin,
+ UserRole role,
+ std::string* id,
+ ErrorPtr* error) = 0;
// Find a command instance with the given ID in the command queue.
virtual CommandInstance* FindCommand(const std::string& id) = 0;
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc
index 1883739..5b0ab23 100644
--- a/src/component_manager_impl.cc
+++ b/src/component_manager_impl.cc
@@ -18,7 +18,18 @@
namespace {
// Max of 100 state update events should be enough in the queue.
const size_t kMaxStateChangeQueueSize = 100;
-} // namespace
+
+const EnumToStringMap<UserRole>::Map kMap[] = {
+ {UserRole::kViewer, commands::attributes::kCommand_Role_Viewer},
+ {UserRole::kUser, commands::attributes::kCommand_Role_User},
+ {UserRole::kOwner, commands::attributes::kCommand_Role_Owner},
+ {UserRole::kManager, commands::attributes::kCommand_Role_Manager},
+};
+} // anonymous namespace
+
+template <>
+LIBWEAVE_EXPORT EnumToStringMap<UserRole>::EnumToStringMap()
+ : EnumToStringMap(kMap) {}
ComponentManagerImpl::ComponentManagerImpl() {}
@@ -147,11 +158,17 @@
callback.Run();
}
-bool ComponentManagerImpl::AddCommand(const base::DictionaryValue& command,
- Command::Origin command_origin,
- UserRole role,
- std::string* id,
- ErrorPtr* error) {
+void ComponentManagerImpl::AddCommand(
+ std::unique_ptr<CommandInstance> command_instance) {
+ command_queue_.Add(std::move(command_instance));
+}
+
+std::unique_ptr<CommandInstance> ComponentManagerImpl::ParseCommandInstance(
+ const base::DictionaryValue& command,
+ Command::Origin command_origin,
+ UserRole role,
+ std::string* id,
+ ErrorPtr* error) {
std::string command_id;
auto command_instance = CommandInstance::FromJson(&command, command_origin,
&command_id, error);
@@ -162,18 +179,18 @@
*id = command_id;
if (!command_instance)
- return false;
+ return nullptr;
UserRole minimal_role;
if (!GetMinimalRole(command_instance->GetName(), &minimal_role, error))
- return false;
+ return nullptr;
if (role < minimal_role) {
Error::AddToPrintf(
error, FROM_HERE, errors::commands::kDomain, "access_denied",
"User role '%s' less than minimal: '%s'", EnumToString(role).c_str(),
EnumToString(minimal_role).c_str());
- return false;
+ return nullptr;
}
std::string component_path = command_instance->GetComponent();
@@ -188,14 +205,14 @@
"Unable route command '%s' because there is no component supporting"
"trait '%s'", command_instance->GetName().c_str(),
trait_name.c_str());
- return false;
+ return nullptr;
}
command_instance->SetComponent(component_path);
}
const base::DictionaryValue* component = FindComponent(component_path, error);
if (!component)
- return false;
+ return nullptr;
// Check that the command's trait is supported by the given component.
auto pair = SplitAtFirst(command_instance->GetName(), ".", true);
@@ -218,18 +235,17 @@
"trait_not_supported",
"Component '%s' doesn't support trait '%s'",
component_path.c_str(), pair.first.c_str());
- return false;
+ return nullptr;
}
if (command_id.empty()) {
command_id = std::to_string(++next_command_id_);
command_instance->SetID(command_id);
+ if (id)
+ *id = command_id;
}
- if (id)
- *id = command_id;
- command_queue_.Add(std::move(command_instance));
- return true;
+ return command_instance;
}
CommandInstance* ComponentManagerImpl::FindCommand(const std::string& id) {
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h
index 9778a93..c59c6d9 100644
--- a/src/component_manager_impl.h
+++ b/src/component_manager_impl.h
@@ -49,13 +49,22 @@
// Sets callback which is called when new components are added.
void AddComponentTreeChangedCallback(const base::Closure& callback) override;
- // Parses the command definition from a json dictionary and adds it to the
- // command queue. The new command ID is returned through optional |id| param.
- bool AddCommand(const base::DictionaryValue& command,
- Command::Origin command_origin,
- UserRole role,
- std::string* id,
- ErrorPtr* error) override;
+ // Adds a new command instance to the command queue. The command specified in
+ // |command_instance| must be fully initialized and have its name, component,
+ // id populated.
+ void AddCommand(
+ std::unique_ptr<CommandInstance> command_instance) override;
+
+ // Parses the command definition from a json dictionary. The resulting command
+ // instance is populated with all the required fields and partially validated
+ // against syntax/schema.
+ // The new command ID is returned through optional |id| param.
+ std::unique_ptr<CommandInstance> ParseCommandInstance(
+ const base::DictionaryValue& command,
+ Command::Origin command_origin,
+ UserRole role,
+ std::string* id,
+ ErrorPtr* error) override;
// Find a command instance with the given ID in the command queue.
CommandInstance* FindCommand(const std::string& id) override;
@@ -180,6 +189,13 @@
ErrorPtr* error);
base::Clock* clock_{nullptr};
+ // An ID of last state change update. Each NotifyPropertiesUpdated()
+ // invocation increments this value by 1.
+ UpdateID last_state_change_id_{0};
+ // Callback list for state change queue event sinks.
+ // This member must be defined before |command_queue_|.
+ base::CallbackList<void(UpdateID)> on_server_state_updated_;
+
base::DictionaryValue traits_; // Trait definitions.
base::DictionaryValue components_; // Component instances.
CommandQueue command_queue_; // Command queue containing command instances.
@@ -187,13 +203,7 @@
std::vector<base::Closure> on_componet_tree_changed_;
std::vector<base::Closure> on_state_changed_;
uint32_t next_command_id_{0};
-
std::map<std::string, std::unique_ptr<StateChangeQueue>> state_change_queues_;
- // An ID of last state change update. Each NotifyPropertiesUpdated()
- // invocation increments this value by 1.
- UpdateID last_state_change_id_{0};
- // Callback list for state change queue event sinks.
- base::CallbackList<void(UpdateID)> on_server_state_updated_;
// Legacy API support.
mutable base::DictionaryValue legacy_state_; // Device state.
diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc
index 8c9b386..b35e16a 100644
--- a/src/component_manager_unittest.cc
+++ b/src/component_manager_unittest.cc
@@ -621,7 +621,7 @@
EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[1", nullptr));
}
-TEST(ComponentManager, AddCommand) {
+TEST(ComponentManager, ParseCommandInstance) {
ComponentManagerImpl manager;
const char kTraits[] = R"({
"trait1": {
@@ -635,6 +635,12 @@
"command1": { "minimalRole": "manager" },
"command2": { "minimalRole": "owner" }
}
+ },
+ "trait3": {
+ "commands": {
+ "command1": { "minimalRole": "manager" },
+ "command2": { "minimalRole": "owner" }
+ }
}
})";
auto traits = CreateDictionaryValue(kTraits);
@@ -650,12 +656,14 @@
"parameters": {}
})";
auto command1 = CreateDictionaryValue(kCommand1);
- EXPECT_TRUE(manager.AddCommand(*command1, Command::Origin::kLocal,
- UserRole::kUser, &id, nullptr));
+ EXPECT_NE(nullptr,
+ manager.ParseCommandInstance(*command1, Command::Origin::kLocal,
+ UserRole::kUser, &id, nullptr).get());
EXPECT_EQ("1234-12345", id);
// Not enough access rights
- EXPECT_FALSE(manager.AddCommand(*command1, Command::Origin::kLocal,
- UserRole::kViewer, &id, nullptr));
+ EXPECT_EQ(nullptr,
+ manager.ParseCommandInstance(*command1, Command::Origin::kLocal,
+ UserRole::kViewer, &id, nullptr).get());
const char kCommand2[] = R"({
"name": "trait1.command3",
@@ -664,8 +672,9 @@
})";
auto command2 = CreateDictionaryValue(kCommand2);
// trait1.command3 doesn't exist
- EXPECT_FALSE(manager.AddCommand(*command2, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr));
+ EXPECT_EQ(nullptr,
+ manager.ParseCommandInstance(*command2, Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr).get());
EXPECT_TRUE(id.empty());
const char kCommand3[] = R"({
@@ -675,8 +684,9 @@
})";
auto command3 = CreateDictionaryValue(kCommand3);
// Component comp1 doesn't have trait2.
- EXPECT_FALSE(manager.AddCommand(*command3, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr));
+ EXPECT_EQ(nullptr,
+ manager.ParseCommandInstance(*command3, Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr).get());
// No component specified, find the suitable component
const char kCommand4[] = R"({
@@ -684,22 +694,60 @@
"parameters": {}
})";
auto command4 = CreateDictionaryValue(kCommand4);
- EXPECT_TRUE(manager.AddCommand(*command4, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr));
- auto cmd = manager.FindCommand(id);
- ASSERT_NE(nullptr, cmd);
- EXPECT_EQ("comp1", cmd->GetComponent());
+ auto command_instance = manager.ParseCommandInstance(
+ *command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
+ EXPECT_NE(nullptr, command_instance.get());
+ EXPECT_EQ("comp1", command_instance->GetComponent());
const char kCommand5[] = R"({
"name": "trait2.command1",
"parameters": {}
})";
auto command5 = CreateDictionaryValue(kCommand5);
- EXPECT_TRUE(manager.AddCommand(*command5, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr));
- cmd = manager.FindCommand(id);
- ASSERT_NE(nullptr, cmd);
- EXPECT_EQ("comp2", cmd->GetComponent());
+ command_instance = manager.ParseCommandInstance(
+ *command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
+ EXPECT_NE(nullptr, command_instance.get());
+ EXPECT_EQ("comp2", command_instance->GetComponent());
+
+ // Cannot route the command, no component with 'trait3'.
+ const char kCommand6[] = R"({
+ "name": "trait3.command1",
+ "parameters": {}
+ })";
+ auto command6 = CreateDictionaryValue(kCommand6);
+ EXPECT_EQ(nullptr,
+ manager.ParseCommandInstance(*command6, Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr).get());
+}
+
+TEST(ComponentManager, AddCommand) {
+ ComponentManagerImpl manager;
+ const char kTraits[] = R"({
+ "trait1": {
+ "commands": {
+ "command1": { "minimalRole": "user" }
+ }
+ }
+ })";
+ auto traits = CreateDictionaryValue(kTraits);
+ ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
+
+ std::string id;
+ const char kCommand[] = R"({
+ "name": "trait1.command1",
+ "id": "1234-12345",
+ "component": "comp1",
+ "parameters": {}
+ })";
+ auto command = CreateDictionaryValue(kCommand);
+ auto command_instance = manager.ParseCommandInstance(
+ *command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
+ ASSERT_NE(nullptr, command_instance.get());
+ manager.AddCommand(std::move(command_instance));
+ const auto* queued_command = manager.FindCommand(id);
+ ASSERT_NE(nullptr, queued_command);
+ EXPECT_EQ("trait1.command1", queued_command->GetName());
}
TEST(ComponentManager, AddCommandHandler) {
@@ -738,8 +786,10 @@
"component": "comp1"
})";
auto command1 = CreateDictionaryValue(kCommand1);
- EXPECT_TRUE(manager.AddCommand(*command1, Command::Origin::kCloud,
- UserRole::kUser, nullptr, nullptr));
+ auto command_instance = manager.ParseCommandInstance(
+ *command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
+ ASSERT_NE(nullptr, command_instance.get());
+ manager.AddCommand(std::move(command_instance));
EXPECT_EQ("1", last_tags);
last_tags.clear();
@@ -748,8 +798,10 @@
"component": "comp2"
})";
auto command2 = CreateDictionaryValue(kCommand2);
- EXPECT_TRUE(manager.AddCommand(*command2, Command::Origin::kCloud,
- UserRole::kUser, nullptr, nullptr));
+ command_instance = manager.ParseCommandInstance(
+ *command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
+ ASSERT_NE(nullptr, command_instance.get());
+ manager.AddCommand(std::move(command_instance));
EXPECT_EQ("2", last_tags);
last_tags.clear();
@@ -759,8 +811,10 @@
"parameters": {}
})";
auto command3 = CreateDictionaryValue(kCommand3);
- EXPECT_TRUE(manager.AddCommand(*command3, Command::Origin::kLocal,
- UserRole::kUser, nullptr, nullptr));
+ command_instance = manager.ParseCommandInstance(
+ *command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
+ ASSERT_NE(nullptr, command_instance.get());
+ manager.AddCommand(std::move(command_instance));
EXPECT_EQ("3", last_tags);
last_tags.clear();
}
diff --git a/src/device_manager.cc b/src/device_manager.cc
index a44f0db..7a9021f 100644
--- a/src/device_manager.cc
+++ b/src/device_manager.cc
@@ -9,23 +9,16 @@
#include <base/bind.h>
#include "src/base_api_handler.h"
-#include "src/commands/command_manager.h"
+#include "src/commands/schema_constants.h"
#include "src/component_manager_impl.h"
#include "src/config.h"
#include "src/device_registration_info.h"
#include "src/privet/privet_manager.h"
-#include "src/states/state_change_queue.h"
-#include "src/states/state_manager.h"
+#include "src/string_utils.h"
+#include "src/utils.h"
namespace weave {
-namespace {
-
-// Max of 100 state update events should be enough in the queue.
-const size_t kMaxStateChangeQueueSize = 100;
-
-} // namespace
-
DeviceManager::DeviceManager(provider::ConfigStore* config_store,
provider::TaskRunner* task_runner,
provider::HttpClient* http_client,
@@ -35,16 +28,13 @@
provider::Wifi* wifi,
provider::Bluetooth* bluetooth) {
component_manager_.reset(new ComponentManagerImpl);
- command_manager_ = std::make_shared<CommandManager>();
- state_change_queue_.reset(new StateChangeQueue(kMaxStateChangeQueueSize));
- state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
std::unique_ptr<Config> config{new Config{config_store}};
config->Load();
device_info_.reset(new DeviceRegistrationInfo(
- command_manager_, state_manager_, std::move(config), task_runner,
- http_client, network));
+ component_manager_.get(), std::move(config), task_runner, http_client,
+ network));
base_api_handler_.reset(new BaseApiHandler{device_info_.get(), this});
device_info_->Start();
@@ -79,7 +69,7 @@
provider::Bluetooth* bluetooth) {
privet_.reset(new privet::Manager{task_runner});
privet_->Start(network, dns_sd, http_server, wifi, device_info_.get(),
- command_manager_.get(), state_manager_.get());
+ component_manager_.get());
}
GcdState DeviceManager::GetGcdState() const {
@@ -151,63 +141,108 @@
}
void DeviceManager::AddCommandDefinitionsFromJson(const std::string& json) {
- CHECK(command_manager_->LoadCommands(json, nullptr));
+ auto dict = LoadJsonDict(json, nullptr);
+ CHECK(dict);
+ AddCommandDefinitions(*dict);
}
void DeviceManager::AddCommandDefinitions(const base::DictionaryValue& dict) {
- CHECK(command_manager_->LoadCommands(dict, nullptr));
+ CHECK(component_manager_->AddLegacyCommandDefinitions(dict, nullptr));
}
bool DeviceManager::AddCommand(const base::DictionaryValue& command,
std::string* id,
ErrorPtr* error) {
- return command_manager_->AddCommand(command, id, error);
+ auto command_instance =
+ component_manager_->ParseCommandInstance(command, Command::Origin::kLocal,
+ UserRole::kOwner, id, error);
+ if (!command_instance)
+ return false;
+ component_manager_->AddCommand(std::move(command_instance));
+ return true;
}
Command* DeviceManager::FindCommand(const std::string& id) {
- return command_manager_->FindCommand(id);
+ return component_manager_->FindCommand(id);
}
void DeviceManager::AddCommandHandler(const std::string& command_name,
const CommandHandlerCallback& callback) {
- return command_manager_->AddCommandHandler(command_name, callback);
+ if (command_name.empty())
+ return component_manager_->AddCommandHandler("", "", callback);
+
+ auto trait = SplitAtFirst(command_name, ".", true).first;
+ std::string component = component_manager_->FindComponentWithTrait(trait);
+ CHECK(!component.empty());
+ component_manager_->AddCommandHandler(component, command_name, callback);
}
void DeviceManager::AddStateChangedCallback(const base::Closure& callback) {
- state_manager_->AddChangedCallback(callback);
+ component_manager_->AddStateChangedCallback(callback);
}
void DeviceManager::AddStateDefinitionsFromJson(const std::string& json) {
- CHECK(state_manager_->LoadStateDefinitionFromJson(json, nullptr));
+ auto dict = LoadJsonDict(json, nullptr);
+ CHECK(dict);
+ AddStateDefinitions(*dict);
}
void DeviceManager::AddStateDefinitions(const base::DictionaryValue& dict) {
- CHECK(state_manager_->LoadStateDefinition(dict, nullptr));
+ CHECK(component_manager_->AddLegacyStateDefinitions(dict, nullptr));
}
bool DeviceManager::SetStatePropertiesFromJson(const std::string& json,
ErrorPtr* error) {
- return state_manager_->SetPropertiesFromJson(json, error);
+ auto dict = LoadJsonDict(json, error);
+ return dict && SetStateProperties(*dict, error);
}
bool DeviceManager::SetStateProperties(const base::DictionaryValue& dict,
ErrorPtr* error) {
- return state_manager_->SetProperties(dict, error);
+ for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+ std::string component =
+ component_manager_->FindComponentWithTrait(it.key());
+ if (component.empty()) {
+ Error::AddToPrintf(
+ error, FROM_HERE, errors::commands::kDomain, "unrouted_state",
+ "Unable to set property value because there is no component supporting "
+ "trait '%s'", it.key().c_str());
+ return false;
+ }
+ base::DictionaryValue trait_state;
+ trait_state.Set(it.key(), it.value().DeepCopy());
+ if (!component_manager_->SetStateProperties(component, trait_state, error))
+ return false;
+ }
+ return true;
}
const base::Value* DeviceManager::GetStateProperty(
const std::string& name) const {
- return state_manager_->GetProperty(name);
+ auto trait = SplitAtFirst(name, ".", true).first;
+ std::string component = component_manager_->FindComponentWithTrait(trait);
+ if (component.empty())
+ return nullptr;
+ return component_manager_->GetStateProperty(component, name, nullptr);
}
bool DeviceManager::SetStateProperty(const std::string& name,
const base::Value& value,
ErrorPtr* error) {
- return state_manager_->SetProperty(name, value, error);
+ auto trait = SplitAtFirst(name, ".", true).first;
+ std::string component = component_manager_->FindComponentWithTrait(trait);
+ if (component.empty()) {
+ Error::AddToPrintf(
+ error, FROM_HERE, errors::commands::kDomain, "unrouted_state",
+ "Unable set value of state property '%s' because there is no component "
+ "supporting trait '%s'", name.c_str(), trait.c_str());
+ return false;
+ }
+ return component_manager_->SetStateProperty(component, name, value, error);
}
const base::DictionaryValue& DeviceManager::GetState() const {
- return state_manager_->GetState();
+ return component_manager_->GetLegacyState();
}
void DeviceManager::Register(const std::string& ticket_id,
diff --git a/src/device_manager.h b/src/device_manager.h
index 2a23755..3b042eb 100644
--- a/src/device_manager.h
+++ b/src/device_manager.h
@@ -12,11 +12,8 @@
class BaseApiHandler;
class Config;
-class CommandManager;
class ComponentManager;
class DeviceRegistrationInfo;
-class StateChangeQueue;
-class StateManager;
namespace privet {
class Manager;
@@ -103,9 +100,6 @@
provider::Bluetooth* bluetooth);
std::unique_ptr<ComponentManager> component_manager_;
- std::shared_ptr<CommandManager> command_manager_;
- std::unique_ptr<StateChangeQueue> state_change_queue_;
- std::shared_ptr<StateManager> state_manager_;
std::unique_ptr<DeviceRegistrationInfo> device_info_;
std::unique_ptr<BaseApiHandler> base_api_handler_;
std::unique_ptr<privet::Manager> privet_;
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index 9469d09..abdbb08 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -22,13 +22,11 @@
#include "src/bind_lambda.h"
#include "src/commands/cloud_command_proxy.h"
-#include "src/commands/command_manager.h"
#include "src/commands/schema_constants.h"
#include "src/data_encoding.h"
#include "src/http_constants.h"
#include "src/json_error_codes.h"
#include "src/notification/xmpp_channel.h"
-#include "src/states/state_manager.h"
#include "src/string_utils.h"
#include "src/utils.h"
@@ -239,16 +237,14 @@
} // anonymous namespace
DeviceRegistrationInfo::DeviceRegistrationInfo(
- const std::shared_ptr<CommandManager>& command_manager,
- const std::shared_ptr<StateManager>& state_manager,
+ ComponentManager* component_manager,
std::unique_ptr<Config> config,
provider::TaskRunner* task_runner,
provider::HttpClient* http_client,
provider::Network* network)
: http_client_{http_client},
task_runner_{task_runner},
- command_manager_{command_manager},
- state_manager_{state_manager},
+ component_manager_{component_manager},
config_{std::move(config)},
network_{network} {
cloud_backoff_policy_.reset(new BackoffEntry::Policy{});
@@ -267,10 +263,13 @@
gcd_state_ =
revoked ? GcdState::kInvalidCredentials : GcdState::kUnconfigured;
- command_manager_->AddCommandDefChanged(
- base::Bind(&DeviceRegistrationInfo::OnCommandDefsChanged,
+ component_manager_->AddTraitDefChangedCallback(
+ base::Bind(&DeviceRegistrationInfo::OnTraitDefsChanged,
weak_factory_.GetWeakPtr()));
- state_manager_->AddChangedCallback(base::Bind(
+ component_manager_->AddComponentTreeChangedCallback(base::Bind(
+ &DeviceRegistrationInfo::OnComponentTreeChanged,
+ weak_factory_.GetWeakPtr()));
+ component_manager_->AddStateChangedCallback(base::Bind(
&DeviceRegistrationInfo::OnStateChanged, weak_factory_.GetWeakPtr()));
}
@@ -479,12 +478,6 @@
std::unique_ptr<base::DictionaryValue>
DeviceRegistrationInfo::BuildDeviceResource(ErrorPtr* error) {
- // Limit only to commands that are visible to the cloud.
- const base::DictionaryValue& commands =
- command_manager_->GetCommandDictionary().GetCommandsAsJson();
-
- const base::DictionaryValue& state = state_manager_->GetState();
-
std::unique_ptr<base::DictionaryValue> resource{new base::DictionaryValue};
if (!GetSettings().cloud_id.empty())
resource->SetString("id", GetSettings().cloud_id);
@@ -503,34 +496,12 @@
channel->SetString("supportedType", "pull");
}
resource->Set("channel", channel.release());
- resource->Set("commandDefs", commands.DeepCopy());
- resource->Set("state", state.DeepCopy());
+ resource->Set("commandDefs",
+ component_manager_->GetLegacyCommandDefinitions().DeepCopy());
+ resource->Set("state", component_manager_->GetLegacyState().DeepCopy());
+ resource->Set("traits", component_manager_->GetTraits().DeepCopy());
+ resource->Set("components", component_manager_->GetComponents().DeepCopy());
- // TODO(avakulenko): Temporary code to generate a single top-level component
- // using the new component-trait model. This is to unblock clients to start
- // implementation on their side.
- base::DictionaryValue traits;
- base::DictionaryValue component;
- std::set<std::string> all_traits;
- for (const auto& pair : state_manager_->packages()) {
- all_traits.insert(pair.first);
- std::string key = base::StringPrintf("%s.state", pair.first.c_str());
- traits.Set(key, pair.second->types().DeepCopy());
- key = base::StringPrintf("state.%s", pair.first.c_str());
- component.Set(key, pair.second->GetValuesAsJson().DeepCopy());
- }
- for (base::DictionaryValue::Iterator it(commands); !it.IsAtEnd();
- it.Advance()) {
- all_traits.insert(it.key());
- std::string key = base::StringPrintf("%s.commands", it.key().c_str());
- traits.Set(key, it.value().DeepCopy());
- }
- resource->Set("traits", traits.DeepCopy());
- base::ListValue* trait_list = new base::ListValue();
- for (const std::string& trait : all_traits)
- trait_list->AppendString(trait);
- component.Set("traits", trait_list);
- resource->Set("components.device", component.DeepCopy());
return resource;
}
@@ -1102,8 +1073,8 @@
const base::DictionaryValue& command) {
std::string command_id;
ErrorPtr error;
- auto command_instance = CommandInstance::FromJson(
- &command, Command::Origin::kCloud, &command_id, &error);
+ auto command_instance = component_manager_->ParseCommandInstance(
+ command, Command::Origin::kCloud, UserRole::kOwner, &command_id, &error);
if (!command_instance) {
LOG(WARNING) << "Failed to parse a command instance: " << command;
if (!command_id.empty())
@@ -1112,19 +1083,19 @@
}
// TODO(antonm): Properly process cancellation of commands.
- if (!command_manager_->FindCommand(command_instance->GetID())) {
+ if (!component_manager_->FindCommand(command_instance->GetID())) {
LOG(INFO) << "New command '" << command_instance->GetName()
<< "' arrived, ID: " << command_instance->GetID();
std::unique_ptr<BackoffEntry> backoff_entry{
new BackoffEntry{cloud_backoff_policy_.get()}};
std::unique_ptr<CloudCommandProxy> cloud_proxy{new CloudCommandProxy{
- command_instance.get(), this, state_manager_->GetStateChangeQueue(),
+ command_instance.get(), this, component_manager_,
std::move(backoff_entry), task_runner_}};
// CloudCommandProxy::CloudCommandProxy() subscribe itself to Command
// notifications. When Command is being destroyed it sends
// ::OnCommandDestroyed() and CloudCommandProxy deletes itself.
cloud_proxy.release();
- command_manager_->AddCommand(std::move(command_instance));
+ component_manager_->AddCommand(std::move(command_instance));
}
}
@@ -1133,18 +1104,18 @@
if (device_state_update_pending_)
return;
- StateChangeQueueInterface::UpdateID update_id = 0;
- std::vector<StateChange> state_changes;
- std::tie(update_id, state_changes) =
- state_manager_->GetAndClearRecordedStateChanges();
- if (state_changes.empty())
+ auto snapshot = component_manager_->GetAndClearRecordedStateChanges();
+ if (snapshot.state_changes.empty())
return;
std::unique_ptr<base::ListValue> patches{new base::ListValue};
- for (auto& state_change : state_changes) {
+ for (auto& state_change : snapshot.state_changes) {
std::unique_ptr<base::DictionaryValue> patch{new base::DictionaryValue};
patch->SetString("timeMs",
std::to_string(state_change.timestamp.ToJavaTime()));
+ // TODO(avakulenko): Uncomment this once server supports "component"
+ // attribute on a state patch object.
+ // patch->SetString("component", state_change.component);
patch->Set("patch", state_change.changed_properties.release());
patches->Append(patch.release());
}
@@ -1157,11 +1128,11 @@
device_state_update_pending_ = true;
DoCloudRequest(HttpClient::Method::kPost, GetDeviceURL("patchState"), &body,
base::Bind(&DeviceRegistrationInfo::OnPublishStateDone,
- AsWeakPtr(), update_id));
+ AsWeakPtr(), snapshot.update_id));
}
void DeviceRegistrationInfo::OnPublishStateDone(
- StateChangeQueueInterface::UpdateID update_id,
+ ComponentManager::UpdateID update_id,
const base::DictionaryValue& reply,
ErrorPtr error) {
device_state_update_pending_ = false;
@@ -1169,7 +1140,7 @@
LOG(ERROR) << "Permanent failure while trying to update device state";
return;
}
- state_manager_->NotifyStateUpdatedOnServer(update_id);
+ component_manager_->NotifyStateUpdatedOnServer(update_id);
// See if there were more pending state updates since the previous request
// had been sent out.
PublishStateUpdates();
@@ -1183,7 +1154,7 @@
cb.Run(gcd_state_);
}
-void DeviceRegistrationInfo::OnCommandDefsChanged() {
+void DeviceRegistrationInfo::OnTraitDefsChanged() {
VLOG(1) << "CommandDefinitionChanged notification received";
if (!HaveRegistrationCredentials() || !connected_to_cloud_)
return;
@@ -1200,6 +1171,14 @@
PublishStateUpdates();
}
+void DeviceRegistrationInfo::OnComponentTreeChanged() {
+ VLOG(1) << "ComponentTreeChanged notification received";
+ if (!HaveRegistrationCredentials() || !connected_to_cloud_)
+ return;
+
+ UpdateDeviceResource(base::Bind(&IgnoreCloudError));
+}
+
void DeviceRegistrationInfo::OnConnected(const std::string& channel_name) {
LOG(INFO) << "Notification channel successfully established over "
<< channel_name;
diff --git a/src/device_registration_info.h b/src/device_registration_info.h
index 1399b37..f3b5302 100644
--- a/src/device_registration_info.h
+++ b/src/device_registration_info.h
@@ -21,13 +21,12 @@
#include "src/backoff_entry.h"
#include "src/commands/cloud_command_update_interface.h"
-#include "src/commands/command_manager.h"
+#include "src/component_manager.h"
#include "src/config.h"
#include "src/data_encoding.h"
#include "src/notification/notification_channel.h"
#include "src/notification/notification_delegate.h"
#include "src/notification/pull_channel.h"
-#include "src/states/state_change_queue_interface.h"
namespace base {
class DictionaryValue;
@@ -54,12 +53,12 @@
base::Callback<void(const base::DictionaryValue& response,
ErrorPtr error)>;
- DeviceRegistrationInfo(const std::shared_ptr<CommandManager>& command_manager,
- const std::shared_ptr<StateManager>& state_manager,
- std::unique_ptr<Config> config,
- provider::TaskRunner* task_runner,
- provider::HttpClient* http_client,
- provider::Network* network);
+ DeviceRegistrationInfo(
+ ComponentManager* component_manager,
+ std::unique_ptr<Config> config,
+ provider::TaskRunner* task_runner,
+ provider::HttpClient* http_client,
+ provider::Network* network);
~DeviceRegistrationInfo() override;
@@ -236,7 +235,7 @@
void FetchAndPublishCommands(const std::string& reason);
void PublishStateUpdates();
- void OnPublishStateDone(StateChangeQueueInterface::UpdateID update_id,
+ void OnPublishStateDone(ComponentManager::UpdateID update_id,
const base::DictionaryValue& reply,
ErrorPtr error);
void OnPublishStateError(ErrorPtr error);
@@ -254,7 +253,8 @@
void SetDeviceId(const std::string& cloud_id);
// Callback called when command definitions are changed to re-publish new CDD.
- void OnCommandDefsChanged();
+ void OnTraitDefsChanged();
+ void OnComponentTreeChanged();
void OnStateChanged();
// Overrides from NotificationDelegate.
@@ -299,10 +299,8 @@
provider::HttpClient* http_client_{nullptr};
provider::TaskRunner* task_runner_{nullptr};
- // Global command manager.
- std::shared_ptr<CommandManager> command_manager_;
- // Device state manager.
- std::shared_ptr<StateManager> state_manager_;
+ // Global component manager.
+ ComponentManager* component_manager_{nullptr};
std::unique_ptr<Config> config_;
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index f2fe4c4..c242ee5 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -14,10 +14,8 @@
#include <weave/test/unittest_utils.h>
#include "src/bind_lambda.h"
-#include "src/commands/command_manager.h"
+#include "src/component_manager_impl.h"
#include "src/http_constants.h"
-#include "src/states/mock_state_change_queue_interface.h"
-#include "src/states/state_manager.h"
using testing::_;
using testing::AtLeast;
@@ -115,17 +113,9 @@
class DeviceRegistrationInfoTest : public ::testing::Test {
protected:
void SetUp() override {
- EXPECT_CALL(mock_state_change_queue_, GetLastStateChangeId())
- .WillRepeatedly(Return(0));
- EXPECT_CALL(mock_state_change_queue_, MockAddOnStateUpdatedCallback(_))
- .WillRepeatedly(Return(nullptr));
-
- command_manager_ = std::make_shared<CommandManager>();
- state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
-
std::unique_ptr<Config> config{new Config{&config_store_}};
config_ = config.get();
- dev_reg_.reset(new DeviceRegistrationInfo{command_manager_, state_manager_,
+ dev_reg_.reset(new DeviceRegistrationInfo{&component_manager_,
std::move(config), &task_runner_,
&http_client_, nullptr});
@@ -196,9 +186,7 @@
base::DictionaryValue data_;
Config* config_{nullptr};
std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
- std::shared_ptr<CommandManager> command_manager_;
- StrictMock<MockStateChangeQueueInterface> mock_state_change_queue_;
- std::shared_ptr<StateManager> state_manager_;
+ ComponentManagerImpl component_manager_;
};
TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
@@ -352,21 +340,33 @@
}
TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
- auto json_cmds = CreateDictionaryValue(R"({
+ auto json_traits = CreateDictionaryValue(R"({
'base': {
- 'reboot': {
- 'parameters': {'delay': {'minimum': 10, 'type': 'integer'}},
- 'minimalRole': 'user'
+ 'commands': {
+ 'reboot': {
+ 'parameters': {'delay': {'minimum': 10, 'type': 'integer'}},
+ 'minimalRole': 'user'
+ }
+ },
+ 'state': {
+ 'firmwareVersion': {'type': 'string'}
}
},
'robot': {
- '_jump': {
- 'parameters': {'_height': {'type': 'integer'}},
- 'minimalRole': 'user'
+ 'commands': {
+ '_jump': {
+ 'parameters': {'_height': {'type': 'integer'}},
+ 'minimalRole': 'user'
+ }
}
}
})");
- EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, nullptr));
+ EXPECT_TRUE(component_manager_.LoadTraits(*json_traits, nullptr));
+ EXPECT_TRUE(component_manager_.AddComponent("", "comp", {"base", "robot"},
+ nullptr));
+ base::StringValue ver{"1.0"};
+ EXPECT_TRUE(component_manager_.SetStateProperty(
+ "comp", "base.firmwareVersion", ver, nullptr));
std::string ticket_url = dev_reg_->GetServiceURL("registrationTickets/") +
test_data::kClaimTicketId;
@@ -395,12 +395,9 @@
EXPECT_EQ("AAAAA", value);
EXPECT_TRUE(json->GetString("deviceDraft.name", &value));
EXPECT_EQ("Coffee Pot", value);
- base::DictionaryValue* commandDefs = nullptr;
- EXPECT_TRUE(
- json->GetDictionary("deviceDraft.commandDefs", &commandDefs));
- EXPECT_FALSE(commandDefs->empty());
-
- auto expected = R"({
+ base::DictionaryValue* dict = nullptr;
+ EXPECT_TRUE(json->GetDictionary("deviceDraft.commandDefs", &dict));
+ auto expectedCommandDefs = R"({
'base': {
'reboot': {
'parameters': {
@@ -423,7 +420,50 @@
}
}
})";
- EXPECT_JSON_EQ(expected, *commandDefs);
+ EXPECT_JSON_EQ(expectedCommandDefs, *dict);
+
+ EXPECT_TRUE(json->GetDictionary("deviceDraft.state", &dict));
+ auto expectedState = R"({
+ 'base': {
+ 'firmwareVersion': '1.0'
+ }
+ })";
+ EXPECT_JSON_EQ(expectedState, *dict);
+
+ EXPECT_TRUE(json->GetDictionary("deviceDraft.traits", &dict));
+ auto expectedTraits = R"({
+ 'base': {
+ 'commands': {
+ 'reboot': {
+ 'parameters': {'delay': {'minimum': 10, 'type': 'integer'}},
+ 'minimalRole': 'user'
+ }
+ },
+ 'state': {
+ 'firmwareVersion': {'type': 'string'}
+ }
+ },
+ 'robot': {
+ 'commands': {
+ '_jump': {
+ 'parameters': {'_height': {'type': 'integer'}},
+ 'minimalRole': 'user'
+ }
+ }
+ }
+ })";
+ EXPECT_JSON_EQ(expectedTraits, *dict);
+
+ EXPECT_TRUE(json->GetDictionary("deviceDraft.components", &dict));
+ auto expectedComponents = R"({
+ 'comp': {
+ 'traits': ['base', 'robot'],
+ 'state': {
+ 'base': { 'firmwareVersion': '1.0' }
+ }
+ }
+ })";
+ EXPECT_JSON_EQ(expectedComponents, *dict);
base::DictionaryValue json_resp;
json_resp.SetString("id", test_data::kClaimTicketId);
@@ -519,22 +559,27 @@
ReloadSettings();
SetAccessToken();
- auto json_cmds = CreateDictionaryValue(R"({
+ auto json_traits = CreateDictionaryValue(R"({
'robot': {
- '_jump': {
- 'parameters': {'_height': 'integer'},
- 'progress': {'progress': 'integer'},
- 'results': {'status': 'string'},
- 'minimalRole': 'user'
+ 'commands': {
+ '_jump': {
+ 'parameters': {'_height': 'integer'},
+ 'progress': {'progress': 'integer'},
+ 'results': {'status': 'string'},
+ 'minimalRole': 'user'
+ }
}
}
})");
- EXPECT_TRUE(command_manager_->LoadCommands(*json_cmds, nullptr));
+ EXPECT_TRUE(component_manager_.LoadTraits(*json_traits, nullptr));
+ EXPECT_TRUE(component_manager_.AddComponent("", "comp", {"robot"},
+ nullptr));
command_url_ = dev_reg_->GetServiceURL("commands/1234");
auto commands_json = CreateValue(R"([{
'name':'robot._jump',
+ 'component': 'comp',
'id':'1234',
'parameters': {'_height': 100},
'minimalRole': 'user'
@@ -543,7 +588,7 @@
const base::ListValue* command_list = nullptr;
ASSERT_TRUE(commands_json->GetAsList(&command_list));
PublishCommands(*command_list);
- command_ = command_manager_->FindCommand("1234");
+ command_ = component_manager_.FindCommand("1234");
ASSERT_NE(nullptr, command_);
}
diff --git a/src/mock_component_manager.h b/src/mock_component_manager.h
index aa58177..e30b8b0 100644
--- a/src/mock_component_manager.h
+++ b/src/mock_component_manager.h
@@ -29,7 +29,9 @@
ErrorPtr* error));
MOCK_METHOD1(AddComponentTreeChangedCallback,
void(const base::Closure& callback));
- MOCK_METHOD5(AddCommand, bool(const base::DictionaryValue& command,
+ MOCK_METHOD1(MockAddCommand, void(CommandInstance* command_instance));
+ MOCK_METHOD5(MockParseCommandInstance,
+ CommandInstance*(const base::DictionaryValue& command,
Command::Origin command_origin,
UserRole role,
std::string* id,
@@ -89,6 +91,18 @@
const base::DictionaryValue&());
private:
+ void AddCommand(std::unique_ptr<CommandInstance> command_instance) override {
+ MockAddCommand(command_instance.get());
+ }
+ std::unique_ptr<CommandInstance> ParseCommandInstance(
+ const base::DictionaryValue& command,
+ Command::Origin command_origin,
+ UserRole role,
+ std::string* id,
+ ErrorPtr* error) {
+ return std::unique_ptr<CommandInstance>{MockParseCommandInstance(
+ command, command_origin, role, id, error)};
+ }
StateSnapshot GetAndClearRecordedStateChanges() override {
return std::move(MockGetAndClearRecordedStateChanges());
}
diff --git a/src/privet/cloud_delegate.cc b/src/privet/cloud_delegate.cc
index 139bfc6..9c8a619 100644
--- a/src/privet/cloud_delegate.cc
+++ b/src/privet/cloud_delegate.cc
@@ -15,11 +15,10 @@
#include <weave/provider/task_runner.h>
#include "src/backoff_entry.h"
-#include "src/commands/command_manager.h"
+#include "src/component_manager.h"
#include "src/config.h"
#include "src/device_registration_info.h"
#include "src/privet/constants.h"
-#include "src/states/state_manager.h"
namespace weave {
namespace privet {
@@ -42,26 +41,28 @@
public:
CloudDelegateImpl(provider::TaskRunner* task_runner,
DeviceRegistrationInfo* device,
- CommandManager* command_manager,
- StateManager* state_manager)
+ ComponentManager* component_manager)
: task_runner_{task_runner},
device_{device},
- command_manager_{command_manager},
- state_manager_{state_manager} {
+ component_manager_{component_manager} {
device_->GetMutableConfig()->AddOnChangedCallback(base::Bind(
&CloudDelegateImpl::OnConfigChanged, weak_factory_.GetWeakPtr()));
device_->AddGcdStateChangedCallback(base::Bind(
&CloudDelegateImpl::OnRegistrationChanged, weak_factory_.GetWeakPtr()));
- command_manager_->AddCommandDefChanged(base::Bind(
- &CloudDelegateImpl::OnCommandDefChanged, weak_factory_.GetWeakPtr()));
- command_manager_->AddCommandAddedCallback(base::Bind(
+ component_manager_->AddTraitDefChangedCallback(base::Bind(
+ &CloudDelegateImpl::NotifyOnTraitDefsChanged,
+ weak_factory_.GetWeakPtr()));
+ component_manager_->AddCommandAddedCallback(base::Bind(
&CloudDelegateImpl::OnCommandAdded, weak_factory_.GetWeakPtr()));
- command_manager_->AddCommandRemovedCallback(base::Bind(
+ component_manager_->AddCommandRemovedCallback(base::Bind(
&CloudDelegateImpl::OnCommandRemoved, weak_factory_.GetWeakPtr()));
-
- state_manager_->AddChangedCallback(base::Bind(
- &CloudDelegateImpl::OnStateChanged, weak_factory_.GetWeakPtr()));
+ component_manager_->AddStateChangedCallback(base::Bind(
+ &CloudDelegateImpl::NotifyOnComponentTreeChanged,
+ weak_factory_.GetWeakPtr()));
+ component_manager_->AddComponentTreeChangedCallback(base::Bind(
+ &CloudDelegateImpl::NotifyOnComponentTreeChanged,
+ weak_factory_.GetWeakPtr()));
}
~CloudDelegateImpl() override = default;
@@ -139,10 +140,20 @@
: "";
}
- const base::DictionaryValue& GetState() const override { return state_; }
+ const base::DictionaryValue& GetLegacyCommandDef() const override {
+ return component_manager_->GetLegacyCommandDefinitions();
+ }
- const base::DictionaryValue& GetCommandDef() const override {
- return command_defs_;
+ const base::DictionaryValue& GetLegacyState() const override {
+ return component_manager_->GetLegacyState();
+ }
+
+ const base::DictionaryValue& GetComponents() const override {
+ return component_manager_->GetComponents();
+ }
+
+ const base::DictionaryValue& GetTraits() const override {
+ return component_manager_->GetTraits();
}
void AddCommand(const base::DictionaryValue& command,
@@ -162,11 +173,13 @@
}
std::string id;
- if (!command_manager_->AddCommand(command, role, &id, &error))
+ auto command_instance = component_manager_->ParseCommandInstance(
+ command, Command::Origin::kLocal, role, &id, &error);
+ if (!command_instance)
return callback.Run({}, std::move(error));
-
+ component_manager_->AddCommand(std::move(command_instance));
command_owners_[id] = user_info.user_id();
- callback.Run(*command_manager_->FindCommand(id)->ToJson(), nullptr);
+ callback.Run(*component_manager_->FindCommand(id)->ToJson(), nullptr);
}
void GetCommand(const std::string& id,
@@ -200,7 +213,7 @@
for (const auto& it : command_owners_) {
if (CanAccessCommand(it.second, user_info, nullptr)) {
list_value.Append(
- command_manager_->FindCommand(it.first)->ToJson().release());
+ component_manager_->FindCommand(it.first)->ToJson().release());
}
}
@@ -241,21 +254,6 @@
NotifyOnDeviceInfoChanged();
}
- void OnStateChanged() {
- state_.Clear();
- const auto& state = state_manager_->GetState();
- state_.MergeDictionary(&state);
- NotifyOnStateChanged();
- }
-
- void OnCommandDefChanged() {
- command_defs_.Clear();
- const base::DictionaryValue& commands =
- command_manager_->GetCommandDictionary().GetCommandsAsJson();
- command_defs_.MergeDictionary(&commands);
- NotifyOnCommandDefsChanged();
- }
-
void OnRegisterSuccess(const std::string& cloud_id) {
VLOG(1) << "Device registered: " << cloud_id;
setup_state_ = SetupState(SetupState::kSuccess);
@@ -304,7 +302,7 @@
return nullptr;
}
- auto command = command_manager_->FindCommand(command_id);
+ auto command = component_manager_->FindCommand(command_id);
if (!command)
return ReturnNotFound(command_id, error);
@@ -329,8 +327,7 @@
provider::TaskRunner* task_runner_{nullptr};
DeviceRegistrationInfo* device_{nullptr};
- CommandManager* command_manager_{nullptr};
- StateManager* state_manager_{nullptr};
+ ComponentManager* component_manager_{nullptr};
// Primary state of GCD.
ConnectionState connection_state_{ConnectionState::kDisabled};
@@ -338,12 +335,6 @@
// State of the current or last setup.
SetupState setup_state_{SetupState::kNone};
- // Current device state.
- base::DictionaryValue state_;
-
- // Current commands definitions.
- base::DictionaryValue command_defs_;
-
// Map of command IDs to user IDs.
std::map<std::string, uint64_t> command_owners_;
@@ -367,22 +358,21 @@
std::unique_ptr<CloudDelegate> CloudDelegate::CreateDefault(
provider::TaskRunner* task_runner,
DeviceRegistrationInfo* device,
- CommandManager* command_manager,
- StateManager* state_manager) {
+ ComponentManager* component_manager) {
return std::unique_ptr<CloudDelegateImpl>{new CloudDelegateImpl{
- task_runner, device, command_manager, state_manager}};
+ task_runner, device, component_manager}};
}
void CloudDelegate::NotifyOnDeviceInfoChanged() {
FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceInfoChanged());
}
-void CloudDelegate::NotifyOnCommandDefsChanged() {
- FOR_EACH_OBSERVER(Observer, observer_list_, OnCommandDefsChanged());
+void CloudDelegate::NotifyOnTraitDefsChanged() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnTraitDefsChanged());
}
-void CloudDelegate::NotifyOnStateChanged() {
- FOR_EACH_OBSERVER(Observer, observer_list_, OnStateChanged());
+void CloudDelegate::NotifyOnComponentTreeChanged() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnComponentTreeChanged());
}
} // namespace privet
diff --git a/src/privet/cloud_delegate.h b/src/privet/cloud_delegate.h
index 6396519..e1b1887 100644
--- a/src/privet/cloud_delegate.h
+++ b/src/privet/cloud_delegate.h
@@ -22,9 +22,8 @@
namespace weave {
-class CommandManager;
+class ComponentManager;
class DeviceRegistrationInfo;
-class StateManager;
namespace provider {
class TaskRunner;
@@ -48,8 +47,8 @@
virtual ~Observer() {}
virtual void OnDeviceInfoChanged() {}
- virtual void OnCommandDefsChanged() {}
- virtual void OnStateChanged() {}
+ virtual void OnTraitDefsChanged() {}
+ virtual void OnComponentTreeChanged() {}
};
// Returns the ID of the device.
@@ -95,11 +94,17 @@
// Returns cloud id if the registered device or empty string if unregistered.
virtual std::string GetCloudId() const = 0;
- // Returns dictionary with device state.
- virtual const base::DictionaryValue& GetState() const = 0;
+ // Returns dictionary with device state (for legacy APIs).
+ virtual const base::DictionaryValue& GetLegacyState() const = 0;
- // Returns dictionary with commands definitions.
- virtual const base::DictionaryValue& GetCommandDef() const = 0;
+ // Returns dictionary with commands definitions (for legacy APIs).
+ virtual const base::DictionaryValue& GetLegacyCommandDef() const = 0;
+
+ // Returns dictionary with component tree.
+ virtual const base::DictionaryValue& GetComponents() const = 0;
+
+ // Returns dictionary with trait definitions.
+ virtual const base::DictionaryValue& GetTraits() const = 0;
// Adds command created from the given JSON representation.
virtual void AddCommand(const base::DictionaryValue& command,
@@ -126,15 +131,14 @@
}
void NotifyOnDeviceInfoChanged();
- void NotifyOnCommandDefsChanged();
- void NotifyOnStateChanged();
+ void NotifyOnTraitDefsChanged();
+ void NotifyOnComponentTreeChanged();
// Create default instance.
static std::unique_ptr<CloudDelegate> CreateDefault(
provider::TaskRunner* task_runner,
DeviceRegistrationInfo* device,
- CommandManager* command_manager,
- StateManager* state_manager);
+ ComponentManager* component_manager);
private:
base::ObserverList<Observer> observer_list_;
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h
index 2186f2f..0cfa4ed 100644
--- a/src/privet/mock_delegates.h
+++ b/src/privet/mock_delegates.h
@@ -153,8 +153,10 @@
MOCK_CONST_METHOD0(GetSetupState, const SetupState&());
MOCK_METHOD3(Setup, bool(const std::string&, const std::string&, ErrorPtr*));
MOCK_CONST_METHOD0(GetCloudId, std::string());
- MOCK_CONST_METHOD0(GetState, const base::DictionaryValue&());
- MOCK_CONST_METHOD0(GetCommandDef, const base::DictionaryValue&());
+ MOCK_CONST_METHOD0(GetLegacyState, const base::DictionaryValue&());
+ MOCK_CONST_METHOD0(GetLegacyCommandDef, const base::DictionaryValue&());
+ MOCK_CONST_METHOD0(GetComponents, const base::DictionaryValue&());
+ MOCK_CONST_METHOD0(GetTraits, const base::DictionaryValue&());
MOCK_METHOD3(AddCommand,
void(const base::DictionaryValue&,
const UserInfo&,
@@ -185,8 +187,11 @@
EXPECT_CALL(*this, GetSetupState()).WillRepeatedly(ReturnRef(setup_state_));
EXPECT_CALL(*this, GetCloudId()).WillRepeatedly(Return("TestCloudId"));
test_dict_.Set("test", new base::DictionaryValue);
- EXPECT_CALL(*this, GetCommandDef()).WillRepeatedly(ReturnRef(test_dict_));
- EXPECT_CALL(*this, GetState()).WillRepeatedly(ReturnRef(test_dict_));
+ EXPECT_CALL(*this, GetLegacyState()).WillRepeatedly(ReturnRef(test_dict_));
+ EXPECT_CALL(*this,
+ GetLegacyCommandDef()).WillRepeatedly(ReturnRef(test_dict_));
+ EXPECT_CALL(*this, GetTraits()).WillRepeatedly(ReturnRef(test_dict_));
+ EXPECT_CALL(*this, GetComponents()).WillRepeatedly(ReturnRef(test_dict_));
}
ConnectionState connection_state_{ConnectionState::kOnline};
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc
index 157feed..d609787 100644
--- a/src/privet/privet_handler.cc
+++ b/src/privet/privet_handler.cc
@@ -378,7 +378,7 @@
ReplyToUpdateRequest(req.callback);
}
-void PrivetHandler::OnCommandDefsChanged() {
+void PrivetHandler::OnTraitDefsChanged() {
++command_defs_fingerprint_;
auto pred = [this](const UpdateRequestParameters& params) {
return params.command_defs_fingerprint < 0;
@@ -390,7 +390,7 @@
update_requests_.erase(last, update_requests_.end());
}
-void PrivetHandler::OnStateChanged() {
+void PrivetHandler::OnComponentTreeChanged() {
++state_fingerprint_;
auto pred = [this](const UpdateRequestParameters& params) {
return params.state_fingerprint < 0;
@@ -762,8 +762,7 @@
const UserInfo& user_info,
const RequestCallback& callback) {
base::DictionaryValue output;
- base::DictionaryValue* defs = cloud_->GetState().DeepCopy();
- output.Set(kStateKey, defs);
+ output.Set(kStateKey, cloud_->GetLegacyState().DeepCopy());
output.SetString(kFingerprintKey, std::to_string(state_fingerprint_));
callback.Run(http::kOk, output);
@@ -773,8 +772,7 @@
const UserInfo& user_info,
const RequestCallback& callback) {
base::DictionaryValue output;
- base::DictionaryValue* defs = cloud_->GetCommandDef().DeepCopy();
- output.Set(kCommandsKey, defs);
+ output.Set(kCommandsKey, cloud_->GetLegacyCommandDef().DeepCopy());
output.SetString(kFingerprintKey, std::to_string(command_defs_fingerprint_));
callback.Run(http::kOk, output);
diff --git a/src/privet/privet_handler.h b/src/privet/privet_handler.h
index fb9cc94..cc80d43 100644
--- a/src/privet/privet_handler.h
+++ b/src/privet/privet_handler.h
@@ -45,8 +45,8 @@
WifiDelegate* wifi);
~PrivetHandler() override;
- void OnCommandDefsChanged() override;
- void OnStateChanged() override;
+ void OnTraitDefsChanged() override;
+ void OnComponentTreeChanged() override;
std::vector<std::string> GetHttpPaths() const;
std::vector<std::string> GetHttpsPaths() const;
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc
index c212e54..517dda8 100644
--- a/src/privet/privet_handler_unittest.cc
+++ b/src/privet/privet_handler_unittest.cc
@@ -630,7 +630,7 @@
EXPECT_PRED2(IsEqualJson, "{'state': {'test': {}}, 'fingerprint': '0'}",
HandleRequest("/privet/v3/state", "{}"));
- cloud_.NotifyOnStateChanged();
+ cloud_.NotifyOnComponentTreeChanged();
EXPECT_PRED2(IsEqualJson, "{'state': {'test': {}}, 'fingerprint': '1'}",
HandleRequest("/privet/v3/state", "{}"));
@@ -640,7 +640,7 @@
EXPECT_PRED2(IsEqualJson, "{'commands': {'test':{}}, 'fingerprint': '0'}",
HandleRequest("/privet/v3/commandDefs", "{}"));
- cloud_.NotifyOnCommandDefsChanged();
+ cloud_.NotifyOnTraitDefsChanged();
EXPECT_PRED2(IsEqualJson, "{'commands': {'test':{}}, 'fingerprint': '1'}",
HandleRequest("/privet/v3/commandDefs", "{}"));
@@ -735,8 +735,8 @@
TEST_F(PrivetHandlerSetupTest, CheckForUpdates_NoInput) {
EXPECT_CALL(device_, GetHttpRequestTimeout())
.WillOnce(Return(base::TimeDelta::Max()));
- cloud_.NotifyOnCommandDefsChanged();
- cloud_.NotifyOnStateChanged();
+ cloud_.NotifyOnTraitDefsChanged();
+ cloud_.NotifyOnComponentTreeChanged();
const char kInput[] = "{}";
const char kExpected[] = R"({
'commandsFingerprint': '1',
@@ -750,8 +750,8 @@
TEST_F(PrivetHandlerSetupTest, CheckForUpdates_AlreadyChanged) {
EXPECT_CALL(device_, GetHttpRequestTimeout())
.WillOnce(Return(base::TimeDelta::Max()));
- cloud_.NotifyOnCommandDefsChanged();
- cloud_.NotifyOnStateChanged();
+ cloud_.NotifyOnTraitDefsChanged();
+ cloud_.NotifyOnComponentTreeChanged();
const char kInput[] = R"({
'commandsFingerprint': '0',
'stateFingerprint': '0'
@@ -775,7 +775,7 @@
EXPECT_PRED2(IsEqualJson, "{}",
HandleRequest("/privet/v3/checkForUpdates", kInput));
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnCommandDefsChanged();
+ cloud_.NotifyOnTraitDefsChanged();
EXPECT_EQ(1, GetResponseCount());
const char kExpected[] = R"({
'commandsFingerprint': '1',
@@ -794,7 +794,7 @@
EXPECT_PRED2(IsEqualJson, "{}",
HandleRequest("/privet/v3/checkForUpdates", kInput));
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnStateChanged();
+ cloud_.NotifyOnComponentTreeChanged();
EXPECT_EQ(1, GetResponseCount());
const char kExpected[] = R"({
'commandsFingerprint': '0',
@@ -812,9 +812,9 @@
EXPECT_PRED2(IsEqualJson, "{}",
HandleRequest("/privet/v3/checkForUpdates", kInput));
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnCommandDefsChanged();
+ cloud_.NotifyOnTraitDefsChanged();
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnStateChanged();
+ cloud_.NotifyOnComponentTreeChanged();
EXPECT_EQ(1, GetResponseCount());
const char kExpected[] = R"({
'commandsFingerprint': '1',
@@ -832,9 +832,9 @@
EXPECT_PRED2(IsEqualJson, "{}",
HandleRequest("/privet/v3/checkForUpdates", kInput));
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnStateChanged();
+ cloud_.NotifyOnComponentTreeChanged();
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnCommandDefsChanged();
+ cloud_.NotifyOnTraitDefsChanged();
EXPECT_EQ(1, GetResponseCount());
const char kExpected[] = R"({
'commandsFingerprint': '1',
@@ -953,7 +953,7 @@
EXPECT_PRED2(IsEqualJson, "{}",
HandleRequest("/privet/v3/checkForUpdates", kInput));
EXPECT_EQ(0, GetResponseCount());
- cloud_.NotifyOnCommandDefsChanged();
+ cloud_.NotifyOnTraitDefsChanged();
EXPECT_EQ(1, GetResponseCount());
const char kExpected[] = R"({
'commandsFingerprint': '1',
diff --git a/src/privet/privet_manager.cc b/src/privet/privet_manager.cc
index e3485c0..a308eec 100644
--- a/src/privet/privet_manager.cc
+++ b/src/privet/privet_manager.cc
@@ -18,6 +18,7 @@
#include <weave/provider/network.h>
#include "src/bind_lambda.h"
+#include "src/component_manager.h"
#include "src/device_registration_info.h"
#include "src/http_constants.h"
#include "src/privet/auth_manager.h"
@@ -47,15 +48,14 @@
HttpServer* http_server,
Wifi* wifi,
DeviceRegistrationInfo* device,
- CommandManager* command_manager,
- StateManager* state_manager) {
+ ComponentManager* component_manager) {
disable_security_ = device->GetSettings().disable_security;
device_ = DeviceDelegate::CreateDefault(
task_runner_, http_server->GetHttpPort(), http_server->GetHttpsPort(),
http_server->GetRequestTimeout());
- cloud_ = CloudDelegate::CreateDefault(task_runner_, device, command_manager,
- state_manager);
+ cloud_ = CloudDelegate::CreateDefault(task_runner_, device,
+ component_manager);
cloud_observer_.Add(cloud_.get());
auth_.reset(new AuthManager(device->GetSettings().secret,
diff --git a/src/privet/privet_manager.h b/src/privet/privet_manager.h
index 95dbbb8..1342584 100644
--- a/src/privet/privet_manager.h
+++ b/src/privet/privet_manager.h
@@ -27,11 +27,10 @@
namespace weave {
-class CommandManager;
+class ComponentManager;
class DeviceRegistrationInfo;
class DnsServiceDiscovery;
class Network;
-class StateManager;
namespace privet {
@@ -52,8 +51,7 @@
provider::HttpServer* http_server,
provider::Wifi* wifi,
DeviceRegistrationInfo* device,
- CommandManager* command_manager,
- StateManager* state_manager);
+ ComponentManager* component_manager);
std::string GetCurrentlyConnectedSsid() const;
diff --git a/src/states/error_codes.cc b/src/states/error_codes.cc
deleted file mode 100644
index 4b12a45..0000000
--- a/src/states/error_codes.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/states/error_codes.h"
-
-namespace weave {
-namespace errors {
-namespace state {
-
-const char kDomain[] = "buffet_state";
-
-const char kPackageNameMissing[] = "package_name_missing";
-const char kPropertyNameMissing[] = "property_name_missing";
-const char kPropertyNotDefined[] = "property_not_defined";
-const char kPropertyRedefinition[] = "property_redefinition";
-
-} // namespace state
-} // namespace errors
-} // namespace weave
diff --git a/src/states/error_codes.h b/src/states/error_codes.h
deleted file mode 100644
index 676a199..0000000
--- a/src/states/error_codes.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_STATES_ERROR_CODES_H_
-#define LIBWEAVE_SRC_STATES_ERROR_CODES_H_
-
-namespace weave {
-namespace errors {
-namespace state {
-
-// Error domain for state definitions.
-extern const char kDomain[];
-
-// State-specific error codes.
-extern const char kPackageNameMissing[];
-extern const char kPropertyNameMissing[];
-extern const char kPropertyNotDefined[];
-extern const char kPropertyRedefinition[];
-
-} // namespace state
-} // namespace errors
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_STATES_ERROR_CODES_H_
diff --git a/src/states/mock_state_change_queue_interface.h b/src/states/mock_state_change_queue_interface.h
deleted file mode 100644
index fc119cd..0000000
--- a/src/states/mock_state_change_queue_interface.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_STATES_MOCK_STATE_CHANGE_QUEUE_INTERFACE_H_
-#define LIBWEAVE_SRC_STATES_MOCK_STATE_CHANGE_QUEUE_INTERFACE_H_
-
-#include <vector>
-
-#include <gmock/gmock.h>
-
-#include "src/states/state_change_queue_interface.h"
-
-namespace weave {
-
-class MockStateChangeQueueInterface : public StateChangeQueueInterface {
- public:
- MOCK_CONST_METHOD0(IsEmpty, bool());
- MOCK_METHOD2(NotifyPropertiesUpdated,
- bool(base::Time timestamp,
- const base::DictionaryValue& changed_properties));
- MOCK_METHOD0(MockGetAndClearRecordedStateChanges,
- std::vector<StateChange>&());
- MOCK_CONST_METHOD0(GetLastStateChangeId, UpdateID());
- MOCK_METHOD1(MockAddOnStateUpdatedCallback,
- base::CallbackList<void(UpdateID)>::Subscription*(
- const base::Callback<void(UpdateID)>&));
- MOCK_METHOD1(NotifyStateUpdatedOnServer, void(UpdateID));
-
- private:
- std::vector<StateChange> GetAndClearRecordedStateChanges() override {
- return std::move(MockGetAndClearRecordedStateChanges());
- }
-
- Token AddOnStateUpdatedCallback(
- const base::Callback<void(UpdateID)>& callback) override {
- return Token{MockAddOnStateUpdatedCallback(callback)};
- }
-};
-
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_STATES_MOCK_STATE_CHANGE_QUEUE_INTERFACE_H_
diff --git a/src/states/state_change_queue.cc b/src/states/state_change_queue.cc
index b6c67cd..effe7f3 100644
--- a/src/states/state_change_queue.cc
+++ b/src/states/state_change_queue.cc
@@ -5,7 +5,6 @@
#include "src/states/state_change_queue.h"
#include <base/logging.h>
-#include <base/values.h>
namespace weave {
@@ -38,7 +37,6 @@
std::swap(element_old->second, element_new->second);
state_changes_.erase(element_old);
}
- ++last_change_id_;
return true;
}
@@ -52,15 +50,4 @@
return changes;
}
-StateChangeQueueInterface::Token StateChangeQueue::AddOnStateUpdatedCallback(
- const base::Callback<void(UpdateID)>& callback) {
- if (state_changes_.empty())
- callback.Run(last_change_id_);
- return Token{callbacks_.Add(callback).release()};
-}
-
-void StateChangeQueue::NotifyStateUpdatedOnServer(UpdateID update_id) {
- callbacks_.Notify(update_id);
-}
-
} // namespace weave
diff --git a/src/states/state_change_queue.h b/src/states/state_change_queue.h
index 857ec8b..3aef8d5 100644
--- a/src/states/state_change_queue.h
+++ b/src/states/state_change_queue.h
@@ -6,29 +6,36 @@
#define LIBWEAVE_SRC_STATES_STATE_CHANGE_QUEUE_H_
#include <map>
+#include <memory>
#include <vector>
#include <base/macros.h>
-
-#include "src/states/state_change_queue_interface.h"
+#include <base/time/time.h>
+#include <base/values.h>
namespace weave {
+// A simple notification record event to track device state changes.
+// The |timestamp| records the time of the state change.
+// |changed_properties| contains a property set with the new property values
+// which were updated at the time the event was recorded.
+struct StateChange {
+ StateChange(base::Time time,
+ std::unique_ptr<base::DictionaryValue> properties)
+ : timestamp{time}, changed_properties{std::move(properties)} {}
+ base::Time timestamp;
+ std::unique_ptr<base::DictionaryValue> changed_properties;
+};
+
// An object to record and retrieve device state change notification events.
-class StateChangeQueue : public StateChangeQueueInterface {
+class StateChangeQueue {
public:
explicit StateChangeQueue(size_t max_queue_size);
- // Overrides from StateChangeQueueInterface.
- bool IsEmpty() const override { return state_changes_.empty(); }
bool NotifyPropertiesUpdated(
base::Time timestamp,
- const base::DictionaryValue& changed_properties) override;
- std::vector<StateChange> GetAndClearRecordedStateChanges() override;
- UpdateID GetLastStateChangeId() const override { return last_change_id_; }
- Token AddOnStateUpdatedCallback(
- const base::Callback<void(UpdateID)>& callback) override;
- void NotifyStateUpdatedOnServer(UpdateID update_id) override;
+ const base::DictionaryValue& changed_properties);
+ std::vector<StateChange> GetAndClearRecordedStateChanges();
private:
// Maximum queue size. If it is full, the oldest state update records are
@@ -38,13 +45,6 @@
// Accumulated list of device state change notifications.
std::map<base::Time, std::unique_ptr<base::DictionaryValue>> state_changes_;
- // An ID of last state change update. Each NotifyPropertiesUpdated()
- // invocation increments this value by 1.
- UpdateID last_change_id_{0};
-
- // Callback list for state change queue even sinks.
- base::CallbackList<void(UpdateID)> callbacks_;
-
DISALLOW_COPY_AND_ASSIGN(StateChangeQueue);
};
diff --git a/src/states/state_change_queue_interface.h b/src/states/state_change_queue_interface.h
deleted file mode 100644
index 7ddce8c..0000000
--- a/src/states/state_change_queue_interface.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_STATES_STATE_CHANGE_QUEUE_INTERFACE_H_
-#define LIBWEAVE_SRC_STATES_STATE_CHANGE_QUEUE_INTERFACE_H_
-
-#include <vector>
-
-#include <base/callback_list.h>
-#include <base/time/time.h>
-
-namespace base {
-class DictionaryValue;
-} // namespace base
-
-namespace weave {
-
-// A simple notification record event to track device state changes.
-// The |timestamp| records the time of the state change.
-// |changed_properties| contains a property set with the new property values
-// which were updated at the time the event was recorded.
-struct StateChange {
- StateChange(base::Time time,
- std::unique_ptr<base::DictionaryValue> properties)
- : timestamp{time}, changed_properties{std::move(properties)} {}
- base::Time timestamp;
- std::unique_ptr<base::DictionaryValue> changed_properties;
-};
-
-// An abstract interface to StateChangeQueue to record and retrieve state
-// change notification events.
-class StateChangeQueueInterface {
- public:
- using UpdateID = uint64_t;
- using Token =
- std::unique_ptr<base::CallbackList<void(UpdateID)>::Subscription>;
-
- // Returns true if the state change notification queue is empty.
- virtual bool IsEmpty() const = 0;
-
- // Called by StateManager when device state properties are updated.
- virtual bool NotifyPropertiesUpdated(
- base::Time timestamp,
- const base::DictionaryValue& changed_properties) = 0;
-
- // Returns the recorded state changes since last time this method was called.
- virtual std::vector<StateChange> GetAndClearRecordedStateChanges() = 0;
-
- // Returns an ID of last state change update. Each NotifyPropertiesUpdated()
- // invocation increments this value by 1.
- virtual UpdateID GetLastStateChangeId() const = 0;
-
- // Subscribes for device state update notifications from cloud server.
- // The |callback| will be called every time a state patch with given ID is
- // successfully received and processed by GCD server.
- // Returns a subscription token. As soon as this token is destroyed, the
- // respective callback is removed from the callback list.
- virtual Token AddOnStateUpdatedCallback(
- const base::Callback<void(UpdateID)>& callback) WARN_UNUSED_RESULT = 0;
-
- virtual void NotifyStateUpdatedOnServer(UpdateID update_id) = 0;
-
- protected:
- // No one should attempt do destroy the queue through the interface.
- virtual ~StateChangeQueueInterface() {}
-};
-
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_STATES_STATE_CHANGE_QUEUE_INTERFACE_H_
diff --git a/src/states/state_change_queue_unittest.cc b/src/states/state_change_queue_unittest.cc
index b639d37..57cf490 100644
--- a/src/states/state_change_queue_unittest.cc
+++ b/src/states/state_change_queue_unittest.cc
@@ -23,8 +23,6 @@
};
TEST_F(StateChangeQueueTest, Empty) {
- EXPECT_TRUE(queue_->IsEmpty());
- EXPECT_EQ(0u, queue_->GetLastStateChangeId());
EXPECT_TRUE(queue_->GetAndClearRecordedStateChanges().empty());
}
@@ -32,14 +30,10 @@
auto timestamp = base::Time::Now();
ASSERT_TRUE(queue_->NotifyPropertiesUpdated(
timestamp, *CreateDictionaryValue("{'prop': {'name': 23}}")));
- EXPECT_FALSE(queue_->IsEmpty());
- EXPECT_EQ(1u, queue_->GetLastStateChangeId());
auto changes = queue_->GetAndClearRecordedStateChanges();
- EXPECT_EQ(1u, queue_->GetLastStateChangeId());
ASSERT_EQ(1u, changes.size());
EXPECT_EQ(timestamp, changes.front().timestamp);
EXPECT_JSON_EQ("{'prop':{'name': 23}}", *changes.front().changed_properties);
- EXPECT_TRUE(queue_->IsEmpty());
EXPECT_TRUE(queue_->GetAndClearRecordedStateChanges().empty());
}
@@ -54,15 +48,12 @@
ASSERT_TRUE(queue_->NotifyPropertiesUpdated(
timestamp2, *CreateDictionaryValue(state2)));
- EXPECT_EQ(2u, queue_->GetLastStateChangeId());
- EXPECT_FALSE(queue_->IsEmpty());
auto changes = queue_->GetAndClearRecordedStateChanges();
ASSERT_EQ(2u, changes.size());
EXPECT_EQ(timestamp1, changes[0].timestamp);
EXPECT_JSON_EQ(state1, *changes[0].changed_properties);
EXPECT_EQ(timestamp2, changes[1].timestamp);
EXPECT_JSON_EQ(state2, *changes[1].changed_properties);
- EXPECT_TRUE(queue_->IsEmpty());
EXPECT_TRUE(queue_->GetAndClearRecordedStateChanges().empty());
}
@@ -84,7 +75,6 @@
*CreateDictionaryValue("{'prop': {'name1': 4}}")));
auto changes = queue_->GetAndClearRecordedStateChanges();
- EXPECT_EQ(4u, queue_->GetLastStateChangeId());
ASSERT_EQ(2u, changes.size());
const std::string expected1 = "{'prop': {'name1': 3, 'name2': 2}}";
@@ -113,7 +103,6 @@
start_time + time_delta2,
*CreateDictionaryValue("{'prop': {'name10': 10, 'name11': 11}}")));
- EXPECT_EQ(3u, queue_->GetLastStateChangeId());
auto changes = queue_->GetAndClearRecordedStateChanges();
ASSERT_EQ(2u, changes.size());
@@ -128,26 +117,4 @@
EXPECT_JSON_EQ(expected2, *changes[1].changed_properties);
}
-TEST_F(StateChangeQueueTest, ImmediateStateChangeNotification) {
- // When queue is empty, registering a new callback will trigger it.
- bool called = false;
- auto callback = [&called](StateChangeQueueInterface::UpdateID id) {
- called = true;
- };
- queue_->AddOnStateUpdatedCallback(base::Bind(callback));
- EXPECT_TRUE(called);
-}
-
-TEST_F(StateChangeQueueTest, DelayedStateChangeNotification) {
- // When queue is not empty, registering a new callback will not trigger it.
- ASSERT_TRUE(queue_->NotifyPropertiesUpdated(
- base::Time::Now(),
- *CreateDictionaryValue("{'prop': {'name1': 1, 'name3': 2}}")));
-
- auto callback = [](StateChangeQueueInterface::UpdateID id) {
- FAIL() << "This should not be called";
- };
- queue_->AddOnStateUpdatedCallback(base::Bind(callback));
-}
-
} // namespace weave
diff --git a/src/states/state_manager.cc b/src/states/state_manager.cc
deleted file mode 100644
index 128f7d8..0000000
--- a/src/states/state_manager.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/states/state_manager.h"
-
-#include <base/logging.h>
-#include <base/values.h>
-
-#include "src/json_error_codes.h"
-#include "src/states/error_codes.h"
-#include "src/states/state_change_queue_interface.h"
-#include "src/string_utils.h"
-#include "src/utils.h"
-
-namespace weave {
-
-StateManager::StateManager(StateChangeQueueInterface* state_change_queue)
- : state_change_queue_(state_change_queue) {
- CHECK(state_change_queue_) << "State change queue not specified";
-}
-
-StateManager::~StateManager() {}
-
-void StateManager::AddChangedCallback(const base::Closure& callback) {
- on_changed_.push_back(callback);
- callback.Run(); // Force to read current state.
-}
-
-const base::DictionaryValue& StateManager::GetState() const {
- if (!cached_dict_valid_) {
- cached_dict_.Clear();
- for (const auto& pair : packages_) {
- cached_dict_.SetWithoutPathExpansion(
- pair.first, pair.second->GetValuesAsJson().DeepCopy());
- }
- cached_dict_valid_ = true;
- }
-
- return cached_dict_;
-}
-
-bool StateManager::SetProperty(const std::string& name,
- const base::Value& value,
- ErrorPtr* error) {
- bool result = SetPropertyValue(name, value, base::Time::Now(), error);
- for (const auto& cb : on_changed_)
- cb.Run();
- return result;
-}
-
-const base::Value* StateManager::GetProperty(const std::string& name) const {
- auto parts = SplitAtFirst(name, ".", true);
- const std::string& package_name = parts.first;
- const std::string& property_name = parts.second;
- if (package_name.empty() || property_name.empty())
- return nullptr;
-
- const StatePackage* package = FindPackage(package_name);
- if (!package)
- return nullptr;
-
- return package->GetPropertyValue(property_name, nullptr);
-}
-
-bool StateManager::SetPropertyValue(const std::string& full_property_name,
- const base::Value& value,
- const base::Time& timestamp,
- ErrorPtr* error) {
- auto parts = SplitAtFirst(full_property_name, ".", true);
- const std::string& package_name = parts.first;
- const std::string& property_name = parts.second;
- const bool split = (full_property_name.find(".") != std::string::npos);
-
- if (full_property_name.empty() || (split && property_name.empty())) {
- Error::AddTo(error, FROM_HERE, errors::state::kDomain,
- errors::state::kPropertyNameMissing,
- "Property name is missing");
- return false;
- }
- if (!split || package_name.empty()) {
- Error::AddTo(error, FROM_HERE, errors::state::kDomain,
- errors::state::kPackageNameMissing,
- "Package name is missing in the property name");
- return false;
- }
- StatePackage* package = FindPackage(package_name);
- if (package == nullptr) {
- Error::AddToPrintf(error, FROM_HERE, errors::state::kDomain,
- errors::state::kPropertyNotDefined,
- "Unknown state property package '%s'",
- package_name.c_str());
- return false;
- }
- if (!package->SetPropertyValue(property_name, value, error))
- return false;
-
- cached_dict_valid_ = false;
-
- base::DictionaryValue prop_set;
- prop_set.Set(full_property_name, value.DeepCopy());
- state_change_queue_->NotifyPropertiesUpdated(timestamp, prop_set);
- return true;
-}
-
-std::pair<StateChangeQueueInterface::UpdateID, std::vector<StateChange>>
-StateManager::GetAndClearRecordedStateChanges() {
- return std::make_pair(state_change_queue_->GetLastStateChangeId(),
- state_change_queue_->GetAndClearRecordedStateChanges());
-}
-
-void StateManager::NotifyStateUpdatedOnServer(
- StateChangeQueueInterface::UpdateID id) {
- state_change_queue_->NotifyStateUpdatedOnServer(id);
-}
-
-bool StateManager::LoadStateDefinition(const base::DictionaryValue& dict,
- ErrorPtr* error) {
- for (base::DictionaryValue::Iterator iter(dict); !iter.IsAtEnd();
- iter.Advance()) {
- std::string package_name = iter.key();
- if (package_name.empty()) {
- Error::AddTo(error, FROM_HERE, errors::kErrorDomain,
- errors::kInvalidPackageError, "State package name is empty");
- return false;
- }
- const base::DictionaryValue* package_dict = nullptr;
- if (!iter.value().GetAsDictionary(&package_dict)) {
- Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
- errors::json::kObjectExpected,
- "State package '%s' must be an object",
- package_name.c_str());
- return false;
- }
- StatePackage* package = FindOrCreatePackage(package_name);
- CHECK(package) << "Unable to create state package " << package_name;
- if (!package->AddSchemaFromJson(package_dict, error))
- return false;
- }
-
- return true;
-}
-
-bool StateManager::LoadStateDefinitionFromJson(const std::string& json,
- ErrorPtr* error) {
- std::unique_ptr<const base::DictionaryValue> dict = LoadJsonDict(json, error);
- if (!dict)
- return false;
- if (!LoadStateDefinition(*dict, error)) {
- Error::AddToPrintf(error, FROM_HERE, errors::kErrorDomain,
- errors::kSchemaError,
- "Failed to load state definition: '%s'", json.c_str());
- return false;
- }
- return true;
-}
-
-bool StateManager::SetProperties(const base::DictionaryValue& dict,
- ErrorPtr* error) {
- base::Time timestamp = base::Time::Now();
- bool all_success = true;
- for (base::DictionaryValue::Iterator iter(dict); !iter.IsAtEnd();
- iter.Advance()) {
- if (iter.key().empty()) {
- Error::AddTo(error, FROM_HERE, errors::kErrorDomain,
- errors::kInvalidPackageError, "State package name is empty");
- all_success = false;
- continue;
- }
-
- const base::DictionaryValue* package_dict = nullptr;
- if (!iter.value().GetAsDictionary(&package_dict)) {
- Error::AddToPrintf(error, FROM_HERE, errors::json::kDomain,
- errors::json::kObjectExpected,
- "State package '%s' must be an object",
- iter.key().c_str());
- all_success = false;
- continue;
- }
-
- for (base::DictionaryValue::Iterator it_prop(*package_dict);
- !it_prop.IsAtEnd(); it_prop.Advance()) {
- if (!SetPropertyValue(iter.key() + "." + it_prop.key(), it_prop.value(),
- timestamp, error)) {
- all_success = false;
- continue;
- }
- }
- }
- for (const auto& cb : on_changed_)
- cb.Run();
- return all_success;
-}
-
-bool StateManager::SetPropertiesFromJson(const std::string& json,
- ErrorPtr* error) {
- std::unique_ptr<const base::DictionaryValue> dict = LoadJsonDict(json, error);
- if (!dict)
- return false;
- if (!SetProperties(*dict, error)) {
- Error::AddToPrintf(error, FROM_HERE, errors::kErrorDomain,
- errors::kSchemaError, "Failed to load defaults: '%s'",
- json.c_str());
- return false;
- }
- return true;
-}
-
-StatePackage* StateManager::FindPackage(const std::string& package_name) {
- auto it = packages_.find(package_name);
- return (it != packages_.end()) ? it->second.get() : nullptr;
-}
-
-const StatePackage* StateManager::FindPackage(
- const std::string& package_name) const {
- auto it = packages_.find(package_name);
- return (it != packages_.end()) ? it->second.get() : nullptr;
-}
-
-StatePackage* StateManager::FindOrCreatePackage(
- const std::string& package_name) {
- StatePackage* package = FindPackage(package_name);
- if (package == nullptr) {
- std::unique_ptr<StatePackage> new_package{new StatePackage(package_name)};
- package =
- packages_.insert(std::make_pair(package_name, std::move(new_package)))
- .first->second.get();
- }
- return package;
-}
-
-} // namespace weave
diff --git a/src/states/state_manager.h b/src/states/state_manager.h
deleted file mode 100644
index bd1eb92..0000000
--- a/src/states/state_manager.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_STATES_STATE_MANAGER_H_
-#define LIBWEAVE_SRC_STATES_STATE_MANAGER_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/callback.h>
-#include <base/macros.h>
-#include <weave/error.h>
-
-#include "src/states/state_change_queue_interface.h"
-#include "src/states/state_package.h"
-
-namespace base {
-class DictionaryValue;
-class Time;
-} // namespace base
-
-namespace weave {
-
-// StateManager is the class that aggregates the device state fragments
-// provided by device daemons and makes the aggregate device state available
-// to the GCD cloud server and local clients.
-class StateManager final {
- public:
- explicit StateManager(StateChangeQueueInterface* state_change_queue);
- ~StateManager();
-
- void AddChangedCallback(const base::Closure& callback);
- bool LoadStateDefinition(const base::DictionaryValue& dict, ErrorPtr* error);
- bool LoadStateDefinitionFromJson(const std::string& json, ErrorPtr* error);
- bool SetProperties(const base::DictionaryValue& dict, ErrorPtr* error);
- bool SetPropertiesFromJson(const std::string& json, ErrorPtr* error);
- const base::Value* GetProperty(const std::string& name) const;
- bool SetProperty(const std::string& name,
- const base::Value& value,
- ErrorPtr* error);
- const base::DictionaryValue& GetState() const;
-
- // Returns the recorded state changes since last time this method has been
- // called.
- std::pair<StateChangeQueueInterface::UpdateID, std::vector<StateChange>>
- GetAndClearRecordedStateChanges();
-
- // Called to notify that the state patch with |id| has been successfully sent
- // to the server and processed.
- void NotifyStateUpdatedOnServer(StateChangeQueueInterface::UpdateID id);
-
- StateChangeQueueInterface* GetStateChangeQueue() const {
- return state_change_queue_;
- }
-
- const std::map<std::string, std::unique_ptr<StatePackage>>& packages() const {
- return packages_;
- }
-
- private:
- friend class BaseApiHandlerTest;
- friend class StateManagerTest;
-
- // Updates a single property value. |full_property_name| must be the full
- // name of the property to update in format "package.property".
- bool SetPropertyValue(const std::string& full_property_name,
- const base::Value& value,
- const base::Time& timestamp,
- ErrorPtr* error);
-
- // Finds a package by its name. Returns nullptr if not found.
- StatePackage* FindPackage(const std::string& package_name);
- const StatePackage* FindPackage(const std::string& package_name) const;
- // Finds a package by its name. If none exists, one will be created.
- StatePackage* FindOrCreatePackage(const std::string& package_name);
-
- StateChangeQueueInterface* state_change_queue_; // Owned by Manager.
- std::map<std::string, std::unique_ptr<StatePackage>> packages_;
-
- std::vector<base::Closure> on_changed_;
-
- mutable base::DictionaryValue cached_dict_;
- mutable bool cached_dict_valid_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(StateManager);
-};
-
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_STATES_STATE_MANAGER_H_
diff --git a/src/states/state_manager_unittest.cc b/src/states/state_manager_unittest.cc
deleted file mode 100644
index 918fb89..0000000
--- a/src/states/state_manager_unittest.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/states/state_manager.h"
-
-#include <cstdlib> // for abs().
-#include <vector>
-
-#include <base/bind.h>
-#include <base/values.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <weave/provider/test/mock_config_store.h>
-#include <weave/test/unittest_utils.h>
-
-#include "src/commands/schema_constants.h"
-#include "src/states/error_codes.h"
-#include "src/states/mock_state_change_queue_interface.h"
-
-namespace weave {
-
-using testing::_;
-using testing::Return;
-using testing::ReturnRef;
-using test::CreateDictionaryValue;
-
-namespace {
-
-const char kBaseDefinition[] = R"({
- "base": {
- "manufacturer":{"type":"string"},
- "serialNumber":{"type":"string"}
- },
- "device": {
- "state_property":{"type":"string"}
- }
-})";
-
-std::unique_ptr<base::DictionaryValue> GetTestSchema() {
- return CreateDictionaryValue(kBaseDefinition);
-}
-
-const char kBaseDefaults[] = R"({
- "base": {
- "manufacturer":"Test Factory",
- "serialNumber":"Test Model"
- }
-})";
-
-std::unique_ptr<base::DictionaryValue> GetTestValues() {
- return CreateDictionaryValue(kBaseDefaults);
-}
-
-MATCHER_P(IsState, str, "") {
- return arg.Equals(CreateDictionaryValue(str).get());
-}
-
-} // anonymous namespace
-
-class StateManagerTest : public ::testing::Test {
- public:
- void SetUp() override {
- // Initial expectations.
- EXPECT_CALL(mock_state_change_queue_, IsEmpty()).Times(0);
- EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(_, _))
- .WillRepeatedly(Return(true));
- EXPECT_CALL(mock_state_change_queue_, MockGetAndClearRecordedStateChanges())
- .Times(0);
- mgr_.reset(new StateManager(&mock_state_change_queue_));
-
- EXPECT_CALL(*this, OnStateChanged()).Times(2);
- mgr_->AddChangedCallback(
- base::Bind(&StateManagerTest::OnStateChanged, base::Unretained(this)));
-
- LoadStateDefinition(GetTestSchema().get(), nullptr);
- ASSERT_TRUE(mgr_->SetProperties(*GetTestValues().get(), nullptr));
- }
- void TearDown() override { mgr_.reset(); }
-
- void LoadStateDefinition(const base::DictionaryValue* json,
- ErrorPtr* error) {
- ASSERT_TRUE(mgr_->LoadStateDefinition(*json, error));
- }
-
- bool SetPropertyValue(const std::string& name,
- const base::Value& value,
- ErrorPtr* error) {
- return mgr_->SetPropertyValue(name, value, timestamp_, error);
- }
-
- MOCK_CONST_METHOD0(OnStateChanged, void());
-
- base::Time timestamp_{base::Time::Now()};
- std::unique_ptr<StateManager> mgr_;
- testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue_;
-};
-
-TEST(StateManager, Empty) {
- testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue;
- StateManager manager(&mock_state_change_queue);
-}
-
-TEST_F(StateManagerTest, Initialized) {
- auto expected = R"({
- 'base': {
- 'manufacturer': 'Test Factory',
- 'serialNumber': 'Test Model'
- },
- 'device': {}
- })";
- EXPECT_JSON_EQ(expected, mgr_->GetState());
-}
-
-TEST_F(StateManagerTest, LoadStateDefinition) {
- auto dict = CreateDictionaryValue(R"({
- 'power': {
- 'battery_level':'integer'
- }
- })");
- LoadStateDefinition(dict.get(), nullptr);
-
- auto expected = R"({
- 'base': {
- 'manufacturer': 'Test Factory',
- 'serialNumber': 'Test Model'
- },
- 'power': {},
- 'device': {}
- })";
- EXPECT_JSON_EQ(expected, mgr_->GetState());
-}
-
-TEST_F(StateManagerTest, Startup) {
- StateManager manager(&mock_state_change_queue_);
-
- auto state_definition = R"({
- "base": {
- "firmwareVersion": {"type":"string"},
- "localDiscoveryEnabled": {"type":"boolean"},
- "localAnonymousAccessMaxRole": {
- "type": "string",
- "enum": ["none", "viewer", "user"]
- },
- "localPairingEnabled": {"type":"boolean"}
- },
- "power": {"battery_level":{"type":"integer"}}
- })";
- ASSERT_TRUE(manager.LoadStateDefinitionFromJson(state_definition, nullptr));
-
- auto state_values = R"({
- "base": {
- "firmwareVersion": "unknown",
- "localDiscoveryEnabled": false,
- "localAnonymousAccessMaxRole": "none",
- "localPairingEnabled": false
- },
- "power": {"battery_level":44}
- })";
- ASSERT_TRUE(manager.SetPropertiesFromJson(state_values, nullptr));
-
- auto expected = R"({
- 'base': {
- 'firmwareVersion': 'unknown',
- 'localAnonymousAccessMaxRole': 'none',
- 'localDiscoveryEnabled': false,
- 'localPairingEnabled': false
- },
- 'power': {
- 'battery_level': 44
- }
- })";
- EXPECT_JSON_EQ(expected, manager.GetState());
-}
-
-TEST_F(StateManagerTest, SetPropertyValue) {
- const std::string state = "{'device': {'state_property': 'Test Value'}}";
- EXPECT_CALL(mock_state_change_queue_,
- NotifyPropertiesUpdated(timestamp_, IsState(state)))
- .WillOnce(Return(true));
- ASSERT_TRUE(SetPropertyValue("device.state_property",
- base::StringValue{"Test Value"}, nullptr));
- auto expected = R"({
- 'base': {
- 'manufacturer': 'Test Factory',
- 'serialNumber': 'Test Model'
- },
- 'device': {
- 'state_property': 'Test Value'
- }
- })";
- EXPECT_JSON_EQ(expected, mgr_->GetState());
-}
-
-TEST_F(StateManagerTest, SetPropertyValue_Error_NoName) {
- ErrorPtr error;
- ASSERT_FALSE(SetPropertyValue("", base::FundamentalValue{0}, &error));
- EXPECT_EQ(errors::state::kDomain, error->GetDomain());
- EXPECT_EQ(errors::state::kPropertyNameMissing, error->GetCode());
-}
-
-TEST_F(StateManagerTest, SetPropertyValue_Error_NoPackage) {
- ErrorPtr error;
- ASSERT_FALSE(
- SetPropertyValue("state_property", base::FundamentalValue{0}, &error));
- EXPECT_EQ(errors::state::kDomain, error->GetDomain());
- EXPECT_EQ(errors::state::kPackageNameMissing, error->GetCode());
-}
-
-TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownPackage) {
- ErrorPtr error;
- ASSERT_FALSE(
- SetPropertyValue("power.level", base::FundamentalValue{0}, &error));
- EXPECT_EQ(errors::state::kDomain, error->GetDomain());
- EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
-}
-
-TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownProperty) {
- ASSERT_TRUE(
- SetPropertyValue("base.level", base::FundamentalValue{0}, nullptr));
-}
-
-TEST_F(StateManagerTest, GetAndClearRecordedStateChanges) {
- EXPECT_CALL(mock_state_change_queue_,
- NotifyPropertiesUpdated(timestamp_, _))
- .WillOnce(Return(true));
- ASSERT_TRUE(SetPropertyValue("device.state_property",
- base::StringValue{"Test Value"}, nullptr));
- std::vector<StateChange> expected_state;
- const std::string expected_val =
- "{'device': {'state_property': 'Test Value'}}";
- expected_state.emplace_back(
- timestamp_,
- CreateDictionaryValue(expected_val));
- EXPECT_CALL(mock_state_change_queue_, MockGetAndClearRecordedStateChanges())
- .WillOnce(ReturnRef(expected_state));
- EXPECT_CALL(mock_state_change_queue_, GetLastStateChangeId())
- .WillOnce(Return(0));
- auto changes = mgr_->GetAndClearRecordedStateChanges();
- ASSERT_EQ(1u, changes.second.size());
- EXPECT_EQ(timestamp_, changes.second.back().timestamp);
- EXPECT_JSON_EQ(expected_val, *changes.second.back().changed_properties);
-}
-
-TEST_F(StateManagerTest, SetProperties) {
- const std::string state = "{'base': {'manufacturer': 'No Name'}}";
- EXPECT_CALL(mock_state_change_queue_,
- NotifyPropertiesUpdated(_, IsState(state)))
- .WillOnce(Return(true));
-
- EXPECT_CALL(*this, OnStateChanged()).Times(1);
- ASSERT_TRUE(mgr_->SetProperties(
- *CreateDictionaryValue("{'base':{'manufacturer':'No Name'}}"), nullptr));
-
- auto expected = R"({
- 'base': {
- 'manufacturer': 'No Name',
- 'serialNumber': 'Test Model'
- },
- 'device': {}
- })";
- EXPECT_JSON_EQ(expected, mgr_->GetState());
-}
-
-TEST_F(StateManagerTest, GetProperty) {
- EXPECT_JSON_EQ("'Test Model'", *mgr_->GetProperty("base.serialNumber"));
- EXPECT_EQ(nullptr, mgr_->GetProperty("device.state_property"));
- EXPECT_EQ(nullptr, mgr_->GetProperty("device.unknown"));
- EXPECT_EQ(nullptr, mgr_->GetProperty("unknown.state_property"));
-}
-
-} // namespace weave
diff --git a/src/states/state_package.cc b/src/states/state_package.cc
deleted file mode 100644
index b0ea199..0000000
--- a/src/states/state_package.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/states/state_package.h"
-
-#include <base/logging.h>
-#include <base/values.h>
-
-#include "src/states/error_codes.h"
-
-namespace weave {
-
-StatePackage::StatePackage(const std::string& name) : name_(name) {}
-
-bool StatePackage::AddSchemaFromJson(const base::DictionaryValue* json,
- ErrorPtr* error) {
- // Scan first to make sure we have no property redefinitions.
- for (base::DictionaryValue::Iterator it(*json); !it.IsAtEnd(); it.Advance()) {
- if (types_.HasKey(it.key())) {
- Error::AddToPrintf(error, FROM_HERE, errors::state::kDomain,
- errors::state::kPropertyRedefinition,
- "State property '%s.%s' is already defined",
- name_.c_str(), it.key().c_str());
- return false;
- }
- }
-
- types_.MergeDictionary(json);
- return true;
-}
-
-bool StatePackage::AddValuesFromJson(const base::DictionaryValue* json,
- ErrorPtr* error) {
- for (base::DictionaryValue::Iterator it(*json); !it.IsAtEnd(); it.Advance()) {
- if (!SetPropertyValue(it.key(), it.value(), error))
- return false;
- }
- return true;
-}
-
-const base::DictionaryValue& StatePackage::GetValuesAsJson() const {
- return values_;
-}
-
-const base::Value* StatePackage::GetPropertyValue(
- const std::string& property_name,
- ErrorPtr* error) const {
- const base::Value* value = nullptr;
- if (!values_.Get(property_name, &value)) {
- Error::AddToPrintf(error, FROM_HERE, errors::state::kDomain,
- errors::state::kPropertyNotDefined,
- "State property '%s.%s' is not defined", name_.c_str(),
- property_name.c_str());
- return nullptr;
- }
-
- return value;
-}
-
-bool StatePackage::SetPropertyValue(const std::string& property_name,
- const base::Value& value,
- ErrorPtr* error) {
- values_.Set(property_name, value.DeepCopy());
- return true;
-}
-
-} // namespace weave
diff --git a/src/states/state_package.h b/src/states/state_package.h
deleted file mode 100644
index afc4c52..0000000
--- a/src/states/state_package.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIBWEAVE_SRC_STATES_STATE_PACKAGE_H_
-#define LIBWEAVE_SRC_STATES_STATE_PACKAGE_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-#include <base/values.h>
-#include <weave/error.h>
-
-namespace weave {
-
-// A package is a set of related state properties. GCD specification defines
-// a number of standard state properties in "base" package such as
-// "base.manufacturer", "base.model", "base.firmwareVersion" and so on.
-class StatePackage final {
- public:
- explicit StatePackage(const std::string& name);
-
- // Loads state property definitions from a JSON object and adds them
- // to the current package.
- bool AddSchemaFromJson(const base::DictionaryValue* json, ErrorPtr* error);
- // Loads a set of state property values from a JSON object and assigns them
- // to existing properties. A property must be defined prior to loading its
- // value. We use this when we load default values during buffet startup.
- bool AddValuesFromJson(const base::DictionaryValue* json, ErrorPtr* error);
-
- // Returns a set of state properties and their values as a JSON object.
- // After being aggregated across multiple packages, this becomes the device
- // state object passed to the GCD server or a local client in the format
- // described by GCD specification, e.g.:
- // {
- // "base": {
- // "manufacturer":"...",
- // "model":"..."
- // },
- // "printer": {
- // "message": "Printer low on cyan ink"
- // }
- // }
- const base::DictionaryValue& GetValuesAsJson() const;
-
- // Gets the value for a specific state property. |property_name| must not
- // include the package name as part of the property name.
- const base::Value* GetPropertyValue(const std::string& property_name,
- ErrorPtr* error) const;
- // Sets the value for a specific state property. |property_name| must not
- // include the package name as part of the property name.
- bool SetPropertyValue(const std::string& property_name,
- const base::Value& value,
- ErrorPtr* error);
-
- // Returns the name of the this package.
- const std::string& GetName() const { return name_; }
-
- const base::DictionaryValue& types() const { return types_; }
-
- private:
- std::string name_;
- base::DictionaryValue types_;
- base::DictionaryValue values_;
-
- friend class StatePackageTestHelper;
- DISALLOW_COPY_AND_ASSIGN(StatePackage);
-};
-
-} // namespace weave
-
-#endif // LIBWEAVE_SRC_STATES_STATE_PACKAGE_H_
diff --git a/src/states/state_package_unittest.cc b/src/states/state_package_unittest.cc
deleted file mode 100644
index d09625a..0000000
--- a/src/states/state_package_unittest.cc
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2015 The Weave Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/states/state_package.h"
-
-#include <memory>
-#include <string>
-
-#include <base/values.h>
-#include <gtest/gtest.h>
-#include <weave/test/unittest_utils.h>
-
-#include "src/commands/schema_constants.h"
-#include "src/states/error_codes.h"
-
-namespace weave {
-
-using test::CreateDictionaryValue;
-
-class StatePackageTestHelper {
- public:
- // Returns the state property definitions (types/constraints/etc).
- static const base::DictionaryValue& GetTypes(const StatePackage& package) {
- return package.types_;
- }
- // Returns the all state property values in this package.
- static const base::DictionaryValue& GetValues(const StatePackage& package) {
- return package.values_;
- }
-};
-
-namespace {
-std::unique_ptr<base::DictionaryValue> GetTestSchema() {
- return CreateDictionaryValue(R"({
- 'color': {
- 'type': 'string'
- },
- 'direction': {
- 'additionalProperties': false,
- 'properties': {
- 'altitude': {
- 'maximum': 90.0,
- 'type': 'number'
- },
- 'azimuth': {
- 'type': 'number'
- }
- },
- 'type': 'object',
- 'required': [ 'azimuth' ]
- },
- 'iso': {
- 'enum': [50, 100, 200, 400],
- 'type': 'integer'
- },
- 'light': {
- 'type': 'boolean'
- }
- })");
-}
-
-std::unique_ptr<base::DictionaryValue> GetTestValues() {
- return CreateDictionaryValue(R"({
- 'light': true,
- 'color': 'white',
- 'direction': {'azimuth':57.2957795, 'altitude':89.9},
- 'iso': 200
- })");
-}
-
-inline const base::DictionaryValue& GetTypes(const StatePackage& package) {
- return StatePackageTestHelper::GetTypes(package);
-}
-// Returns the all state property values in this package.
-inline const base::DictionaryValue& GetValues(const StatePackage& package) {
- return StatePackageTestHelper::GetValues(package);
-}
-
-} // anonymous namespace
-
-class StatePackageTest : public ::testing::Test {
- public:
- void SetUp() override {
- package_.reset(new StatePackage("test"));
- ASSERT_TRUE(package_->AddSchemaFromJson(GetTestSchema().get(), nullptr));
- ASSERT_TRUE(package_->AddValuesFromJson(GetTestValues().get(), nullptr));
- }
- void TearDown() override { package_.reset(); }
- std::unique_ptr<StatePackage> package_;
-};
-
-TEST(StatePackage, Empty) {
- StatePackage package("test");
- EXPECT_EQ("test", package.GetName());
- EXPECT_TRUE(GetTypes(package).empty());
- EXPECT_TRUE(GetValues(package).empty());
-}
-
-TEST(StatePackage, AddSchemaFromJson_OnEmpty) {
- StatePackage package("test");
- ASSERT_TRUE(package.AddSchemaFromJson(GetTestSchema().get(), nullptr));
- EXPECT_EQ(4u, GetTypes(package).size());
- EXPECT_EQ(0u, GetValues(package).size());
-
- auto expected = R"({
- 'color': {
- 'type': 'string'
- },
- 'direction': {
- 'additionalProperties': false,
- 'properties': {
- 'altitude': {
- 'maximum': 90.0,
- 'type': 'number'
- },
- 'azimuth': {
- 'type': 'number'
- }
- },
- 'type': 'object',
- 'required': [ 'azimuth' ]
- },
- 'iso': {
- 'enum': [50, 100, 200, 400],
- 'type': 'integer'
- },
- 'light': {
- 'type': 'boolean'
- }
- })";
- EXPECT_JSON_EQ(expected, GetTypes(package));
-
- EXPECT_JSON_EQ("{}", package.GetValuesAsJson());
-}
-
-TEST(StatePackage, AddValuesFromJson_OnEmpty) {
- StatePackage package("test");
- ASSERT_TRUE(package.AddSchemaFromJson(GetTestSchema().get(), nullptr));
- ASSERT_TRUE(package.AddValuesFromJson(GetTestValues().get(), nullptr));
- EXPECT_EQ(4u, GetValues(package).size());
- auto expected = R"({
- 'color': 'white',
- 'direction': {
- 'altitude': 89.9,
- 'azimuth': 57.2957795
- },
- 'iso': 200,
- 'light': true
- })";
- EXPECT_JSON_EQ(expected, package.GetValuesAsJson());
-}
-
-TEST_F(StatePackageTest, AddSchemaFromJson_AddMore) {
- auto dict = CreateDictionaryValue(R"({'brightness':{
- 'enum': ['low', 'medium', 'high'],
- 'type': 'string'
- }})");
- ASSERT_TRUE(package_->AddSchemaFromJson(dict.get(), nullptr));
- EXPECT_EQ(5u, GetTypes(*package_).size());
- EXPECT_EQ(4u, GetValues(*package_).size());
- auto expected = R"({
- 'brightness': {
- 'enum': ['low', 'medium', 'high'],
- 'type': 'string'
- },
- 'color': {
- 'type': 'string'
- },
- 'direction': {
- 'additionalProperties': false,
- 'properties': {
- 'altitude': {
- 'maximum': 90.0,
- 'type': 'number'
- },
- 'azimuth': {
- 'type': 'number'
- }
- },
- 'type': 'object',
- 'required': [ 'azimuth' ]
- },
- 'iso': {
- 'enum': [50, 100, 200, 400],
- 'type': 'integer'
- },
- 'light': {
- 'type': 'boolean'
- }
- })";
- EXPECT_JSON_EQ(expected, GetTypes(*package_));
-
- expected = R"({
- 'color': 'white',
- 'direction': {
- 'altitude': 89.9,
- 'azimuth': 57.2957795
- },
- 'iso': 200,
- 'light': true
- })";
- EXPECT_JSON_EQ(expected, package_->GetValuesAsJson());
-}
-
-TEST_F(StatePackageTest, AddValuesFromJson_AddMore) {
- auto dict = CreateDictionaryValue(R"({'brightness':{
- 'enum': ['low', 'medium', 'high'],
- 'type': 'string'
- }})");
- ASSERT_TRUE(package_->AddSchemaFromJson(dict.get(), nullptr));
- dict = CreateDictionaryValue("{'brightness':'medium'}");
- ASSERT_TRUE(package_->AddValuesFromJson(dict.get(), nullptr));
- EXPECT_EQ(5u, GetValues(*package_).size());
- auto expected = R"({
- 'brightness': 'medium',
- 'color': 'white',
- 'direction': {
- 'altitude': 89.9,
- 'azimuth': 57.2957795
- },
- 'iso': 200,
- 'light': true
- })";
- EXPECT_JSON_EQ(expected, package_->GetValuesAsJson());
-}
-
-TEST_F(StatePackageTest, AddSchemaFromJson_Error_Redefined) {
- auto dict = CreateDictionaryValue(R"({'color':
- {'type':'string', 'enum':['white', 'blue', 'red']}})");
- ErrorPtr error;
- EXPECT_FALSE(package_->AddSchemaFromJson(dict.get(), &error));
- EXPECT_EQ(errors::state::kDomain, error->GetDomain());
- EXPECT_EQ(errors::state::kPropertyRedefinition, error->GetCode());
-}
-
-TEST_F(StatePackageTest, AddValuesFromJson_Error_Undefined) {
- auto dict = CreateDictionaryValue("{'brightness':'medium'}");
- EXPECT_TRUE(package_->AddValuesFromJson(dict.get(), nullptr));
-}
-
-TEST_F(StatePackageTest, GetPropertyValue) {
- EXPECT_JSON_EQ("'white'", *package_->GetPropertyValue("color", nullptr));
- EXPECT_JSON_EQ("true", *package_->GetPropertyValue("light", nullptr));
- EXPECT_JSON_EQ("200", *package_->GetPropertyValue("iso", nullptr));
- EXPECT_JSON_EQ("{'altitude': 89.9, 'azimuth': 57.2957795}",
- *package_->GetPropertyValue("direction", nullptr));
-}
-
-TEST_F(StatePackageTest, GetPropertyValue_Unknown) {
- ErrorPtr error;
- EXPECT_EQ(nullptr, package_->GetPropertyValue("volume", &error));
- EXPECT_EQ(errors::state::kDomain, error->GetDomain());
- EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
-}
-
-TEST_F(StatePackageTest, SetPropertyValue_Simple) {
- EXPECT_TRUE(
- package_->SetPropertyValue("color", base::StringValue{"blue"}, nullptr));
- EXPECT_JSON_EQ("'blue'", *package_->GetPropertyValue("color", nullptr));
- EXPECT_TRUE(package_->SetPropertyValue("light", base::FundamentalValue{false},
- nullptr));
- bool light = false;
- ASSERT_TRUE(
- package_->GetPropertyValue("light", nullptr)->GetAsBoolean(&light));
- EXPECT_FALSE(light);
- EXPECT_TRUE(
- package_->SetPropertyValue("iso", base::FundamentalValue{400}, nullptr));
- EXPECT_JSON_EQ("400", *package_->GetPropertyValue("iso", nullptr));
-}
-
-TEST_F(StatePackageTest, SetPropertyValue_Object) {
- EXPECT_TRUE(package_->SetPropertyValue(
- "direction",
- *CreateDictionaryValue("{'altitude': 45.0, 'azimuth': 15.0}"), nullptr));
-
- auto expected = R"({
- 'color': 'white',
- 'direction': {
- 'altitude': 45.0,
- 'azimuth': 15.0
- },
- 'iso': 200,
- 'light': true
- })";
- EXPECT_JSON_EQ(expected, package_->GetValuesAsJson());
-}
-
-} // namespace weave