Add weave::State::SetStateProperty and weave::State::GetStateProperty

BUG:24267885
Change-Id: Ibbeae3b852fec7cebdd8e3c0de05921fc2036c68
Reviewed-on: https://weave-review.googlesource.com/1222
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
diff --git a/libweave/examples/ubuntu/main.cc b/libweave/examples/ubuntu/main.cc
index 43c13ec..ef5f4e6 100644
--- a/libweave/examples/ubuntu/main.cc
+++ b/libweave/examples/ubuntu/main.cc
@@ -54,8 +54,7 @@
                                            ++counter_);
       device_->GetState()->SetProperties(state, nullptr);
 
-      LOG(INFO) << "New state: "
-                << *device_->GetState()->GetStateValuesAsJson();
+      LOG(INFO) << "New state: " << *device_->GetState()->GetState();
 
       cmd->Done();
     } else {
diff --git a/libweave/include/weave/state.h b/libweave/include/weave/state.h
index f1f57e6..211838f 100644
--- a/libweave/include/weave/state.h
+++ b/libweave/include/weave/state.h
@@ -15,14 +15,23 @@
   // Sets callback which is called when stat is changed.
   virtual void AddOnChangedCallback(const base::Closure& callback) = 0;
 
-  // Updates a multiple property values.
+  // Returns value of the single property.
+  // |name| is full property name, including package name. e.g. "base.network".
+  virtual std::unique_ptr<base::Value> GetStateProperty(
+      const std::string& name) = 0;
+
+  // Sets value of the single property.
+  // |name| is full property name, including package name. e.g. "base.network".
+  virtual bool SetStateProperty(const std::string& name,
+                                const base::Value& value,
+                                ErrorPtr* error) = 0;
+
+  // Updates multiple property values.
   virtual bool SetProperties(const base::DictionaryValue& property_set,
                              ErrorPtr* error) = 0;
 
-  // Returns aggregated state properties across all registered packages as
-  // a JSON object that can be used to send the device state to the GCD server.
-  virtual std::unique_ptr<base::DictionaryValue> GetStateValuesAsJson()
-      const = 0;
+  // Returns aggregated state properties across all registered packages.
+  virtual std::unique_ptr<base::DictionaryValue> GetState() const = 0;
 
  protected:
   virtual ~State() = default;
diff --git a/libweave/src/base_api_handler_unittest.cc b/libweave/src/base_api_handler_unittest.cc
index 1dc843d..1f1fc75 100644
--- a/libweave/src/base_api_handler_unittest.cc
+++ b/libweave/src/base_api_handler_unittest.cc
@@ -132,7 +132,7 @@
       'network': {}
     }
   })";
-  EXPECT_JSON_EQ(expected, *state_manager_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *state_manager_->GetState());
 
   AddCommand(R"({
     'name' : 'base.updateBaseConfiguration',
@@ -154,7 +154,7 @@
       'network': {}
     }
   })";
-  EXPECT_JSON_EQ(expected, *state_manager_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *state_manager_->GetState());
 
   {
     Config::Transaction change{dev_reg_->GetMutableConfig()};
@@ -169,7 +169,7 @@
       'network': {}
     }
   })";
