| // Copyright 2018 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 "bluetooth/dispatcher/impersonation_object_manager_interface.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/message_loop/message_loop.h> |
| #include <base/run_loop.h> |
| #include <dbus/mock_bus.h> |
| #include <dbus/mock_exported_object.h> |
| #include <dbus/mock_object_manager.h> |
| #include <dbus/mock_object_proxy.h> |
| #include <brillo/dbus/exported_property_set.h> |
| #include <brillo/dbus/mock_dbus_object.h> |
| #include <brillo/dbus/mock_exported_object_manager.h> |
| #include <dbus/property.h> |
| #include <gtest/gtest.h> |
| |
| #include "bluetooth/dispatcher/client_manager.h" |
| #include "bluetooth/dispatcher/mock_dbus_connection_factory.h" |
| #include "bluetooth/dispatcher/test_helper.h" |
| |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::Mock; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| |
| namespace bluetooth { |
| |
| namespace { |
| |
| constexpr char kTestInterfaceName1[] = "org.example.Interface1"; |
| constexpr char kTestInterfaceName2[] = "org.example.Interface2"; |
| constexpr char kTestObjectPath1[] = "/org/example/Object1"; |
| constexpr char kTestObjectPath2[] = "/org/example/Object2"; |
| constexpr char kTestObjectManagerPath[] = "/"; |
| constexpr char kTestServiceName1[] = "org.example.Service1"; |
| constexpr char kTestServiceName2[] = "org.example.Service2"; |
| constexpr char kTestMethodName1[] = "Method1"; |
| constexpr char kTestMethodName2[] = "Method2"; |
| |
| constexpr char kStringPropertyName[] = "SomeString"; |
| constexpr char kIntPropertyName[] = "SomeInt"; |
| constexpr char kBoolPropertyName[] = "SomeBool"; |
| constexpr char kMergeStringPropertyName[] = "SomeStringForMerging"; |
| |
| constexpr char kTestMethodCallString[] = "The Method Call"; |
| constexpr char kTestResponseString[] = "The Response"; |
| |
| constexpr char kTestSender[] = ":1.1"; |
| |
| constexpr int kTestSerial = 10; |
| |
| constexpr int kTestIntPropertyValue = 7; |
| constexpr char kTestStringPropertyValue[] = "some property value"; |
| constexpr bool kTestBoolPropertyValue = true; |
| |
| } // namespace |
| |
| class TestInterfaceHandler : public InterfaceHandler { |
| public: |
| TestInterfaceHandler() { |
| property_factory_map_[kStringPropertyName] = |
| std::make_unique<PropertyFactory<std::string>>(); |
| property_factory_map_[kIntPropertyName] = |
| std::make_unique<PropertyFactory<int>>(); |
| property_factory_map_[kBoolPropertyName] = |
| std::make_unique<PropertyFactory<bool>>(); |
| property_factory_map_[kMergeStringPropertyName] = |
| std::make_unique<PropertyFactory<std::string>>( |
| MergingRule::CONCATENATION); |
| |
| method_forwardings_[kTestMethodName1] = ForwardingRule::FORWARD_DEFAULT; |
| method_forwardings_[kTestMethodName2] = ForwardingRule::FORWARD_ALL; |
| } |
| |
| explicit TestInterfaceHandler(ObjectExportRule object_export_rule) |
| : TestInterfaceHandler() { |
| object_export_rule_ = object_export_rule; |
| } |
| |
| const PropertyFactoryMap& GetPropertyFactoryMap() const override { |
| return property_factory_map_; |
| } |
| |
| const std::map<std::string, ForwardingRule>& GetMethodForwardings() |
| const override { |
| return method_forwardings_; |
| } |
| |
| ObjectExportRule GetObjectExportRule() const override { |
| return object_export_rule_; |
| } |
| |
| private: |
| InterfaceHandler::PropertyFactoryMap property_factory_map_; |
| std::map<std::string, ForwardingRule> method_forwardings_; |
| ObjectExportRule object_export_rule_ = ObjectExportRule::ANY_SERVICE; |
| }; |
| |
| class ImpersonationObjectManagerInterfaceTest : public ::testing::Test { |
| public: |
| void SetUp() override { |
| bus_ = new dbus::MockBus(dbus::Bus::Options()); |
| auto dbus_connection_factory = |
| std::make_unique<MockDBusConnectionFactory>(); |
| dbus_connection_factory_ = dbus_connection_factory.get(); |
| client_manager_ = std::make_unique<ClientManager>( |
| bus_, std::move(dbus_connection_factory)); |
| EXPECT_CALL(*bus_, GetDBusTaskRunner()) |
| .WillRepeatedly(Return(message_loop_.task_runner().get())); |
| EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber()); |
| EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber()); |
| EXPECT_CALL(*bus_, Connect()).WillRepeatedly(Return(false)); |
| EXPECT_CALL(*bus_, HasDBusThread()).WillRepeatedly(Return(false)); |
| |
| dbus::ObjectPath object_manager_path(kTestObjectManagerPath); |
| |
| object_manager_object_proxy1_ = new dbus::MockObjectProxy( |
| bus_.get(), kTestServiceName1, object_manager_path); |
| EXPECT_CALL(*bus_, GetObjectProxy(kTestServiceName1, object_manager_path)) |
| .WillOnce(Return(object_manager_object_proxy1_.get())); |
| object_manager_object_proxy2_ = new dbus::MockObjectProxy( |
| bus_.get(), kTestServiceName2, object_manager_path); |
| EXPECT_CALL(*bus_, GetObjectProxy(kTestServiceName2, object_manager_path)) |
| .WillOnce(Return(object_manager_object_proxy2_.get())); |
| |
| object_manager1_ = new dbus::MockObjectManager( |
| bus_.get(), kTestServiceName1, object_manager_path); |
| object_manager2_ = new dbus::MockObjectManager( |
| bus_.get(), kTestServiceName2, object_manager_path); |
| // Force MessageLoop to run pending tasks as effect of instantiating |
| // MockObjectManager. Needed to avoid memory leaks because pending tasks |
| // are unowned pointers that will only self destruct after being run. |
| base::RunLoop().RunUntilIdle(); |
| auto exported_object_manager = |
| std::make_unique<brillo::dbus_utils::MockExportedObjectManager>( |
| bus_, object_manager_path); |
| exported_object_manager_ = exported_object_manager.get(); |
| EXPECT_CALL(*exported_object_manager_, RegisterAsync(_)).Times(1); |
| exported_object_manager_wrapper_ = |
| std::make_unique<ExportedObjectManagerWrapper>( |
| bus_, std::move(exported_object_manager)); |
| object_proxy_ = new dbus::MockObjectProxy( |
| bus_.get(), kTestServiceName1, dbus::ObjectPath(kTestObjectPath1)); |
| } |
| |
| void StubHandlePropertiesSet( |
| dbus::MethodCall* method_call, |
| int timeout_ms, |
| dbus::ObjectProxy::ResponseCallback callback, |
| dbus::ObjectProxy::ErrorCallback error_callback) { |
| StubHandleMethod(dbus::kPropertiesInterface, dbus::kPropertiesSet, |
| kTestMethodCallString, kTestResponseString, |
| /* error_name */ "", /* error_message */ "", method_call, |
| timeout_ms, callback, error_callback); |
| } |
| |
| void StubHandleTestMethod1(dbus::MethodCall* method_call, |
| int timeout_ms, |
| dbus::ObjectProxy::ResponseCallback callback, |
| dbus::ObjectProxy::ErrorCallback error_callback) { |
| StubHandleMethod(kTestInterfaceName1, kTestMethodName1, |
| kTestMethodCallString, kTestResponseString, |
| /* error_name */ "", /* error_message */ "", method_call, |
| timeout_ms, callback, error_callback); |
| } |
| |
| void StubHandleTestMethod2(dbus::MethodCall* method_call, |
| int timeout_ms, |
| dbus::ObjectProxy::ResponseCallback callback, |
| dbus::ObjectProxy::ErrorCallback error_callback) { |
| StubHandleMethod(kTestInterfaceName1, kTestMethodName2, |
| kTestMethodCallString, kTestResponseString, |
| /* error_name */ "", /* error_message */ "", method_call, |
| timeout_ms, callback, error_callback); |
| } |
| |
| protected: |
| // Expects that |exported_object| exports the standard methods: |
| // Get/Set/GetAll/PropertiesChanged. |
| // Optionally the Set handler will be assigned if |set_method_handler| is |
| // provided. |
| void ExpectExportPropertiesMethods( |
| dbus::MockExportedObject* exported_object, |
| dbus::ExportedObject::MethodCallCallback* set_method_handler = nullptr) { |
| EXPECT_CALL(*exported_object, |
| ExportMethodAndBlock(dbus::kPropertiesInterface, |
| dbus::kPropertiesGet, _)) |
| .WillOnce(Return(true)); |
| |
| EXPECT_CALL(*exported_object, |
| ExportMethodAndBlock(dbus::kPropertiesInterface, |
| dbus::kPropertiesGetAll, _)) |
| .WillOnce(Return(true)); |
| |
| if (set_method_handler == nullptr) |
| set_method_handler = &dummy_method_handler_; |
| EXPECT_CALL(*exported_object, |
| ExportMethodAndBlock(dbus::kPropertiesInterface, |
| dbus::kPropertiesSet, _)) |
| .WillOnce(DoAll(SaveArg<2>(set_method_handler), Return(true))); |
| } |
| |
| void TestMethodForwarding( |
| const std::string& interface_name, |
| const std::string& method_name, |
| const dbus::ObjectPath object_path, |
| scoped_refptr<dbus::MockBus> forwarding_bus, |
| dbus::ExportedObject::MethodCallCallback* tested_method_handler, |
| void (ImpersonationObjectManagerInterfaceTest::*stub_method_handler)( |
| dbus::MethodCall*, |
| int, |
| dbus::ObjectProxy::ResponseCallback, |
| dbus::ObjectProxy::ErrorCallback)) { |
| scoped_refptr<dbus::MockObjectProxy> object_proxy1 = |
| new dbus::MockObjectProxy(forwarding_bus.get(), kTestServiceName1, |
| object_path); |
| EXPECT_CALL(*forwarding_bus, GetObjectProxy(kTestServiceName1, object_path)) |
| .WillOnce(Return(object_proxy1.get())); |
| EXPECT_CALL(*forwarding_bus, Connect()).WillRepeatedly(Return(true)); |
| dbus::MethodCall method_call(interface_name, method_name); |
| method_call.SetPath(object_path); |
| method_call.SetSender(kTestSender); |
| method_call.SetSerial(kTestSerial); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(kTestMethodCallString); |
| EXPECT_CALL(*object_proxy1, CallMethodWithErrorCallback(_, _, _, _)) |
| .WillOnce(Invoke(this, stub_method_handler)); |
| std::unique_ptr<dbus::Response> saved_response; |
| tested_method_handler->Run( |
| &method_call, base::Bind( |
| [](std::unique_ptr<dbus::Response>* saved_response, |
| std::unique_ptr<dbus::Response> response) { |
| *saved_response = std::move(response); |
| }, |
| &saved_response)); |
| EXPECT_TRUE(saved_response.get() != nullptr); |
| std::string saved_response_string; |
| dbus::MessageReader reader(saved_response.get()); |
| reader.PopString(&saved_response_string); |
| // Check that the response is the forwarded response of the stub method |
| // handler. |
| EXPECT_EQ(kTestSender, saved_response->GetDestination()); |
| EXPECT_EQ(kTestSerial, saved_response->GetReplySerial()); |
| EXPECT_EQ(kTestResponseString, saved_response_string); |
| } |
| |
| void TestMethodForwardingMultiService( |
| const std::string& interface_name, |
| const std::string& method_name, |
| const dbus::ObjectPath object_path, |
| scoped_refptr<dbus::MockBus> forwarding_bus, |
| dbus::ExportedObject::MethodCallCallback* tested_method_handler, |
| void (ImpersonationObjectManagerInterfaceTest::*stub_method_handler)( |
| dbus::MethodCall*, |
| int, |
| dbus::ObjectProxy::ResponseCallback, |
| dbus::ObjectProxy::ErrorCallback)) { |
| scoped_refptr<dbus::MockObjectProxy> object_proxy1 = |
| new dbus::MockObjectProxy(forwarding_bus.get(), kTestServiceName1, |
| object_path); |
| scoped_refptr<dbus::MockObjectProxy> object_proxy2 = |
| new dbus::MockObjectProxy(forwarding_bus.get(), kTestServiceName2, |
| object_path); |
| EXPECT_CALL(*forwarding_bus, GetObjectProxy(kTestServiceName1, object_path)) |
| .WillOnce(Return(object_proxy1.get())); |
| EXPECT_CALL(*forwarding_bus, GetObjectProxy(kTestServiceName2, object_path)) |
| .WillOnce(Return(object_proxy2.get())); |
| EXPECT_CALL(*forwarding_bus, Connect()).WillRepeatedly(Return(true)); |
| dbus::MethodCall method_call(interface_name, method_name); |
| method_call.SetPath(object_path); |
| method_call.SetSender(kTestSender); |
| method_call.SetSerial(kTestSerial); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendString(kTestMethodCallString); |
| |
| // Check that the object proxies of both services receive method forwarding. |
| EXPECT_CALL(*object_proxy1, CallMethodWithErrorCallback(_, _, _, _)) |
| .WillOnce(Invoke(this, stub_method_handler)); |
| EXPECT_CALL(*object_proxy2, CallMethodWithErrorCallback(_, _, _, _)) |
| .WillOnce(Invoke(this, stub_method_handler)); |
| |
| std::unique_ptr<dbus::Response> saved_response; |
| tested_method_handler->Run( |
| &method_call, base::Bind( |
| [](std::unique_ptr<dbus::Response>* saved_response, |
| std::unique_ptr<dbus::Response> response) { |
| *saved_response = std::move(response); |
| }, |
| &saved_response)); |
| EXPECT_TRUE(saved_response.get() != nullptr); |
| std::string saved_response_string; |
| dbus::MessageReader reader(saved_response.get()); |
| reader.PopString(&saved_response_string); |
| // Check that the response is the forwarded response of the stub method |
| // handler. |
| EXPECT_EQ(kTestSender, saved_response->GetDestination()); |
| EXPECT_EQ(kTestSerial, saved_response->GetReplySerial()); |
| EXPECT_EQ(kTestResponseString, saved_response_string); |
| } |
| |
| // Expects that |exported_object| exports the test methods. |
| // Optionally the method handlers will be assigned if |method1_handler| or |
| // |method2_handler| is not null. |
| void ExpectExportTestMethods( |
| dbus::MockExportedObject* exported_object, |
| const std::string& interface_name, |
| dbus::ExportedObject::MethodCallCallback* method1_handler = nullptr, |
| dbus::ExportedObject::MethodCallCallback* method2_handler = nullptr) { |
| if (method1_handler == nullptr) |
| method1_handler = &dummy_method_handler_; |
| EXPECT_CALL(*exported_object, |
| ExportMethodAndBlock(interface_name, kTestMethodName1, _)) |
| .WillOnce(DoAll(SaveArg<2>(method1_handler), Return(true))); |
| |
| if (method2_handler == nullptr) |
| method2_handler = &dummy_method_handler_; |
| EXPECT_CALL(*exported_object, |
| ExportMethodAndBlock(interface_name, kTestMethodName2, _)) |
| .WillOnce(DoAll(SaveArg<2>(method2_handler), Return(true))); |
| } |
| |
| void ExpectUnexportTestMethods(dbus::MockExportedObject* exported_object, |
| const std::string& interface_name) { |
| EXPECT_CALL(*exported_object, |
| UnexportMethodAndBlock(interface_name, kTestMethodName1)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*exported_object, |
| UnexportMethodAndBlock(interface_name, kTestMethodName2)) |
| .WillOnce(Return(true)); |
| } |
| |
| template <typename T> |
| void SetPropertyValue(dbus::PropertyBase* property_base, T value) { |
| dbus::Property<T>* property = |
| static_cast<dbus::Property<T>*>(property_base); |
| property->SetAndBlock(value); |
| property->ReplaceValueWithSetValue(); |
| property->set_valid(true); |
| } |
| |
| template <typename T> |
| void ExpectExportedPropertyEquals( |
| T value, |
| brillo::dbus_utils::ExportedPropertyBase* exported_property_base) { |
| ASSERT_TRUE(exported_property_base != nullptr); |
| brillo::dbus_utils::ExportedProperty<T>* exported_property = |
| static_cast<brillo::dbus_utils::ExportedProperty<T>*>( |
| exported_property_base); |
| EXPECT_EQ(value, exported_property->value()); |
| } |
| |
| base::MessageLoop message_loop_; |
| scoped_refptr<dbus::MockBus> bus_; |
| scoped_refptr<dbus::MockObjectProxy> object_manager_object_proxy1_; |
| scoped_refptr<dbus::MockObjectProxy> object_manager_object_proxy2_; |
| scoped_refptr<dbus::MockObjectProxy> object_proxy_; |
| scoped_refptr<dbus::MockObjectManager> object_manager1_; |
| scoped_refptr<dbus::MockObjectManager> object_manager2_; |
| std::unique_ptr<ExportedObjectManagerWrapper> |
| exported_object_manager_wrapper_; |
| brillo::dbus_utils::MockExportedObjectManager* exported_object_manager_; |
| std::unique_ptr<ClientManager> client_manager_; |
| MockDBusConnectionFactory* dbus_connection_factory_; |
| dbus::ExportedObject::MethodCallCallback dummy_method_handler_; |
| }; |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, SingleInterface) { |
| dbus::ObjectPath object_path1(kTestObjectPath1); |
| dbus::ObjectPath object_path2(kTestObjectPath2); |
| |
| std::map<std::string, std::unique_ptr<ExportedObject>> exported_objects; |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| |
| EXPECT_CALL(*object_manager1_, RegisterInterface(kTestInterfaceName1, _)); |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object1 = |
| new dbus::MockExportedObject(bus_.get(), object_path1); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path1)) |
| .WillOnce(Return(exported_object1.get())); |
| scoped_refptr<dbus::MockExportedObject> exported_object2 = |
| new dbus::MockExportedObject(bus_.get(), object_path2); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path2)) |
| .WillOnce(Return(exported_object2.get())); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object1.get()); |
| // CreateProperties called for an object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| PropertySet* property_set1 = |
| static_cast<PropertySet*>(dbus_property_set1.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set1->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kBoolPropertyName)); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object2.get()); |
| // CreateProperties called for another object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path2, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set2( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path2, |
| kTestInterfaceName1)); |
| PropertySet* property_set2 = |
| static_cast<PropertySet*>(dbus_property_set2.get()); |
| |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set2->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kBoolPropertyName)); |
| |
| // ObjectAdded events |
| ExpectExportTestMethods(exported_object1.get(), kTestInterfaceName1); |
| ExpectExportTestMethods(exported_object2.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, kTestInterfaceName1, _)) |
| .Times(1); |
| impersonation_om_interface->ObjectAdded(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path2, kTestInterfaceName1, _)) |
| .Times(1); |
| impersonation_om_interface->ObjectAdded(kTestServiceName1, object_path2, |
| kTestInterfaceName1); |
| |
| // ObjectRemoved events |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, kTestInterfaceName1)) |
| .Times(1); |
| ExpectUnexportTestMethods(exported_object1.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object1, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path2, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path2, kTestInterfaceName1)) |
| .Times(1); |
| ExpectUnexportTestMethods(exported_object2.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object2, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path2, |
| kTestInterfaceName1); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, MultipleInterfaces) { |
| dbus::ObjectPath object_path(kTestObjectPath1); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object = |
| new dbus::MockExportedObject(bus_.get(), object_path); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path)) |
| .WillOnce(Return(exported_object.get())); |
| |
| std::map<std::string, std::unique_ptr<ExportedObject>> exported_objects; |
| auto impersonation_om_interface1 = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| auto impersonation_om_interface2 = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName2, |
| client_manager_.get()); |
| |
| EXPECT_CALL(*object_manager1_, RegisterInterface(kTestInterfaceName1, _)); |
| EXPECT_CALL(*object_manager1_, RegisterInterface(kTestInterfaceName2, _)); |
| impersonation_om_interface1->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| impersonation_om_interface2->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object.get()); |
| // CreateProperties called for an object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface1->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path, |
| kTestInterfaceName1)); |
| PropertySet* property_set1 = |
| static_cast<PropertySet*>(dbus_property_set1.get()); |
| |
| std::unique_ptr<dbus::PropertySet> dbus_property_set2( |
| impersonation_om_interface2->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path, |
| kTestInterfaceName2)); |
| PropertySet* property_set2 = |
| static_cast<PropertySet*>(dbus_property_set2.get()); |
| |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set1->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kBoolPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kBoolPropertyName)); |
| |
| // ObjectAdded events |
| ExpectExportTestMethods(exported_object.get(), kTestInterfaceName1); |
| ExpectExportTestMethods(exported_object.get(), kTestInterfaceName2); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path, kTestInterfaceName1, _)) |
| .Times(1); |
| impersonation_om_interface1->ObjectAdded(kTestServiceName1, object_path, |
| kTestInterfaceName1); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path, kTestInterfaceName2, _)) |
| .Times(1); |
| impersonation_om_interface2->ObjectAdded(kTestServiceName1, object_path, |
| kTestInterfaceName2); |
| |
| // ObjectRemoved events |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, kTestInterfaceName1)) |
| .Times(1); |
| // Exported object shouldn't be unregistered until the last interface is |
| // removed. |
| ExpectUnexportTestMethods(exported_object.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object, Unregister()).Times(0); |
| impersonation_om_interface1->ObjectRemoved(kTestServiceName1, object_path, |
| kTestInterfaceName1); |
| |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, kTestInterfaceName2)) |
| .Times(1); |
| // Now that the last interface has been removed, exported object should be |
| // unregistered. |
| ExpectUnexportTestMethods(exported_object.get(), kTestInterfaceName2); |
| EXPECT_CALL(*exported_object, Unregister()).Times(1); |
| impersonation_om_interface2->ObjectRemoved(kTestServiceName1, object_path, |
| kTestInterfaceName2); |
| |
| // Make sure that the Unregister actually happens on ObjectRemoved above and |
| // not due to its automatic deletion when this test case finishes. |
| Mock::VerifyAndClearExpectations(exported_object.get()); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, UnexpectedEvents) { |
| dbus::ObjectPath object_path(kTestObjectPath1); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object = |
| new dbus::MockExportedObject(bus_.get(), object_path); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path)) |
| .WillOnce(Return(exported_object.get())); |
| |
| std::map<std::string, std::unique_ptr<ExportedObject>> exported_objects; |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| |
| // ObjectAdded event happens before CreateProperties. This shouldn't happen. |
| // Make sure we only ignore the event and don't crash if this happens. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path, kTestInterfaceName1, _)) |
| .Times(0); |
| impersonation_om_interface->ObjectAdded(kTestServiceName1, object_path, |
| kTestInterfaceName1); |
| |
| // ObjectRemoved event happens before CreateProperties. This shouldn't happen. |
| // Make sure we only ignore the event and don't crash if this happens. |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, dbus::kPropertiesInterface)) |
| .Times(0); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, kTestInterfaceName1)) |
| .Times(0); |
| EXPECT_CALL(*exported_object, Unregister()).Times(0); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path, |
| kTestInterfaceName1); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object.get()); |
| // CreateProperties called for an object. |
| std::unique_ptr<dbus::PropertySet> dbus_property_set( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path, |
| kTestInterfaceName1)); |
| PropertySet* property_set = |
| static_cast<PropertySet*>(dbus_property_set.get()); |
| |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set->GetProperty(kBoolPropertyName)); |
| |
| // ObjectRemoved event happens before ObjectAdded. This shouldn't happen. |
| // Make sure we still handle this gracefully. |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path, kTestInterfaceName1)) |
| .Times(0); |
| EXPECT_CALL(*exported_object, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path, |
| kTestInterfaceName1); |
| |
| // Make sure that the Unregister actually happens on ObjectRemoved above and |
| // not due to its automatic deletion when this test case finishes. |
| Mock::VerifyAndClearExpectations(exported_object.get()); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, PropertiesHandler) { |
| dbus::ObjectPath object_path1(kTestObjectPath1); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object1 = |
| new dbus::MockExportedObject(bus_.get(), object_path1); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path1)) |
| .WillOnce(Return(exported_object1.get())); |
| |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| |
| EXPECT_CALL(*object_manager1_, RegisterInterface(kTestInterfaceName1, _)); |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| |
| dbus::ExportedObject::MethodCallCallback set_method_handler; |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object1.get(), &set_method_handler); |
| // CreateProperties called for another object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| PropertySet* property_set1 = |
| static_cast<PropertySet*>(dbus_property_set1.get()); |
| ASSERT_FALSE(set_method_handler.is_null()); |
| |
| // The properties should all be registered. |
| ASSERT_TRUE(property_set1->GetProperty(kStringPropertyName) != nullptr); |
| ASSERT_TRUE(property_set1->GetProperty(kIntPropertyName) != nullptr); |
| ASSERT_TRUE(property_set1->GetProperty(kBoolPropertyName) != nullptr); |
| |
| // Test that Properties.Set handler should forward the message to the source |
| // service and forward the response back to the caller. |
| TestMethodForwarding( |
| dbus::kPropertiesInterface, dbus::kPropertiesSet, object_path1, bus_, |
| &set_method_handler, |
| &ImpersonationObjectManagerInterfaceTest::StubHandlePropertiesSet); |
| |
| // ObjectRemoved events |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object1, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, MethodHandler) { |
| dbus::ObjectPath object_path1(kTestObjectPath1); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object1 = |
| new dbus::MockExportedObject(bus_.get(), object_path1); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path1)) |
| .WillOnce(Return(exported_object1.get())); |
| |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| |
| EXPECT_CALL(*object_manager1_, RegisterInterface(kTestInterfaceName1, _)); |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object1.get()); |
| // CreateProperties called for another object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| |
| // Method forwarding |
| dbus::ExportedObject::MethodCallCallback method1_handler; |
| dbus::ExportedObject::MethodCallCallback method2_handler; |
| ExpectExportTestMethods(exported_object1.get(), kTestInterfaceName1, |
| &method1_handler, &method2_handler); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, kTestInterfaceName1, _)) |
| .Times(1); |
| impersonation_om_interface->ObjectAdded(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| scoped_refptr<dbus::MockBus> client_bus = |
| new dbus::MockBus(dbus::Bus::Options()); |
| EXPECT_CALL(*dbus_connection_factory_, GetNewBus()) |
| .WillOnce(Return(client_bus)); |
| // Test that method call should be forwarding to the source service via |
| // |client_bus|. |
| TestMethodForwarding( |
| kTestInterfaceName1, kTestMethodName1, object_path1, client_bus, |
| &method1_handler, |
| &ImpersonationObjectManagerInterfaceTest::StubHandleTestMethod1); |
| TestMethodForwarding( |
| kTestInterfaceName1, kTestMethodName2, object_path1, client_bus, |
| &method2_handler, |
| &ImpersonationObjectManagerInterfaceTest::StubHandleTestMethod2); |
| |
| // ObjectRemoved events |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, kTestInterfaceName1)) |
| .Times(1); |
| ExpectUnexportTestMethods(exported_object1.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object1, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, MultiService) { |
| dbus::ObjectPath object_path1(kTestObjectPath1); |
| |
| std::map<std::string, std::unique_ptr<ExportedObject>> exported_objects; |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| impersonation_om_interface->RegisterToObjectManager(object_manager2_.get(), |
| kTestServiceName2); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object1 = |
| new dbus::MockExportedObject(bus_.get(), object_path1); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path1)) |
| .WillOnce(Return(exported_object1.get())); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object1.get()); |
| // CreateProperties called for an object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| PropertySet* property_set1 = |
| static_cast<PropertySet*>(dbus_property_set1.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set1->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kBoolPropertyName)); |
| EXPECT_CALL(*object_manager1_, |
| GetProperties(object_path1, kTestInterfaceName1)) |
| .WillRepeatedly(Return(property_set1)); |
| SetPropertyValue<std::string>(property_set1->GetProperty(kStringPropertyName), |
| kTestStringPropertyValue); |
| SetPropertyValue<int>(property_set1->GetProperty(kIntPropertyName), |
| kTestIntPropertyValue); |
| // Trigger property changed event and check that the exported properties are |
| // updated. |
| property_set1->NotifyPropertyChanged(kStringPropertyName); |
| property_set1->NotifyPropertyChanged(kIntPropertyName); |
| property_set1->NotifyPropertyChanged(kBoolPropertyName); |
| ExportedInterface* interface = |
| exported_object_manager_wrapper_->GetExportedInterface( |
| object_path1, kTestInterfaceName1); |
| ExpectExportedPropertyEquals<std::string>( |
| kTestStringPropertyValue, |
| interface->GetRegisteredExportedProperty(kStringPropertyName)); |
| ExpectExportedPropertyEquals<int>( |
| kTestIntPropertyValue, |
| interface->GetRegisteredExportedProperty(kIntPropertyName)); |
| EXPECT_EQ(nullptr, |
| interface->GetRegisteredExportedProperty(kBoolPropertyName)); |
| |
| // Another service also triggers CreateProperties for the same object. |
| // This shouldn't trigger another object export since it's already exported |
| // when the first service triggered CreateProperties. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(0); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set2( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName2, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| PropertySet* property_set2 = |
| static_cast<PropertySet*>(dbus_property_set2.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set2->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kBoolPropertyName)); |
| EXPECT_CALL(*object_manager2_, |
| GetProperties(object_path1, kTestInterfaceName1)) |
| .WillRepeatedly(Return(property_set2)); |
| SetPropertyValue<int>(property_set2->GetProperty(kIntPropertyName), |
| kTestIntPropertyValue + 1); |
| SetPropertyValue<bool>(property_set2->GetProperty(kBoolPropertyName), |
| kTestBoolPropertyValue); |
| |
| // ObjectAdded events |
| dbus::ExportedObject::MethodCallCallback method1_handler; |
| dbus::ExportedObject::MethodCallCallback method2_handler; |
| ExpectExportTestMethods(exported_object1.get(), kTestInterfaceName1, |
| &method1_handler, &method2_handler); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, kTestInterfaceName1, _)) |
| .Times(1); |
| impersonation_om_interface->ObjectAdded(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, kTestInterfaceName1, _)) |
| .Times(0); |
| impersonation_om_interface->ObjectAdded(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| |
| // Method forwarding |
| scoped_refptr<dbus::MockBus> client_bus = |
| new dbus::MockBus(dbus::Bus::Options()); |
| EXPECT_CALL(*client_bus, AssertOnDBusThread()).Times(AnyNumber()); |
| EXPECT_CALL(*dbus_connection_factory_, GetNewBus()) |
| .WillOnce(Return(client_bus)); |
| |
| // Method1's rule is FORWARD_DEFAULT, so test that only Service1 receives |
| // method forwarding. |
| TestMethodForwarding( |
| kTestInterfaceName1, kTestMethodName1, object_path1, client_bus, |
| &method1_handler, |
| &ImpersonationObjectManagerInterfaceTest::StubHandleTestMethod1); |
| // Method2's rule is FORWARD_ALL, so test that all services receive method |
| // forwarding. |
| TestMethodForwardingMultiService( |
| kTestInterfaceName1, kTestMethodName2, object_path1, client_bus, |
| &method2_handler, |
| &ImpersonationObjectManagerInterfaceTest::StubHandleTestMethod2); |
| |
| // ObjectRemoved events |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, kTestInterfaceName1)) |
| .Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| // Service1 removed the object, so now the properties of this object should |
| // be updated based on the properties of Service2. |
| EXPECT_EQ(nullptr, |
| interface->GetRegisteredExportedProperty(kStringPropertyName)); |
| ExpectExportedPropertyEquals<int>( |
| kTestIntPropertyValue + 1, |
| interface->GetRegisteredExportedProperty(kIntPropertyName)); |
| ExpectExportedPropertyEquals<bool>( |
| kTestBoolPropertyValue, |
| interface->GetRegisteredExportedProperty(kBoolPropertyName)); |
| |
| // The last service removes the object, the corrseponding exported object |
| // should be unregistered. |
| ExpectUnexportTestMethods(exported_object1.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object1, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, MultiServiceMerging) { |
| dbus::ObjectPath object_path1(kTestObjectPath1); |
| |
| std::map<std::string, std::unique_ptr<ExportedObject>> exported_objects; |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>(), kTestInterfaceName1, |
| client_manager_.get()); |
| |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| impersonation_om_interface->RegisterToObjectManager(object_manager2_.get(), |
| kTestServiceName2); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object1 = |
| new dbus::MockExportedObject(bus_.get(), object_path1); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path1)) |
| .WillOnce(Return(exported_object1.get())); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object1.get()); |
| // CreateProperties called for an object. |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| |
| PropertySet* property_set1 = |
| static_cast<PropertySet*>(dbus_property_set1.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set1->GetProperty(kMergeStringPropertyName)); |
| EXPECT_CALL(*object_manager1_, |
| GetProperties(object_path1, kTestInterfaceName1)) |
| .WillRepeatedly(Return(property_set1)); |
| SetPropertyValue<std::string>( |
| property_set1->GetProperty(kMergeStringPropertyName), "string1"); |
| // Trigger property changed event and check that the exported properties are |
| // updated. |
| property_set1->NotifyPropertyChanged(kMergeStringPropertyName); |
| ExportedInterface* interface = |
| exported_object_manager_wrapper_->GetExportedInterface( |
| object_path1, kTestInterfaceName1); |
| ExpectExportedPropertyEquals<std::string>( |
| "string1", |
| interface->GetRegisteredExportedProperty(kMergeStringPropertyName)); |
| |
| // Now the second service creates the same property. |
| std::unique_ptr<dbus::PropertySet> dbus_property_set2( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName2, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| PropertySet* property_set2 = |
| static_cast<PropertySet*>(dbus_property_set2.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set2->GetProperty(kMergeStringPropertyName)); |
| EXPECT_CALL(*object_manager2_, |
| GetProperties(object_path1, kTestInterfaceName1)) |
| .WillRepeatedly(Return(property_set2)); |
| SetPropertyValue<std::string>( |
| property_set2->GetProperty(kMergeStringPropertyName), "string2"); |
| |
| // Trigger property changed event and check that the exported properties are |
| // updated. |
| property_set2->NotifyPropertyChanged(kMergeStringPropertyName); |
| ExpectExportedPropertyEquals<std::string>( |
| "string1 string2", |
| interface->GetRegisteredExportedProperty(kMergeStringPropertyName)); |
| |
| // ObjectAdded events |
| dbus::ExportedObject::MethodCallCallback method1_handler; |
| dbus::ExportedObject::MethodCallCallback method2_handler; |
| ExpectExportTestMethods(exported_object1.get(), kTestInterfaceName1, |
| &method1_handler, &method2_handler); |
| impersonation_om_interface->ObjectAdded(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| impersonation_om_interface->ObjectAdded(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| // ObjectRemoved events |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| // Service1 removed the object, so now the property of this object should |
| // be updated based on the property of Service2. |
| ExpectExportedPropertyEquals<std::string>( |
| "string2", |
| interface->GetRegisteredExportedProperty(kMergeStringPropertyName)); |
| |
| // The last service removes the object, the corrseponding exported object |
| // should be unregistered and the exported property removed. |
| ExpectUnexportTestMethods(exported_object1.get(), kTestInterfaceName1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| EXPECT_EQ(nullptr, |
| interface->GetRegisteredExportedProperty(kMergeStringPropertyName)); |
| } |
| |
| TEST_F(ImpersonationObjectManagerInterfaceTest, |
| MultiServiceWithObjectExportRuleAllServices) { |
| dbus::ObjectPath object_path1(kTestObjectPath1); |
| |
| std::map<std::string, std::unique_ptr<ExportedObject>> exported_objects; |
| auto impersonation_om_interface = |
| std::make_unique<ImpersonationObjectManagerInterface>( |
| bus_, exported_object_manager_wrapper_.get(), |
| std::make_unique<TestInterfaceHandler>( |
| ObjectExportRule::ALL_SERVICES), |
| kTestInterfaceName1, client_manager_.get()); |
| |
| impersonation_om_interface->RegisterToObjectManager(object_manager1_.get(), |
| kTestServiceName1); |
| impersonation_om_interface->RegisterToObjectManager(object_manager2_.get(), |
| kTestServiceName2); |
| |
| scoped_refptr<dbus::MockExportedObject> exported_object1 = |
| new dbus::MockExportedObject(bus_.get(), object_path1); |
| EXPECT_CALL(*bus_, GetExportedObject(object_path1)) |
| .WillOnce(Return(exported_object1.get())); |
| |
| // D-Bus properties methods should be exported. |
| ExpectExportPropertiesMethods(exported_object1.get()); |
| // CreateProperties called for an object. |
| // This shouldn't trigger object export until the second service also exports |
| // the same object. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(0); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set1( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName1, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| PropertySet* property_set1 = |
| static_cast<PropertySet*>(dbus_property_set1.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set1->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set1->GetProperty(kBoolPropertyName)); |
| EXPECT_CALL(*object_manager1_, |
| GetProperties(object_path1, kTestInterfaceName1)) |
| .WillRepeatedly(Return(property_set1)); |
| SetPropertyValue<std::string>(property_set1->GetProperty(kStringPropertyName), |
| kTestStringPropertyValue); |
| SetPropertyValue<int>(property_set1->GetProperty(kIntPropertyName), |
| kTestIntPropertyValue); |
| // Trigger property changed events, they should be ignored. |
| property_set1->NotifyPropertyChanged(kStringPropertyName); |
| property_set1->NotifyPropertyChanged(kIntPropertyName); |
| property_set1->NotifyPropertyChanged(kBoolPropertyName); |
| // ObjectAdded event before the other service exports the object. This should |
| // be ignored. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, kTestInterfaceName1, _)) |
| .Times(0); |
| impersonation_om_interface->ObjectAdded(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| |
| // Another service also triggers CreateProperties for the same object. |
| // This should trigger an object export. |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, dbus::kPropertiesInterface, _)) |
| .Times(1); |
| std::unique_ptr<dbus::PropertySet> dbus_property_set2( |
| impersonation_om_interface->CreateProperties( |
| kTestServiceName2, object_proxy_.get(), object_path1, |
| kTestInterfaceName1)); |
| // The value of the properties should reflect those of Service1. |
| ExportedInterface* interface = |
| exported_object_manager_wrapper_->GetExportedInterface( |
| object_path1, kTestInterfaceName1); |
| ExpectExportedPropertyEquals<std::string>( |
| kTestStringPropertyValue, |
| interface->GetRegisteredExportedProperty(kStringPropertyName)); |
| ExpectExportedPropertyEquals<int>( |
| kTestIntPropertyValue, |
| interface->GetRegisteredExportedProperty(kIntPropertyName)); |
| EXPECT_EQ(nullptr, |
| interface->GetRegisteredExportedProperty(kBoolPropertyName)); |
| |
| PropertySet* property_set2 = |
| static_cast<PropertySet*>(dbus_property_set2.get()); |
| // The properties should all be registered. |
| ASSERT_NE(nullptr, property_set2->GetProperty(kStringPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kIntPropertyName)); |
| ASSERT_NE(nullptr, property_set2->GetProperty(kBoolPropertyName)); |
| EXPECT_CALL(*object_manager2_, |
| GetProperties(object_path1, kTestInterfaceName1)) |
| .WillRepeatedly(Return(property_set2)); |
| SetPropertyValue<int>(property_set2->GetProperty(kIntPropertyName), |
| kTestIntPropertyValue + 1); |
| SetPropertyValue<bool>(property_set2->GetProperty(kBoolPropertyName), |
| kTestBoolPropertyValue); |
| |
| // ObjectAdded event for Service2. |
| dbus::ExportedObject::MethodCallCallback method1_handler; |
| dbus::ExportedObject::MethodCallCallback method2_handler; |
| ExpectExportTestMethods(exported_object1.get(), kTestInterfaceName1, |
| &method1_handler, &method2_handler); |
| EXPECT_CALL(*exported_object_manager_, |
| ClaimInterface(object_path1, kTestInterfaceName1, _)) |
| .Times(1); |
| impersonation_om_interface->ObjectAdded(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| |
| // ObjectRemoved events |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, dbus::kPropertiesInterface)) |
| .Times(1); |
| EXPECT_CALL(*exported_object_manager_, |
| ReleaseInterface(object_path1, kTestInterfaceName1)) |
| .Times(1); |
| // Service1 removed the object, the corresponding exported object should be |
| // unregistered. |
| ExpectUnexportTestMethods(exported_object1.get(), kTestInterfaceName1); |
| EXPECT_CALL(*exported_object1, Unregister()).Times(1); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName1, object_path1, |
| kTestInterfaceName1); |
| EXPECT_EQ(nullptr, exported_object_manager_wrapper_->GetExportedInterface( |
| object_path1, kTestInterfaceName1)); |
| |
| // The last service removes the object, there should be no other object |
| // unregistration. |
| EXPECT_CALL(*exported_object1, Unregister()).Times(0); |
| impersonation_om_interface->ObjectRemoved(kTestServiceName2, object_path1, |
| kTestInterfaceName1); |
| } |
| |
| } // namespace bluetooth |