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