-  EXPECT_JSON_EQ(expected, *state_manager_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *state_manager_->GetState());
 }
 
 TEST_F(BaseApiHandlerTest, UpdateDeviceInfo) {
diff --git a/libweave/src/device_registration_info.cc b/libweave/src/device_registration_info.cc
index 610871f..f93c652 100644
--- a/libweave/src/device_registration_info.cc
+++ b/libweave/src/device_registration_info.cc
@@ -485,8 +485,7 @@
   if (!commands)
     return nullptr;
 
-  std::unique_ptr<base::DictionaryValue> state =
-      state_manager_->GetStateValuesAsJson();
+  std::unique_ptr<base::DictionaryValue> state = state_manager_->GetState();
   CHECK(state);
 
   std::unique_ptr<base::DictionaryValue> resource{new base::DictionaryValue};
diff --git a/libweave/src/privet/cloud_delegate.cc b/libweave/src/privet/cloud_delegate.cc
index 2a60de0..f6a1558 100644
--- a/libweave/src/privet/cloud_delegate.cc
+++ b/libweave/src/privet/cloud_delegate.cc
@@ -254,7 +254,7 @@
 
   void OnStateChanged() {
     state_.Clear();
-    auto state = state_manager_->GetStateValuesAsJson();
+    auto state = state_manager_->GetState();
     CHECK(state);
     state_.MergeDictionary(state.get());
     NotifyOnStateChanged();
diff --git a/libweave/src/states/state_manager.cc b/libweave/src/states/state_manager.cc
index a04b3e9..1f17307 100644
--- a/libweave/src/states/state_manager.cc
+++ b/libweave/src/states/state_manager.cc
@@ -75,8 +75,7 @@
     cb.Run();
 }
 
-std::unique_ptr<base::DictionaryValue> StateManager::GetStateValuesAsJson()
-    const {
+std::unique_ptr<base::DictionaryValue> StateManager::GetState() const {
   std::unique_ptr<base::DictionaryValue> dict{new base::DictionaryValue};
   for (const auto& pair : packages_) {
     auto pkg_value = pair.second->GetValuesAsJson();
@@ -103,6 +102,27 @@
   return all_success;
 }
 
+bool StateManager::SetStateProperty(const std::string& name,
+                                    const base::Value& value,
+                                    ErrorPtr* error) {
+  return SetPropertyValue(name, value, base::Time::Now(), error);
+}
+
+std::unique_ptr<base::Value> StateManager::GetStateProperty(
+    const std::string& name) {
+  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;
+
+  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,
diff --git a/libweave/src/states/state_manager.h b/libweave/src/states/state_manager.h
index 88e28c0..bfa43e7 100644
--- a/libweave/src/states/state_manager.h
+++ b/libweave/src/states/state_manager.h
@@ -43,7 +43,12 @@
   void AddOnChangedCallback(const base::Closure& callback) override;
   bool SetProperties(const base::DictionaryValue& property_set,
                      ErrorPtr* error) override;
-  std::unique_ptr<base::DictionaryValue> GetStateValuesAsJson() const override;
+  std::unique_ptr<base::Value> GetStateProperty(
+      const std::string& name) override;
+  bool SetStateProperty(const std::string& name,
+                        const base::Value& value,
+                        ErrorPtr* error) override;
+  std::unique_ptr<base::DictionaryValue> GetState() const override;
 
   // Initializes the state manager and load device state fragments.
   // Called by Buffet daemon at startup.
diff --git a/libweave/src/states/state_manager_unittest.cc b/libweave/src/states/state_manager_unittest.cc
index 8d07e65..d02b57f 100644
--- a/libweave/src/states/state_manager_unittest.cc
+++ b/libweave/src/states/state_manager_unittest.cc
@@ -109,7 +109,7 @@
       'state_property': ''
     }
   })";
-  EXPECT_JSON_EQ(expected, *mgr_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *mgr_->GetState());
 }
 
 TEST_F(StateManagerTest, LoadStateDefinition) {
@@ -134,7 +134,7 @@
       'state_property': ''
     }
   })";
-  EXPECT_JSON_EQ(expected, *mgr_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *mgr_->GetState());
 }
 
 TEST_F(StateManagerTest, Startup) {
@@ -163,7 +163,7 @@
       'battery_level': 44
     }
   })";
-  EXPECT_JSON_EQ(expected, *manager.GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *manager.GetState());
 }
 
 TEST_F(StateManagerTest, SetPropertyValue) {
@@ -184,7 +184,7 @@
       'state_property': 'Test Value'
     }
   })";
-  EXPECT_JSON_EQ(expected, *mgr_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *mgr_->GetState());
 }
 
 TEST_F(StateManagerTest, SetPropertyValue_Error_NoName) {
@@ -259,7 +259,14 @@
       'state_property': ''
     }
   })";
-  EXPECT_JSON_EQ(expected, *mgr_->GetStateValuesAsJson());
+  EXPECT_JSON_EQ(expected, *mgr_->GetState());
+}
+
+TEST_F(StateManagerTest, GetProperty) {
+  EXPECT_JSON_EQ("'Test Model'", *mgr_->GetStateProperty("base.serialNumber"));
+  EXPECT_JSON_EQ("''", *mgr_->GetStateProperty("device.state_property"));
+  EXPECT_EQ(nullptr, mgr_->GetStateProperty("device.unknown"));
+  EXPECT_EQ(nullptr, mgr_->GetStateProperty("unknown.state_property"));
 }
 
 }  // namespace weave