buffet: Add device state manager
Added StateManager class to buffet and all the internals to
load vendor-provided state definition fragments, apply state
property defaults, expose the state property values over D-Bus
to be updated by daemons (using Buffet.UpdateState method) and
sent the current device state to GCD server as part of device
draft provided during device registration.
BUG=chromium:415364
TEST=FEATURES=test emerge-link buffet
Change-Id: I78e470c98d906064dfbe925614613ee6a91ff3cf
Reviewed-on: https://chromium-review.googlesource.com/218743
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/states/state_manager_unittest.cc b/buffet/states/state_manager_unittest.cc
new file mode 100644
index 0000000..1ce130d
--- /dev/null
+++ b/buffet/states/state_manager_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium OS 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 <base/values.h>
+#include <gtest/gtest.h>
+
+#include "buffet/commands/schema_constants.h"
+#include "buffet/commands/unittest_utils.h"
+#include "buffet/states/error_codes.h"
+#include "buffet/states/state_manager.h"
+
+using buffet::unittests::CreateDictionaryValue;
+using buffet::unittests::ValueToString;
+
+namespace buffet {
+
+namespace {
+std::unique_ptr<base::DictionaryValue> GetTestSchema() {
+ return CreateDictionaryValue(R"({
+ 'base': {
+ 'manufacturer':'string',
+ 'serialNumber':'string'
+ },
+ 'terminator': {
+ 'target':'string'
+ }
+ })");
+}
+
+std::unique_ptr<base::DictionaryValue> GetTestValues() {
+ return CreateDictionaryValue(R"({
+ 'base': {
+ 'manufacturer':'Skynet',
+ 'serialNumber':'T1000'
+ }
+ })");
+}
+} // anonymous namespace
+
+class StateManagerTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ mgr_.reset(new StateManager);
+ LoadStateDefinition(GetTestSchema().get(), "default", nullptr);
+ ASSERT_TRUE(mgr_->LoadStateDefaults(*GetTestValues().get(), nullptr));
+ }
+ void TearDown() override {
+ mgr_.reset();
+ }
+
+ void LoadStateDefinition(const base::DictionaryValue* json,
+ const std::string& category,
+ chromeos::ErrorPtr* error) {
+ ASSERT_TRUE(mgr_->LoadStateDefinition(*json, category, error));
+ }
+
+ std::unique_ptr<StateManager> mgr_;
+};
+
+TEST(StateManager, Empty) {
+ StateManager manager;
+ EXPECT_TRUE(manager.GetCategories().empty());
+}
+
+TEST_F(StateManagerTest, Initialized) {
+ EXPECT_EQ(std::set<std::string>{"default"}, mgr_->GetCategories());
+ EXPECT_EQ("{'base':{'manufacturer':'Skynet','serialNumber':'T1000'},"
+ "'terminator':{'target':''}}",
+ ValueToString(mgr_->GetStateValuesAsJson(nullptr).get()));
+}
+
+TEST_F(StateManagerTest, LoadStateDefinition) {
+ auto dict = CreateDictionaryValue(R"({
+ 'power': {
+ 'battery_level':'integer'
+ }
+ })");
+ LoadStateDefinition(dict.get(), "powerd", nullptr);
+ EXPECT_EQ((std::set<std::string>{"default", "powerd"}),
+ mgr_->GetCategories());
+ EXPECT_EQ("{'base':{'manufacturer':'Skynet','serialNumber':'T1000'},"
+ "'power':{'battery_level':0},"
+ "'terminator':{'target':''}}",
+ ValueToString(mgr_->GetStateValuesAsJson(nullptr).get()));
+}
+
+TEST_F(StateManagerTest, SetPropertyValue) {
+ ASSERT_TRUE(mgr_->SetPropertyValue("terminator.target",
+ std::string{"John Connor"}, nullptr));
+ EXPECT_EQ("{'base':{'manufacturer':'Skynet','serialNumber':'T1000'},"
+ "'terminator':{'target':'John Connor'}}",
+ ValueToString(mgr_->GetStateValuesAsJson(nullptr).get()));
+}
+
+TEST_F(StateManagerTest, SetPropertyValue_Error_NoName) {
+ chromeos::ErrorPtr error;
+ ASSERT_FALSE(mgr_->SetPropertyValue("", int{0}, &error));
+ EXPECT_EQ(errors::state::kDomain, error->GetDomain());
+ EXPECT_EQ(errors::state::kPropertyNameMissing, error->GetCode());
+ EXPECT_EQ("Property name is missing", error->GetMessage());
+}
+
+TEST_F(StateManagerTest, SetPropertyValue_Error_NoPackage) {
+ chromeos::ErrorPtr error;
+ ASSERT_FALSE(mgr_->SetPropertyValue("target", int{0}, &error));
+ EXPECT_EQ(errors::state::kDomain, error->GetDomain());
+ EXPECT_EQ(errors::state::kPackageNameMissing, error->GetCode());
+ EXPECT_EQ("Package name is missing in the property name",
+ error->GetMessage());
+}
+
+TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownPackage) {
+ chromeos::ErrorPtr error;
+ ASSERT_FALSE(mgr_->SetPropertyValue("power.level", int{0}, &error));
+ EXPECT_EQ(errors::state::kDomain, error->GetDomain());
+ EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
+ EXPECT_EQ("Unknown state property package 'power'", error->GetMessage());
+}
+
+TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownProperty) {
+ chromeos::ErrorPtr error;
+ ASSERT_FALSE(mgr_->SetPropertyValue("base.level", int{0}, &error));
+ EXPECT_EQ(errors::state::kDomain, error->GetDomain());
+ EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
+ EXPECT_EQ("State property 'base.level' is not defined", error->GetMessage());
+}
+
+} // namespace buffet