| // 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 <brillo/dbus/exported_object_manager.h> |
| |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <brillo/dbus/dbus_object_test_helpers.h> |
| #include <brillo/dbus/utils.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 brillo { |
| |
| 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(VariantDictionary* dict) { |
| dict->insert(std::make_pair(kTestPropertyName, Any(kTestPropertyValue))); |
| } |
| |
| 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: |
| void SetUp() override { |
| 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())); |
| EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _)) |
| .Times(AnyNumber()); |
| om_.reset(new ExportedObjectManager(bus_.get(), kTestPath)); |
| property_writer_ = base::Bind(&WriteTestPropertyDict); |
| om_->RegisterAsync(AsyncEventSequencer::GetDefaultCompletionAction()); |
| } |
| |
| void TearDown() override { |
| EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1); |
| om_.reset(); |
| bus_ = nullptr; |
| } |
| |
| std::unique_ptr<dbus::Response> CallHandleGetManagedObjects() { |
| dbus::MethodCall method_call(dbus::kObjectManagerInterface, |
| dbus::kObjectManagerGetManagedObjects); |
| method_call.SetSerial(1234); |
| return brillo::dbus_utils::testing::CallMethod(om_->dbus_object_, |
| &method_call); |
| } |
| |
| scoped_refptr<dbus::MockBus> bus_; |
| scoped_refptr<dbus::MockExportedObject> mock_exported_object_; |
| std::unique_ptr<ExportedObjectManager> om_; |
| ExportedPropertySet::PropertyWriter property_writer_; |
| }; |
| |
| 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) { |
| auto response = CallHandleGetManagedObjects(); |
| dbus::MessageReader reader(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>>> ) |
| EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1); |
| om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_); |
| auto response = CallHandleGetManagedObjects(); |
| dbus::MessageReader reader(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 brillo |