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/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