buffet: Add ExportedObjectManager delegate
This makes it easy to export an object manager. We'll use this very
soon to implement the ObjectManager interface on the root Buffet
object.
BUG=chromium:359190
TEST=Unittests
Change-Id: I19d2da33b81557431c5787937c49a18e7d7bacb2
Reviewed-on: https://chromium-review.googlesource.com/196387
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Christopher Wiley <wiley@chromium.org>
Tested-by: Christopher Wiley <wiley@chromium.org>
diff --git a/buffet/exported_object_manager_unittest.cc b/buffet/exported_object_manager_unittest.cc
new file mode 100644
index 0000000..696b76f
--- /dev/null
+++ b/buffet/exported_object_manager_unittest.cc
@@ -0,0 +1,205 @@
+// 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 "buffet/exported_object_manager.h"
+
+#include <base/bind.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_exported_object.h>
+#include <dbus/object_manager.h>
+#include <dbus/object_path.h>
+#include <gtest/gtest.h>
+
+using ::testing::AnyNumber;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::_;
+
+namespace buffet {
+
+namespace dbus_utils {
+
+namespace {
+
+const dbus::ObjectPath kTestPath(std::string("/test/om_path"));
+const dbus::ObjectPath kClaimedTestPath(std::string("/test/claimed_path"));
+const std::string kClaimedInterface("claimed.interface");
+const std::string kTestPropertyName("PropertyName");
+const std::string kTestPropertyValue("PropertyValue");
+
+void WriteTestPropertyDict(dbus::MessageWriter* writer) {
+ dbus::MessageWriter all_properties(nullptr);
+ dbus::MessageWriter each_property(nullptr);
+ writer->OpenArray("{sv}", &all_properties);
+ all_properties.OpenDictEntry(&each_property);
+ each_property.AppendString(kTestPropertyName);
+ each_property.AppendVariantOfString(kTestPropertyValue);
+ all_properties.CloseContainer(&each_property);
+ writer->CloseContainer(&all_properties);
+}
+
+void ReadTestPropertyDict(dbus::MessageReader* reader) {
+ dbus::MessageReader all_properties(nullptr);
+ dbus::MessageReader each_property(nullptr);
+ ASSERT_TRUE(reader->PopArray(&all_properties));
+ ASSERT_TRUE(all_properties.PopDictEntry(&each_property));
+ std::string property_name;
+ std::string property_value;
+ ASSERT_TRUE(each_property.PopString(&property_name));
+ ASSERT_TRUE(each_property.PopVariantOfString(&property_value));
+ EXPECT_FALSE(each_property.HasMoreData());
+ EXPECT_FALSE(all_properties.HasMoreData());
+ EXPECT_EQ(property_name, kTestPropertyName);
+ EXPECT_EQ(property_value, kTestPropertyValue);
+}
+
+void VerifyInterfaceClaimSignal(dbus::Signal* signal) {
+ EXPECT_EQ(signal->GetInterface(),
+ std::string(dbus::kObjectManagerInterface));
+ EXPECT_EQ(signal->GetMember(),
+ std::string(dbus::kObjectManagerInterfacesAdded));
+ // org.freedesktop.DBus.ObjectManager.InterfacesAdded (
+ // OBJPATH object_path,
+ // DICT<STRING,DICT<STRING,VARIANT>> interfaces_and_properties);
+ dbus::MessageReader reader(signal);
+ dbus::MessageReader all_interfaces(nullptr);
+ dbus::MessageReader each_interface(nullptr);
+ dbus::ObjectPath path;
+ ASSERT_TRUE(reader.PopObjectPath(&path));
+ ASSERT_TRUE(reader.PopArray(&all_interfaces));
+ ASSERT_TRUE(all_interfaces.PopDictEntry(&each_interface));
+ std::string interface_name;
+ ASSERT_TRUE(each_interface.PopString(&interface_name));
+ ReadTestPropertyDict(&each_interface);
+ EXPECT_FALSE(each_interface.HasMoreData());
+ EXPECT_FALSE(all_interfaces.HasMoreData());
+ EXPECT_FALSE(reader.HasMoreData());
+ EXPECT_EQ(interface_name, kClaimedInterface);
+ EXPECT_EQ(path, kClaimedTestPath);
+}
+
+void VerifyInterfaceDropSignal(dbus::Signal* signal) {
+ EXPECT_EQ(signal->GetInterface(),
+ std::string(dbus::kObjectManagerInterface));
+ EXPECT_EQ(signal->GetMember(),
+ std::string(dbus::kObjectManagerInterfacesRemoved));
+ // org.freedesktop.DBus.ObjectManager.InterfacesRemoved (
+ // OBJPATH object_path, ARRAY<STRING> interfaces);
+ dbus::MessageReader reader(signal);
+ dbus::MessageReader each_interface(nullptr);
+ dbus::ObjectPath path;
+ ASSERT_TRUE(reader.PopObjectPath(&path));
+ ASSERT_TRUE(reader.PopArray(&each_interface));
+ std::string interface_name;
+ ASSERT_TRUE(each_interface.PopString(&interface_name));
+ EXPECT_FALSE(each_interface.HasMoreData());
+ EXPECT_FALSE(reader.HasMoreData());
+ EXPECT_EQ(interface_name, kClaimedInterface);
+ EXPECT_EQ(path, kClaimedTestPath);
+}
+
+} // namespace
+
+class ExportedObjectManagerTest: public ::testing::Test {
+ public:
+ virtual void SetUp() {
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ bus_ = new dbus::MockBus(options);
+ // By default, don't worry about threading assertions.
+ EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+ EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+ // Use a mock exported object.
+ mock_exported_object_ = new dbus::MockExportedObject(
+ bus_.get(), kTestPath);
+ EXPECT_CALL(*bus_, GetExportedObject(kTestPath))
+ .Times(1).WillOnce(Return(mock_exported_object_.get()));
+ om_.reset(new ExportedObjectManager(bus_.get(), kTestPath));
+ property_writer_ = base::Bind(&WriteTestPropertyDict);
+ response_storer_ = base::Bind(&ExportedObjectManagerTest::StoreResponse,
+ base::Unretained(this));
+ }
+
+ void StoreResponse(scoped_ptr<dbus::Response> method_response) {
+ last_response_.reset(method_response.release());
+ }
+
+ void CallHandleGetManagedObjects(
+ dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender sender) {
+ om_->HandleGetManagedObjects(method_call, response_storer_);
+ }
+
+ scoped_refptr<dbus::MockBus> bus_;
+ scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+ scoped_ptr<ExportedObjectManager> om_;
+ ExportedObjectManager::PropertyWriter property_writer_;
+ dbus::ExportedObject::ResponseSender response_storer_;
+ scoped_ptr<dbus::Response> last_response_;
+};
+
+TEST_F(ExportedObjectManagerTest, ClaimInterfaceSendsSignals) {
+ EXPECT_CALL(*mock_exported_object_, SendSignal(_))
+ .Times(1).WillOnce(Invoke(&VerifyInterfaceClaimSignal));
+ om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_);
+}
+
+TEST_F(ExportedObjectManagerTest, ReleaseInterfaceSendsSignals) {
+ InSequence dummy;
+ EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
+ EXPECT_CALL(*mock_exported_object_, SendSignal(_))
+ .Times(1).WillOnce(Invoke(&VerifyInterfaceDropSignal));
+ om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_);
+ om_->ReleaseInterface(kClaimedTestPath, kClaimedInterface);
+}
+
+TEST_F(ExportedObjectManagerTest, GetManagedObjectsResponseEmptyCorrectness) {
+ dbus::MethodCall method_call(dbus::kObjectManagerInterface,
+ dbus::kObjectManagerGetManagedObjects);
+ method_call.SetSerial(123);
+ CallHandleGetManagedObjects(&method_call, response_storer_);
+ dbus::MessageReader reader(last_response_.get());
+ dbus::MessageReader all_paths(nullptr);
+ ASSERT_TRUE(reader.PopArray(&all_paths));
+ EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedObjectManagerTest, GetManagedObjectsResponseCorrectness) {
+ // org.freedesktop.DBus.ObjectManager.GetManagedObjects (
+ // out DICT<OBJPATH,
+ // DICT<STRING,
+ // DICT<STRING,VARIANT>>> )
+ dbus::MethodCall method_call(dbus::kObjectManagerInterface,
+ dbus::kObjectManagerGetManagedObjects);
+ method_call.SetSerial(123);
+ EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
+ om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_);
+ CallHandleGetManagedObjects(&method_call, response_storer_);
+ dbus::MessageReader reader(last_response_.get());
+ dbus::MessageReader all_paths(nullptr);
+ dbus::MessageReader each_path(nullptr);
+ dbus::MessageReader all_interfaces(nullptr);
+ dbus::MessageReader each_interface(nullptr);
+ ASSERT_TRUE(reader.PopArray(&all_paths));
+ ASSERT_TRUE(all_paths.PopDictEntry(&each_path));
+ dbus::ObjectPath path;
+ ASSERT_TRUE(each_path.PopObjectPath(&path));
+ ASSERT_TRUE(each_path.PopArray(&all_interfaces));
+ ASSERT_TRUE(all_interfaces.PopDictEntry(&each_interface));
+ std::string interface_name;
+ ASSERT_TRUE(each_interface.PopString(&interface_name));
+ ReadTestPropertyDict(&each_interface);
+ EXPECT_FALSE(each_interface.HasMoreData());
+ EXPECT_FALSE(all_interfaces.HasMoreData());
+ EXPECT_FALSE(each_path.HasMoreData());
+ EXPECT_FALSE(all_paths.HasMoreData());
+ EXPECT_FALSE(reader.HasMoreData());
+ EXPECT_EQ(path, kClaimedTestPath);
+ EXPECT_EQ(interface_name, kClaimedInterface);
+}
+
+} // namespace dbus_utils
+
+} // namespace buffet