buffet: Add property update signals to ExportedPropertSet BUG=chromium:356368 TEST=unit tests pass, added more Change-Id: I4c4beabce9bf6d3daf444066b2ce26cf13d50d10 Reviewed-on: https://chromium-review.googlesource.com/192725 Tested-by: Christopher Wiley <wiley@chromium.org> Reviewed-by: Alex Vakulenko <avakulenko@chromium.org> Commit-Queue: Christopher Wiley <wiley@chromium.org>
diff --git a/buffet/exported_property_set.cc b/buffet/exported_property_set.cc index fe1ef65..caf0c31 100644 --- a/buffet/exported_property_set.cc +++ b/buffet/exported_property_set.cc
@@ -138,7 +138,34 @@ const std::string& interface, const std::string& name, const ExportedPropertyBase* property) { - // TODO(wiley): Send a signal from the exported object here. + dbus::Signal signal(dbus::kPropertiesInterface, dbus::kPropertiesChanged); + WriteSignalForPropertyUpdate(interface, name, property, &signal); + // This sends the signal asyncronously. However, the raw message inside + // the signal object is ref-counted, so we're fine to allocate the Signal + // object on our local stack. + exported_object_->SendSignal(&signal); +} + +void ExportedPropertySet::WriteSignalForPropertyUpdate( + const std::string& interface, + const std::string& name, + const ExportedPropertyBase* property, + dbus::Signal* signal) const { + dbus::MessageWriter writer(signal); + dbus::MessageWriter array_writer(nullptr); + dbus::MessageWriter dict_writer(nullptr); + writer.AppendString(interface); + writer.OpenArray("{sv}", &array_writer); + array_writer.OpenDictEntry(&dict_writer); + dict_writer.AppendString(name); + property->AppendValueToWriter(&dict_writer); + array_writer.CloseContainer(&dict_writer); + writer.CloseContainer(&array_writer); + // The interface specification tells us to include this list of properties + // which have changed, but for whom no value is conveyed. Currently, we + // don't do anything interesting here. + std::vector<std::string> invalidated_properties; + writer.AppendArrayOfStrings(invalidated_properties); } template <typename T> @@ -259,7 +286,8 @@ } template <typename T> -void ExportedProperty<T>::AppendValueToWriter(dbus::MessageWriter* writer) { +void ExportedProperty<T>::AppendValueToWriter( + dbus::MessageWriter* writer) const { AppendPropertyToWriter(writer, value_); }
diff --git a/buffet/exported_property_set.h b/buffet/exported_property_set.h index 7ed9d9b..84dbe2a 100644 --- a/buffet/exported_property_set.h +++ b/buffet/exported_property_set.h
@@ -89,7 +89,7 @@ // needed to write out properties to Get and GetAll methods implemented // by the ExportedPropertySet since it doesn't actually know the type // of each property. - virtual void AppendValueToWriter(dbus::MessageWriter* writer) = 0; + virtual void AppendValueToWriter(dbus::MessageWriter* writer) const = 0; }; class ExportedPropertySet { @@ -123,6 +123,11 @@ const std::string& name, const ExportedPropertyBase* property); + void WriteSignalForPropertyUpdate(const std::string& interface, + const std::string& name, + const ExportedPropertyBase* property, + dbus::Signal* signal) const; + dbus::ExportedObject* exported_object_; // weak; owned by the Bus object. // This is a map from interface name -> property name -> pointer to property. std::map<std::string, @@ -154,7 +159,7 @@ virtual void SetUpdateCallback(const OnUpdateCallback& cb) override; // Implementation provided by specialization. - virtual void AppendValueToWriter(dbus::MessageWriter* writer) override; + virtual void AppendValueToWriter(dbus::MessageWriter* writer) const override; private: OnUpdateCallback on_update_;
diff --git a/buffet/exported_property_set_unittest.cc b/buffet/exported_property_set_unittest.cc index 257614e..0bd3c3d 100644 --- a/buffet/exported_property_set_unittest.cc +++ b/buffet/exported_property_set_unittest.cc
@@ -104,6 +104,13 @@ HandleSet(method_call, response_sender); } + void CallWriteSignalForPropertyUpdate(const std::string& interface, + const std::string& name, + const ExportedPropertyBase* property, + dbus::Signal* signal) { + WriteSignalForPropertyUpdate(interface, name, property, signal); + } + MOCK_METHOD3(PropertyUpdated, void(const std::string&, const std::string&, const ExportedPropertyBase*)); @@ -470,6 +477,35 @@ dynamic_cast<dbus::ErrorResponse*>(last_response_.get()) != nullptr); } +TEST_F(ExportedPropertySetTest, SignalsAreParsable) { + EXPECT_CALL(p_, PropertyUpdated(kTestInterface1, kUint8PropName, + &p_.uint8_prop_)).Times(1); + p_.uint8_prop_.SetValue(57); + dbus::Signal signal(dbus::kPropertiesInterface, dbus::kPropertiesChanged); + p_.CallWriteSignalForPropertyUpdate(kTestInterface1, kUint8PropName, + &p_.uint8_prop_, &signal); + std::string interface_name; + std::string property_name; + uint8 value; + dbus::MessageReader reader(&signal); + dbus::MessageReader array_reader(nullptr); + dbus::MessageReader dict_reader(nullptr); + ASSERT_TRUE(reader.PopString(&interface_name)); + ASSERT_TRUE(reader.PopArray(&array_reader)); + ASSERT_TRUE(array_reader.PopDictEntry(&dict_reader)); + ASSERT_TRUE(dict_reader.PopString(&property_name)); + ASSERT_TRUE(dict_reader.PopVariantOfByte(&value)); + ASSERT_FALSE(dict_reader.HasMoreData()); + ASSERT_FALSE(array_reader.HasMoreData()); + // Read the (empty) list of invalidated property names. + std::vector<std::string> invalidated_properties; + ASSERT_TRUE(reader.PopArrayOfStrings(&invalidated_properties)); + ASSERT_FALSE(reader.HasMoreData()); + ASSERT_EQ(value, 57); + ASSERT_EQ(property_name, std::string(kUint8PropName)); + ASSERT_EQ(interface_name, std::string(kTestInterface1)); +} + } // namespace dbus_utils } // namespace buffet