// Copyright (C) 2013-2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef _GLIBCXX_USE_NANOSLEEP #define _GLIBCXX_USE_NANOSLEEP #endif #include #define COMMONAPI_INTERNAL_COMPILATION #include #include #include #include #include #include #include #include #include static const std::string dbusServiceName = "CommonAPI.DBus.DBusObjectManagerStubTest"; static const std::string& dbusObjectManagerStubPath = "/commonapi/dbus/test/DBusObjectManagerStub"; static const std::string& managedDBusObjectPathPrefix = "/commonapi/dbus/test/DBusObjectManagerStub/ManagedObject"; class TestDBusStubAdapter: public CommonAPI::DBus::DBusStubAdapter { public: TestDBusStubAdapter(const std::string& dbusObjectPath, const std::shared_ptr& dbusConnection, const bool isManagingInterface) : DBusStubAdapter(CommonAPI::DBus::DBusAddress(dbusServiceName, dbusObjectPath, "commonapi.dbus.tests.TestDBusStubAdapter"), dbusConnection, isManagingInterface) { } void deactivateManagedInstances() { } virtual const char* getMethodsDBusIntrospectionXmlData() const { return ""; } virtual bool onInterfaceDBusMessage(const CommonAPI::DBus::DBusMessage& dbusMessage) { return false; } virtual bool onInterfaceDBusFreedesktopPropertiesMessage(const CommonAPI::DBus::DBusMessage& dbusMessage) { return false; } protected: TestDBusStubAdapter(const std::string& dbusObjectPath, const std::string& dbusInterfaceName, const std::shared_ptr& dbusConnection, const bool isManagingInterface) : DBusStubAdapter(CommonAPI::DBus::DBusAddress(dbusServiceName, dbusObjectPath, dbusInterfaceName), dbusConnection, isManagingInterface) { } }; class ManagerTestDBusStubAdapter: public TestDBusStubAdapter { public: ManagerTestDBusStubAdapter(const std::string& dbusObjectPath, const std::shared_ptr& dbusConnection) : TestDBusStubAdapter( dbusObjectPath, "commonapi.dbus.tests.ManagerTestDBusStubAdapter", dbusConnection, true) { } }; struct TestDBusObjectManagerSignalHandler: public CommonAPI::DBus::DBusConnection::DBusSignalHandler { size_t totalAddedCount; size_t totalRemovedCount; std::string lastAddedDBusObjectPath; std::string lastRemovedDBusObjectPath; std::condition_variable signalReceived; std::mutex lock; ~TestDBusObjectManagerSignalHandler() { dbusConnection_->removeSignalMemberHandler(dbusSignalHandlerAddedToken_); dbusConnection_->removeSignalMemberHandler(dbusSignalHandlerRemovedToken_); } virtual CommonAPI::SubscriptionStatus onSignalDBusMessage(const CommonAPI::DBus::DBusMessage& dbusMessage) { if (!dbusMessage.hasInterfaceName(CommonAPI::DBus::DBusObjectManagerStub::getInterfaceName())) { return CommonAPI::SubscriptionStatus::CANCEL; } if (!dbusMessage.hasMemberName("InterfacesAdded") && !dbusMessage.hasMemberName("InterfacesRemoved")) { return CommonAPI::SubscriptionStatus::CANCEL; } CommonAPI::DBus::DBusInputStream dbusInputStream(dbusMessage); std::lock_guard lockGuard(lock); if (dbusMessage.hasMemberName("InterfacesAdded")) { totalAddedCount++; dbusInputStream >> lastAddedDBusObjectPath; } else { totalRemovedCount++; dbusInputStream >> lastRemovedDBusObjectPath; } signalReceived.notify_all(); return CommonAPI::SubscriptionStatus::RETAIN; } static inline std::shared_ptr create( const std::string& dbusObjectPath, const std::shared_ptr< CommonAPI::DBus::DBusProxyConnection>& dbusConnection) { auto dbusSignalHandler = new TestDBusObjectManagerSignalHandler(dbusObjectPath, dbusConnection); dbusSignalHandler->init(); return std::shared_ptr(dbusSignalHandler); } private: TestDBusObjectManagerSignalHandler(const std::string& dbusObjectPath, const std::shared_ptr& dbusConnection) : totalAddedCount(0), totalRemovedCount(0), dbusObjectPath_(dbusObjectPath), dbusConnection_(dbusConnection) { } void init() { dbusSignalHandlerAddedToken_ = dbusConnection_->addSignalMemberHandler( dbusObjectPath_, CommonAPI::DBus::DBusObjectManagerStub::getInterfaceName(), "InterfacesAdded", "oa{sa{sv}}", this, false); dbusSignalHandlerRemovedToken_ = dbusConnection_->addSignalMemberHandler( dbusObjectPath_, CommonAPI::DBus::DBusObjectManagerStub::getInterfaceName(), "InterfacesRemoved", "oas", this, false); } std::string dbusObjectPath_; std::shared_ptr dbusConnection_; CommonAPI::DBus::DBusProxyConnection::DBusSignalHandlerToken dbusSignalHandlerAddedToken_; CommonAPI::DBus::DBusProxyConnection::DBusSignalHandlerToken dbusSignalHandlerRemovedToken_; }; class DBusObjectManagerStubTest: public ::testing::Test { protected: virtual void SetUp() { runtime = CommonAPI::Runtime::get(); proxyDBusConnection_ = CommonAPI::DBus::DBusConnection::getBus(CommonAPI::DBus::DBusType_t::SESSION); ASSERT_TRUE(proxyDBusConnection_->connect()); stubDBusConnection_ = serviceFactory->getDbusConnection(); ASSERT_TRUE(stubDBusConnection_->connect()); ASSERT_TRUE(bool(stubDBusConnection_->getDBusObjectManager())); ASSERT_TRUE(stubDBusConnection_->requestServiceNameAndBlock(dbusServiceName)); } virtual void TearDown() { stubDBusConnection_->releaseServiceName(dbusServiceName); stubDBusConnection_->disconnect(); stubDBusConnection_.reset(); proxyDBusConnection_->disconnect(); proxyDBusConnection_.reset(); } std::shared_ptr runtime; void getManagedObjects(const std::string& dbusObjectPath, CommonAPI::DBus::DBusObjectManagerStub::DBusObjectPathAndInterfacesDict& dbusObjectPathAndInterfacesDict) { auto dbusMessageCall = CommonAPI::DBus::DBusMessage::createMethodCall( dbusServiceName, dbusObjectPath, CommonAPI::DBus::DBusObjectManagerStub::getInterfaceName(), "GetManagedObjects"); CommonAPI::DBus::DBusError dbusError; auto dbusMessageReply = proxyDBusConnection_->sendDBusMessageWithReplyAndBlock(dbusMessageCall, dbusError); ASSERT_FALSE(dbusError)<< dbusError.getMessage(); ASSERT_TRUE(dbusMessageReply.isMethodReturnType()); ASSERT_TRUE(dbusMessageReply.hasSignature("a{oa{sa{sv}}}")); CommonAPI::DBus::DBusInputStream dbusInputStream(dbusMessageReply); dbusInputStream >> dbusObjectPathAndInterfacesDict; ASSERT_FALSE(dbusInputStream.hasError()); } void getIntrospectionData(const std::string& dbusObjectPath, std::string& introspectionDataXml) { auto dbusMessageCall = CommonAPI::DBus::DBusMessage::createMethodCall( dbusServiceName, dbusObjectPath, "org.freedesktop.DBus.Introspectable", "Introspect"); CommonAPI::DBus::DBusError dbusError; auto dbusMessageReply = proxyDBusConnection_->sendDBusMessageWithReplyAndBlock(dbusMessageCall, dbusError); ASSERT_FALSE(dbusError)<< dbusError.getMessage(); ASSERT_TRUE(dbusMessageReply.isMethodReturnType()); ASSERT_TRUE(dbusMessageReply.hasSignature("s")); CommonAPI::DBus::DBusInputStream dbusInputStream(dbusMessageReply); dbusInputStream >> introspectionDataXml; ASSERT_FALSE(dbusInputStream.hasError()); } void waitForInterfacesAdded(const std::shared_ptr& dbusSignalHandler, const size_t& interfacesAddedCount, const size_t& interfacesRemovedExpectedCount) { const size_t waitMillisecondsPerInterface = 300; std::unique_lock lock(dbusSignalHandler->lock); auto waitResult = dbusSignalHandler->signalReceived.wait_for( lock, std::chrono::milliseconds(interfacesAddedCount * waitMillisecondsPerInterface), [&]() {return dbusSignalHandler->totalAddedCount == interfacesAddedCount;}); ASSERT_TRUE(waitResult); ASSERT_EQ(dbusSignalHandler->totalRemovedCount, interfacesRemovedExpectedCount); const std::string lastAddedDBusObjectPath = managedDBusObjectPathPrefix + std::to_string(interfacesAddedCount - 1); ASSERT_TRUE(dbusSignalHandler->lastAddedDBusObjectPath == lastAddedDBusObjectPath); } void waitForInterfacesRemoved(const std::shared_ptr& dbusSignalHandler, const size_t& interfacesRemovedCount, const size_t& interfacesAddedExpectedCount) { const size_t waitMillisecondsPerInterface = 300; std::unique_lock lock(dbusSignalHandler->lock); auto waitResult = dbusSignalHandler->signalReceived.wait_for( lock, std::chrono::milliseconds(interfacesRemovedCount * waitMillisecondsPerInterface), [&]() {return dbusSignalHandler->totalRemovedCount == interfacesRemovedCount;}); ASSERT_TRUE(waitResult); ASSERT_EQ(dbusSignalHandler->totalAddedCount, interfacesAddedExpectedCount); const std::string lastRemovedDBusObjectPath = managedDBusObjectPathPrefix + std::to_string(interfacesRemovedCount - 1); ASSERT_TRUE(dbusSignalHandler->lastRemovedDBusObjectPath == lastRemovedDBusObjectPath); } template void createDBusStubAdapterArray(std::array, _ArraySize>& dbusStubAdapter) { for (size_t i = 0; i < _ArraySize; i++) { dbusStubAdapter[i] = std::make_shared<_StubType>(serviceFactory, managedDBusObjectPathPrefix + std::to_string(i), stubDBusConnection_, false); ASSERT_TRUE(bool(dbusStubAdapter[i])); dbusStubAdapter[i]->init(dbusStubAdapter[i]); } } std::shared_ptr proxyDBusConnection_; std::shared_ptr stubDBusConnection_; }; TEST_F(DBusObjectManagerStubTest, EmptyRootGetManagedObjectsWorks) { CommonAPI::DBus::DBusObjectManagerStub::DBusObjectPathAndInterfacesDict dbusObjectPathAndInterfacesDict; getManagedObjects("/", dbusObjectPathAndInterfacesDict); ASSERT_TRUE(dbusObjectPathAndInterfacesDict.empty()); } TEST_F(DBusObjectManagerStubTest, RootObjectManagerIntrospectionWorks) { std::string introspectionDataXml; getIntrospectionData("/", introspectionDataXml); ASSERT_FALSE(introspectionDataXml.empty()); ASSERT_TRUE(introspectionDataXml.find("GetManagedObjects") != std::string::npos); ASSERT_TRUE(introspectionDataXml.find("InterfacesAdded") != std::string::npos); ASSERT_TRUE(introspectionDataXml.find("InterfacesRemoved") != std::string::npos); } TEST_F(DBusObjectManagerStubTest, RootRegisterStubAdapterWorks) { CommonAPI::DBus::DBusObjectManagerStub::DBusObjectPathAndInterfacesDict dbusObjectPathAndInterfacesDict; auto dbusSignalHandler = TestDBusObjectManagerSignalHandler::create("/", proxyDBusConnection_); std::array, 10> dbusStubAdapterArray; createDBusStubAdapterArray(dbusStubAdapterArray); const bool isServiceRegistrationSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [](const std::shared_ptr& dbusStubAdapter) { return CommonAPI::DBus::DBusServicePublisher::getInstance()->registerService(dbusStubAdapter); }); ASSERT_TRUE(isServiceRegistrationSuccessful); waitForInterfacesAdded(dbusSignalHandler, dbusStubAdapterArray.size(), 0); getManagedObjects("/", dbusObjectPathAndInterfacesDict); ASSERT_EQ(dbusObjectPathAndInterfacesDict.size(), dbusStubAdapterArray.size()); const bool isServiceDeregistrationSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [](const std::shared_ptr& dbusStubAdapter) { const auto& serviceAddress = dbusStubAdapter->getAddress(); return CommonAPI::DBus::DBusServicePublisher::getInstance()->unregisterService(serviceAddress); }); ASSERT_TRUE(isServiceDeregistrationSuccessful); waitForInterfacesRemoved(dbusSignalHandler, dbusStubAdapterArray.size(), dbusStubAdapterArray.size()); dbusObjectPathAndInterfacesDict.clear(); getManagedObjects("/", dbusObjectPathAndInterfacesDict); ASSERT_TRUE(dbusObjectPathAndInterfacesDict.empty()); } TEST_F(DBusObjectManagerStubTest, RegisterManagerStubAdapterWorks) { CommonAPI::DBus::DBusObjectManagerStub::DBusObjectPathAndInterfacesDict dbusObjectPathAndInterfacesDict; auto managerDBusStubAdapter = std::make_shared( serviceFactory, dbusObjectManagerStubPath, stubDBusConnection_); managerDBusStubAdapter->init(managerDBusStubAdapter); ASSERT_TRUE(CommonAPI::DBus::DBusServicePublisher::getInstance()->registerService(managerDBusStubAdapter)); getManagedObjects("/", dbusObjectPathAndInterfacesDict); ASSERT_FALSE(dbusObjectPathAndInterfacesDict.empty()); ASSERT_EQ(dbusObjectPathAndInterfacesDict.size(), 1); ASSERT_EQ(dbusObjectPathAndInterfacesDict.count(dbusObjectManagerStubPath), 1); ASSERT_EQ(dbusObjectPathAndInterfacesDict[dbusObjectManagerStubPath].size(), 2); ASSERT_EQ(dbusObjectPathAndInterfacesDict[dbusObjectManagerStubPath].count( CommonAPI::DBus::DBusObjectManagerStub::getInterfaceName()), 1); ASSERT_EQ(dbusObjectPathAndInterfacesDict[dbusObjectManagerStubPath].count( managerDBusStubAdapter->getInterfaceName()), 1); ASSERT_TRUE( CommonAPI::DBus::DBusServicePublisher::getInstance()->unregisterService( managerDBusStubAdapter->getAddress())); dbusObjectPathAndInterfacesDict.clear(); getManagedObjects("/", dbusObjectPathAndInterfacesDict); ASSERT_TRUE(dbusObjectPathAndInterfacesDict.empty()); } TEST_F(DBusObjectManagerStubTest, ManagerStubAdapterExportAndUnexportWorks) { CommonAPI::DBus::DBusObjectManagerStub::DBusObjectPathAndInterfacesDict dbusObjectPathAndInterfacesDict; auto dbusSignalHandler = TestDBusObjectManagerSignalHandler::create( dbusObjectManagerStubPath, proxyDBusConnection_); auto managerDBusStubAdapter = std::make_shared( serviceFactory, dbusObjectManagerStubPath, stubDBusConnection_); managerDBusStubAdapter->init(managerDBusStubAdapter); ASSERT_TRUE(CommonAPI::DBus::DBusServicePublisher::getInstance()->registerService(managerDBusStubAdapter)); std::array, 10> dbusStubAdapterArray; createDBusStubAdapterArray(dbusStubAdapterArray); const bool isServiceRegistrationSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [](const std::shared_ptr& dbusStubAdapter) { return CommonAPI::DBus::DBusServicePublisher::getInstance()->registerManagedService(dbusStubAdapter); }); ASSERT_TRUE(isServiceRegistrationSuccessful); const bool isServiceExportSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [&](const std::shared_ptr& dbusStubAdapter) { return stubDBusConnection_->getDBusObjectManager()->exportManagedDBusStubAdapter(managerDBusStubAdapter->getObjectPath(), dbusStubAdapter); }); ASSERT_TRUE(isServiceExportSuccessful); waitForInterfacesAdded(dbusSignalHandler, dbusStubAdapterArray.size(), 0); getManagedObjects(dbusObjectManagerStubPath, dbusObjectPathAndInterfacesDict); EXPECT_EQ(dbusObjectPathAndInterfacesDict.size(), dbusStubAdapterArray.size()); const bool isServiceUnexportSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [&](const std::shared_ptr& dbusStubAdapter) { return stubDBusConnection_->getDBusObjectManager()->unexportManagedDBusStubAdapter(managerDBusStubAdapter->getObjectPath(), dbusStubAdapter); }); ASSERT_TRUE(isServiceUnexportSuccessful); const bool isServiceDeregistrationSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [](const std::shared_ptr& dbusStubAdapter) { return CommonAPI::DBus::DBusServicePublisher::getInstance()->unregisterManagedService( dbusStubAdapter->getAddress()); }); ASSERT_TRUE(isServiceDeregistrationSuccessful); waitForInterfacesRemoved(dbusSignalHandler, dbusStubAdapterArray.size(), dbusStubAdapterArray.size()); dbusObjectPathAndInterfacesDict.clear(); getManagedObjects(dbusObjectManagerStubPath, dbusObjectPathAndInterfacesDict); EXPECT_TRUE(dbusObjectPathAndInterfacesDict.empty()); ASSERT_TRUE(CommonAPI::DBus::DBusServicePublisher::getInstance()->unregisterService(managerDBusStubAdapter->getAddress())); } TEST_F(DBusObjectManagerStubTest, DestructorUnpublishingWorks) { CommonAPI::DBus::DBusObjectManagerStub::DBusObjectPathAndInterfacesDict dbusObjectPathAndInterfacesDict; auto dbusSignalHandler = TestDBusObjectManagerSignalHandler::create( dbusObjectManagerStubPath, proxyDBusConnection_); auto managerDBusStubAdapter = std::make_shared( serviceFactory, dbusObjectManagerStubPath, stubDBusConnection_); managerDBusStubAdapter->init(managerDBusStubAdapter); EXPECT_TRUE(CommonAPI::DBus::DBusServicePublisher::getInstance()->registerService(managerDBusStubAdapter)); std::array, 10> dbusStubAdapterArray; createDBusStubAdapterArray(dbusStubAdapterArray); const bool isServiceRegistrationSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [](const std::shared_ptr& dbusStubAdapter) { return CommonAPI::DBus::DBusServicePublisher::getInstance()->registerManagedService(dbusStubAdapter); }); ASSERT_TRUE(isServiceRegistrationSuccessful); const bool isServiceExportSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [&](const std::shared_ptr& dbusStubAdapter) { return stubDBusConnection_->getDBusObjectManager()->exportManagedDBusStubAdapter(managerDBusStubAdapter->getObjectPath(), dbusStubAdapter); }); ASSERT_TRUE(isServiceExportSuccessful); waitForInterfacesAdded(dbusSignalHandler, dbusStubAdapterArray.size(), 0); ASSERT_TRUE(CommonAPI::DBus::DBusServicePublisher::getInstance()->unregisterService(managerDBusStubAdapter->getAddress())); managerDBusStubAdapter.reset(); const bool wasServiceDeregistrationSuccessful = std::all_of( dbusStubAdapterArray.begin(), dbusStubAdapterArray.end(), [](const std::shared_ptr& dbusStubAdapter) { return !CommonAPI::DBus::DBusServicePublisher::getInstance()->unregisterManagedService( dbusStubAdapter->getAddress()); }); ASSERT_TRUE(wasServiceDeregistrationSuccessful); } #ifndef __NO_MAIN__ int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } #endif