diff --git a/docs/using-sdbus-c++.md b/docs/using-sdbus-c++.md index f3bf50e..8e4f947 100644 --- a/docs/using-sdbus-c++.md +++ b/docs/using-sdbus-c++.md @@ -441,7 +441,7 @@ On the **server** side, we generally need to create D-Bus objects and publish th * its internal event loop * either in a blocking way, through `enterEventLoop()`, * or in a non-blocking async way, through `enterEventLoopAsync()`, - * or an external event loop. This is suitable if we use in our application an event loop implementation of our choice (e.g., GLib Event Loop, boost::asio, ...) and we want to hook up our sdbus-c++ connections with it. See [Using sdbus-c++ in external event loops](#using-sdbus-c-in-external-event-loops) section for more information. + * or an external event loop. This is suitable if we use in our application an event loop implementation of our choice (e.g., sd-event, GLib Event Loop, boost::asio, ...) and we want to hook up our sdbus-c++ connections with it. See [Using sdbus-c++ in external event loops](#using-sdbus-c-in-external-event-loops) section for more information. The object takes the D-Bus connection as a reference in its constructor. This is the only way to wire the connection and the object together. We must make sure the connection exists as long as objects using it exist. @@ -1723,7 +1723,13 @@ Note that the returned timeout should be considered only a maximum sleeping time `PollData::fd` is a bus I/O fd. `PollData::eventFd` is an sdbus-c++ internal fd for communicating important changes from other threads to the event loop thread, so the event loop retrieves new poll data (with updated timeout, for example) and, potentially, processes pending D-Bus messages (like signals that came in during a blocking synchronous call from other thread, or queued outgoing messages that are very big to be able to have been sent in one shot from another thread), before the next poll. -Consult `IConnection::PollData` and `IConnection::getEventLoopPollData()` documentation for more potentially more information. +Consult `IConnection::PollData` and `IConnection::getEventLoopPollData()` documentation for potentially more information. + +### Integration of sd-event event loop + +sdbus-c++ provides built-in integration of sd-event, which makes it very convenient to hook sdbus-c++ connection up with an sd-event event loop. + +See documentation of `IConnection::attachSdEventLoop()`, `IConnection::detachSdEventLoop()`, and `IConnection::getSdEventLoop()` methods, or sdbus-c++ integration tests for an example of use. These methods are sdbus-c++ counterparts to and mimic the behavior of these underlying sd-bus functions: `sd_bus_attach_event()`, `sd_bus_detach_event()`, and `sd_bus_get_event()`. Their manual pages provide much more details about their behavior. Conclusion ---------- diff --git a/include/sdbus-c++/IConnection.h b/include/sdbus-c++/IConnection.h index 329f69c..ef7729c 100644 --- a/include/sdbus-c++/IConnection.h +++ b/include/sdbus-c++/IConnection.h @@ -35,6 +35,7 @@ #include struct sd_bus; +struct sd_event; namespace sdbus { @@ -107,6 +108,32 @@ namespace sdbus { */ virtual void leaveEventLoop() = 0; + /*! + * @brief Attaches the bus connection to an sd-event event loop + * + * @param[in] event sd-event event loop object + * @param[in] priority Specified priority + * + * @throws sdbus::Error in case of failure + * + * See `man sd_bus_attach_event'. + */ + virtual void attachSdEventLoop(sd_event *event, int priority = 0) = 0; + + /*! + * @brief Detaches the bus connection from an sd-event event loop + * + * @throws sdbus::Error in case of failure + */ + virtual void detachSdEventLoop() = 0; + + /*! + * @brief Gets current sd-event event loop for the bus connection + * + * @return Pointer to event loop object if attached, nullptr otherwise + */ + virtual sd_event *getSdEventLoop() = 0; + /*! * @brief Adds an ObjectManager at the specified D-Bus object path * @@ -150,6 +177,10 @@ namespace sdbus { * Use PollData::getPollTimeout() to have the timeout value converted * in a form that can be passed to poll(2). * + * The bus connection conveniently integrates sd-event event loop. + * To attach the bus connection to an sd-event event loop, use + * attachSdEventLoop() function. + * * @throws sdbus::Error in case of failure */ [[nodiscard]] virtual PollData getEventLoopPollData() const = 0; @@ -170,7 +201,8 @@ namespace sdbus { * * You don't need to directly call this method or getEventLoopPollData() method * when using convenient, internal bus connection event loops through - * enterEventLoop() or enterEventLoopAsync() calls. + * enterEventLoop() or enterEventLoopAsync() calls, or when the bus is + * connected to an sd-event event loop through attachSdEventLoop(). * It is invoked automatically when necessary. * * @throws sdbus::Error in case of failure diff --git a/src/Connection.cpp b/src/Connection.cpp index aabb235..61abfbd 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -32,6 +32,9 @@ #include #include "ScopeGuard.h" #include SDBUS_HEADER +#ifndef SDBUS_basu // sd_event integration is not supported in basu-based sdbus-c++ +#include +#endif #include #include #include @@ -274,6 +277,189 @@ void Connection::addMatchAsync(const std::string& match, message_handler callbac floatingMatchRules_.push_back(addMatchAsync(match, std::move(callback), std::move(installCallback))); } +void Connection::attachSdEventLoop(sd_event *event, int priority) +{ +#ifndef SDBUS_basu + auto pollData = getEventLoopPollData(); + + auto sdEvent = createSdEventSlot(event); + auto sdTimeEventSource = createSdTimeEventSourceSlot(event, priority); + auto sdIoEventSource = createSdIoEventSourceSlot(event, pollData.fd, priority); + auto sdInternalEventSource = createSdInternalEventSourceSlot(event, pollData.eventFd, priority); + + sdEvent_ = std::make_unique(SdEvent{ std::move(sdEvent) + , std::move(sdTimeEventSource) + , std::move(sdIoEventSource) + , std::move(sdInternalEventSource) }); +#else + (void)event; + (void)priority; + SDBUS_THROW_ERROR("sd_event integration is not supported on this platform", EOPNOTSUPP); +#endif +} + +void Connection::detachSdEventLoop() +{ + sdEvent_.reset(); +} + +sd_event *Connection::getSdEventLoop() +{ + return sdEvent_ ? static_cast(sdEvent_->sdEvent.get()) : nullptr; +} + +#ifndef SDBUS_basu + +Slot Connection::createSdEventSlot(sd_event *event) +{ + // Get default event if no event is provided by the caller + if (event != nullptr) + event = sd_event_ref(event); + else + (void)sd_event_default(&event); + SDBUS_THROW_ERROR_IF(!event, "Invalid sd_event handle", EINVAL); + + return Slot{event, [](void* event){ sd_event_unref((sd_event*)event); }}; +} + +Slot Connection::createSdTimeEventSourceSlot(sd_event *event, int priority) +{ + sd_event_source *timeEventSource{}; + auto r = sd_event_add_time(event, &timeEventSource, CLOCK_MONOTONIC, 0, 0, onSdTimerEvent, this); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to add timer event", -r); + Slot sdTimeEventSource{timeEventSource, [](void* source){ deleteSdEventSource((sd_event_source*)source); }}; + + r = sd_event_source_set_priority(timeEventSource, priority); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event priority", -r); + + r = sd_event_source_set_description(timeEventSource, "bus-time"); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set time event description", -r); + + return sdTimeEventSource; +} + +Slot Connection::createSdIoEventSourceSlot(sd_event *event, int fd, int priority) +{ + sd_event_source *ioEventSource{}; + auto r = sd_event_add_io(event, &ioEventSource, fd, 0, onSdIoEvent, this); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to add io event", -r); + Slot sdIoEventSource{ioEventSource, [](void* source){ deleteSdEventSource((sd_event_source*)source); }}; + + r = sd_event_source_set_prepare(ioEventSource, onSdEventPrepare); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for IO event", -r); + + r = sd_event_source_set_priority(ioEventSource, priority); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r); + + r = sd_event_source_set_description(ioEventSource, "bus-input"); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r); + + return sdIoEventSource; +} + +Slot Connection::createSdInternalEventSourceSlot(sd_event *event, int fd, int priority) +{ + sd_event_source *internalEventSource{}; + auto r = sd_event_add_io(event, &internalEventSource, fd, 0, onSdInternalEvent, this); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to add internal event", -r); + Slot sdInternalEventSource{internalEventSource, [](void* source){ deleteSdEventSource((sd_event_source*)source); }}; + + // sd-event loop calls prepare callbacks for all event sources, not just for the one that fired now. + // So since onSdEventPrepare is already registered on ioEventSource, we don't need to duplicate it here. + //r = sd_event_source_set_prepare(internalEventSource, onSdEventPrepare); + //SDBUS_THROW_ERROR_IF(r < 0, "Failed to set prepare callback for internal event", -r); + + r = sd_event_source_set_priority(internalEventSource, priority); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for internal event", -r); + + r = sd_event_source_set_description(internalEventSource, "internal-event"); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set priority for IO event", -r); + + return sdInternalEventSource; +} + +int Connection::onSdTimerEvent(sd_event_source */*s*/, uint64_t /*usec*/, void *userdata) +{ + auto connection = static_cast(userdata); + assert(connection != nullptr); + + (void)connection->processPendingEvent(); + + return 1; +} + +int Connection::onSdIoEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata) +{ + auto connection = static_cast(userdata); + assert(connection != nullptr); + + (void)connection->processPendingEvent(); + + return 1; +} + +int Connection::onSdInternalEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata) +{ + auto connection = static_cast(userdata); + assert(connection != nullptr); + + // It's not really necessary to processPendingEvent() here. We just clear the event fd. + // The sd-event loop will before the next poll call prepare callbacks for all event sources, + // including I/O bus fd. This will get up-to-date poll timeout, which will be zero if there + // are pending D-Bus messages in the read queue, which will immediately wake up next poll + // and go to onSdIoEvent() handler, which calls processPendingEvent(). Viola. + // For external event loops that only have access to public sdbus-c++ API, processPendingEvent() + // is the only option to clear event fd (it comes at a little extra cost but on the other hand + // the solution is simpler for clients -- we don't provide an extra method for just clearing + // the event fd. There is one method for both fd's -- and that's processPendingEvent(). + + // Kept here so that potential readers know what to do in their custom external event loops. + //(void)connection->processPendingEvent(); + + connection->eventFd_.clear(); + + return 1; +} + +int Connection::onSdEventPrepare(sd_event_source */*s*/, void *userdata) +{ + auto connection = static_cast(userdata); + assert(connection != nullptr); + + auto sdbusPollData = connection->getEventLoopPollData(); + + // Set poll events to watch out for on I/O fd + auto* sdIoEventSource = static_cast(connection->sdEvent_->sdIoEventSource.get()); + auto r = sd_event_source_set_io_events(sdIoEventSource, sdbusPollData.events); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set poll events for IO event source", -r); + + // Set poll events to watch out for on internal event fd + auto* sdInternalEventSource = static_cast(connection->sdEvent_->sdInternalEventSource.get()); + r = sd_event_source_set_io_events(sdInternalEventSource, POLLIN); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set poll events for internal event source", -r); + + // Set current timeout to the time event source (it may be zero if there are messages in the sd-bus queues to be processed) + auto* sdTimeEventSource = static_cast(connection->sdEvent_->sdTimeEventSource.get()); + r = sd_event_source_set_time(sdTimeEventSource, static_cast(sdbusPollData.timeout.count())); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to set timeout for time event source", -r); + r = sd_event_source_set_enabled(sdTimeEventSource, SD_EVENT_ON); + SDBUS_THROW_ERROR_IF(r < 0, "Failed to enable time event source", -r); + + return 1; +} + +void Connection::deleteSdEventSource(sd_event_source *s) +{ +#if LIBSYSTEMD_VERSION>=243 + sd_event_source_disable_unref(s); +#else + sd_event_source_set_enabled(s, SD_EVENT_OFF); + sd_event_source_unref(s); +#endif +} + +#endif // SDBUS_basu + Slot Connection::addObjectVTable( const std::string& objectPath , const std::string& interfaceName , const sd_bus_vtable* vtable diff --git a/src/Connection.h b/src/Connection.h index 80a3d76..9da4a91 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -38,6 +38,8 @@ #include #include +struct sd_event_source; + namespace sdbus::internal { class Connection final @@ -97,6 +99,10 @@ namespace sdbus::internal { [[nodiscard]] Slot addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback) override; void addMatchAsync(const std::string& match, message_handler callback, message_handler installCallback, floating_slot_t) override; + void attachSdEventLoop(sd_event *event, int priority) override; + void detachSdEventLoop() override; + sd_event *getSdEventLoop() override; + const ISdBus& getSdBusInterface() const override; ISdBus& getSdBusInterface() override; @@ -162,6 +168,19 @@ namespace sdbus::internal { static int sdbus_match_install_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError); private: +#ifndef SDBUS_basu // sd_event integration is not supported if instead of libsystemd we are based on basu + Slot createSdEventSlot(sd_event *event); + Slot createSdTimeEventSourceSlot(sd_event *event, int priority); + Slot createSdIoEventSourceSlot(sd_event *event, int fd, int priority); + Slot createSdInternalEventSourceSlot(sd_event *event, int fd, int priority); + static void deleteSdEventSource(sd_event_source *s); + + static int onSdTimerEvent(sd_event_source *s, uint64_t usec, void *userdata); + static int onSdIoEvent(sd_event_source *s, int fd, uint32_t revents, void *userdata); + static int onSdInternalEvent(sd_event_source *s, int fd, uint32_t revents, void *userdata); + static int onSdEventPrepare(sd_event_source *s, void *userdata); +#endif + struct EventFd { EventFd(); @@ -180,6 +199,15 @@ namespace sdbus::internal { sd_bus_slot *slot; }; + // sd-event integration + struct SdEvent + { + Slot sdEvent; + Slot sdTimeEventSource; + Slot sdIoEventSource; + Slot sdInternalEventSource; + }; + private: std::unique_ptr sdbus_; BusPtr bus_; @@ -187,6 +215,7 @@ namespace sdbus::internal { EventFd loopExitFd_; // To wake up event loop I/O polling to exit EventFd eventFd_; // To wake up event loop I/O polling to re-enter poll with fresh PollData values std::vector floatingMatchRules_; + std::unique_ptr sdEvent_; // Integration of systemd sd-event event loop implementation }; } diff --git a/src/SdBus.cpp b/src/SdBus.cpp index 867f8aa..9ff05f2 100644 --- a/src/SdBus.cpp +++ b/src/SdBus.cpp @@ -300,11 +300,13 @@ int SdBus::sd_bus_open_server(sd_bus **ret, int fd) int SdBus::sd_bus_open_system_remote(sd_bus **ret, const char *host) { -#ifdef SDBUS_basu +#ifndef SDBUS_basu + return ::sd_bus_open_system_remote(ret, host); +#else + (void)ret; + (void)host; // https://git.sr.ht/~emersion/basu/commit/01d33b244eb6 return -EOPNOTSUPP; -#else - return ::sd_bus_open_system_remote(ret, host); #endif } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b7a20e5..fb08236 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -107,12 +107,21 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_executable(sdbus-c++-unit-tests ${UNITTESTS_SRCS}) target_compile_definitions(sdbus-c++-unit-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION} + SDBUS_${LIBSYSTEMD_IMPL} SDBUS_HEADER=<${LIBSYSTEMD_IMPL}/sd-bus.h>) target_link_libraries(sdbus-c++-unit-tests sdbus-c++-objlib GTest::gmock) add_executable(sdbus-c++-integration-tests ${INTEGRATIONTESTS_SRCS}) -target_compile_definitions(sdbus-c++-integration-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION}) -target_link_libraries(sdbus-c++-integration-tests sdbus-c++ GTest::gmock) +target_compile_definitions(sdbus-c++-integration-tests PRIVATE + LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION} + SDBUS_${LIBSYSTEMD}) +if(NOT LIBSYSTEMD STREQUAL "basu") + # Systemd::Libsystemd is included because integration tests use sd-event. Otherwise sdbus-c++ encapsulates and hides libsystemd. + target_link_libraries(sdbus-c++-integration-tests sdbus-c++ Systemd::Libsystemd GTest::gmock) +else() + # sd-event implementation is not part of basu, so its integration tests will be skipped + target_link_libraries(sdbus-c++-integration-tests sdbus-c++ GTest::gmock) +endif() # Manual performance and stress tests option(ENABLE_PERF_TESTS "Build and install manual performance tests (default OFF)" OFF) diff --git a/tests/integrationtests/DBusAsyncMethodsTests.cpp b/tests/integrationtests/DBusAsyncMethodsTests.cpp index 1ee1f73..d0a9862 100644 --- a/tests/integrationtests/DBusAsyncMethodsTests.cpp +++ b/tests/integrationtests/DBusAsyncMethodsTests.cpp @@ -49,20 +49,18 @@ using ::testing::SizeIs; using namespace std::chrono_literals; using namespace sdbus::test; -using SdbusTestObject = TestFixture; - /*-------------------------------------*/ /* -- TEST CASES -- */ /*-------------------------------------*/ -TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) +TYPED_TEST(AsyncSdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) { std::chrono::time_point start; try { std::promise promise; auto future = promise.get_future(); - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err) + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err) { if (err == nullptr) promise.set_value(res); @@ -71,7 +69,7 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) }); start = std::chrono::steady_clock::now(); - m_proxy->doOperationClientSideAsyncWithTimeout(1us, 1000); // The operation will take 1s, but the timeout is 500ms, so we should time out + this->m_proxy->doOperationClientSideAsyncWithTimeout(1us, (1s).count()); // The operation will take 1s, but the timeout is 1us, so we should time out future.get(); FAIL() << "Expected sdbus::Error exception"; @@ -89,7 +87,7 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) } } -TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously) +TYPED_TEST(AsyncSdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously) { // Yeah, this is kinda timing-dependent test, but times should be safe... std::mutex mtx; @@ -114,7 +112,7 @@ TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously) ASSERT_THAT(results, ElementsAre(500, 1000, 1500)); } -TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods) +TYPED_TEST(AsyncSdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods) { std::atomic resultCount{}; std::atomic invoke{}; @@ -144,11 +142,11 @@ TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods) ASSERT_THAT(resultCount, Eq(1500)); } -TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide) +TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSide) { std::promise promise; auto future = promise.get_future(); - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err) + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err) { if (err == nullptr) promise.set_value(res); @@ -156,21 +154,21 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide) promise.set_exception(std::make_exception_ptr(*err)); }); - m_proxy->doOperationClientSideAsync(100); + this->m_proxy->doOperationClientSideAsync(100); ASSERT_THAT(future.get(), Eq(100)); } -TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFuture) +TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFuture) { - auto future = m_proxy->doOperationClientSideAsync(100, sdbus::with_future); + auto future = this->m_proxy->doOperationClientSideAsync(100, sdbus::with_future); ASSERT_THAT(future.get(), Eq(100)); } -TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFutureOnBasicAPILevel) +TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFutureOnBasicAPILevel) { - auto future = m_proxy->doOperationClientSideAsyncOnBasicAPILevel(100); + auto future = this->m_proxy->doOperationClientSideAsyncOnBasicAPILevel(100); auto methodReply = future.get(); uint32_t returnValue{}; @@ -179,72 +177,72 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSideWithFutureOnBasic ASSERT_THAT(returnValue, Eq(100)); } -TEST_F(SdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress) +TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsPendingIfItIsInProgress) { - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){}); + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){}); - auto call = m_proxy->doOperationClientSideAsync(100); + auto call = this->m_proxy->doOperationClientSideAsync(100); ASSERT_TRUE(call.isPending()); } -TEST_F(SdbusTestObject, CancelsPendingAsyncCallOnClientSide) +TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSide) { std::promise promise; auto future = promise.get_future(); - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); - auto call = m_proxy->doOperationClientSideAsync(100); + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); + auto call = this->m_proxy->doOperationClientSideAsync(100); call.cancel(); ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout)); } -TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled) +TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled) { std::promise promise; auto future = promise.get_future(); - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); - auto call = m_proxy->doOperationClientSideAsync(100); + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); + auto call = this->m_proxy->doOperationClientSideAsync(100); call.cancel(); ASSERT_FALSE(call.isPending()); } -TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted) +TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted) { std::promise promise; auto future = promise.get_future(); - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); - auto call = m_proxy->doOperationClientSideAsync(0); + auto call = this->m_proxy->doOperationClientSideAsync(0); (void) future.get(); // Wait for the call to finish ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); })); } -TEST_F(SdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending) +TYPED_TEST(AsyncSdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending) { sdbus::PendingAsyncCall call; ASSERT_FALSE(call.isPending()); } -TEST_F(SdbusTestObject, SupportsAsyncCallCopyAssignment) +TYPED_TEST(AsyncSdbusTestObject, SupportsAsyncCallCopyAssignment) { sdbus::PendingAsyncCall call; - call = m_proxy->doOperationClientSideAsync(100); + call = this->m_proxy->doOperationClientSideAsync(100); ASSERT_TRUE(call.isPending()); } -TEST_F(SdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails) +TYPED_TEST(AsyncSdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails) { std::promise promise; auto future = promise.get_future(); - m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err) + this->m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err) { if (err == nullptr) promise.set_value(res); @@ -252,14 +250,14 @@ TEST_F(SdbusTestObject, ReturnsNonnullErrorWhenAsynchronousMethodCallFails) promise.set_exception(std::make_exception_ptr(*err)); }); - m_proxy->doErroneousOperationClientSideAsync(); + this->m_proxy->doErroneousOperationClientSideAsync(); ASSERT_THROW(future.get(), sdbus::Error); } -TEST_F(SdbusTestObject, ThrowsErrorWhenClientSideAsynchronousMethodCallWithFutureFails) +TYPED_TEST(AsyncSdbusTestObject, ThrowsErrorWhenClientSideAsynchronousMethodCallWithFutureFails) { - auto future = m_proxy->doErroneousOperationClientSideAsync(sdbus::with_future); + auto future = this->m_proxy->doErroneousOperationClientSideAsync(sdbus::with_future); ASSERT_THROW(future.get(), sdbus::Error); } diff --git a/tests/integrationtests/DBusGeneralTests.cpp b/tests/integrationtests/DBusGeneralTests.cpp index edeab54..17816c0 100644 --- a/tests/integrationtests/DBusGeneralTests.cpp +++ b/tests/integrationtests/DBusGeneralTests.cpp @@ -45,7 +45,6 @@ using ::testing::Eq; using namespace std::chrono_literals; using namespace sdbus::test; -using AConnection = TestFixture; using ADirectConnection = TestFixtureWithDirectConnection; /*-------------------------------------*/ @@ -73,61 +72,61 @@ TEST(AnAdaptor, SupportsMoveSemantics) static_assert(std::is_move_assignable_v); } -TEST_F(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule) +TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule) { auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; std::atomic matchingMessageReceived{false}; - auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) + auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) { if(msg.getPath() == OBJECT_PATH) matchingMessageReceived = true; }); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); ASSERT_TRUE(waitUntil(matchingMessageReceived)); } -TEST_F(AConnection, CanInstallMatchRuleAsynchronously) +TYPED_TEST(AConnection, CanInstallMatchRuleAsynchronously) { auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; std::atomic matchingMessageReceived{false}; std::atomic matchRuleInstalled{false}; - auto slot = s_proxyConnection->addMatchAsync( matchRule - , [&](sdbus::Message& msg) - { - if(msg.getPath() == OBJECT_PATH) - matchingMessageReceived = true; - } - , [&](sdbus::Message& /*msg*/) - { - matchRuleInstalled = true; - } ); + auto slot = this->s_proxyConnection->addMatchAsync( matchRule + , [&](sdbus::Message& msg) + { + if(msg.getPath() == OBJECT_PATH) + matchingMessageReceived = true; + } + , [&](sdbus::Message& /*msg*/) + { + matchRuleInstalled = true; + } ); EXPECT_TRUE(waitUntil(matchRuleInstalled)); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); ASSERT_TRUE(waitUntil(matchingMessageReceived)); } -TEST_F(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot) +TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot) { auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; std::atomic matchingMessageReceived{false}; - auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) + auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) { if(msg.getPath() == OBJECT_PATH) matchingMessageReceived = true; }); slot.reset(); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_FALSE(waitUntil(matchingMessageReceived, 2s)); + ASSERT_FALSE(waitUntil(matchingMessageReceived, 1s)); } -TEST_F(AConnection, CanAddFloatingMatchRule) +TYPED_TEST(AConnection, CanAddFloatingMatchRule) { auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; std::atomic matchingMessageReceived{false}; @@ -139,31 +138,31 @@ TEST_F(AConnection, CanAddFloatingMatchRule) matchingMessageReceived = true; }; con->addMatch(matchRule, std::move(callback), sdbus::floating_slot); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); [[maybe_unused]] auto gotMessage = waitUntil(matchingMessageReceived, 2s); assert(gotMessage); matchingMessageReceived = false; con.reset(); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_FALSE(waitUntil(matchingMessageReceived, 2s)); + ASSERT_FALSE(waitUntil(matchingMessageReceived, 1s)); } -TEST_F(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule) +TYPED_TEST(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule) { auto matchRule = "type='signal',interface='" + INTERFACE_NAME + "',member='simpleSignal'"; std::atomic numberOfMatchingMessages{}; - auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) + auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) { if(msg.getMemberName() == "simpleSignal") numberOfMatchingMessages++; }); - auto adaptor2 = std::make_unique(*s_adaptorConnection, OBJECT_PATH_2); + auto adaptor2 = std::make_unique(*this->s_adaptorConnection, OBJECT_PATH_2); - m_adaptor->emitSignalWithMap({}); + this->m_adaptor->emitSignalWithMap({}); adaptor2->emitSimpleSignal(); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); ASSERT_TRUE(waitUntil([&](){ return numberOfMatchingMessages == 2; })); ASSERT_FALSE(waitUntil([&](){ return numberOfMatchingMessages > 2; }, 1s)); diff --git a/tests/integrationtests/DBusMethodsTests.cpp b/tests/integrationtests/DBusMethodsTests.cpp index 50f8dfb..62acb39 100644 --- a/tests/integrationtests/DBusMethodsTests.cpp +++ b/tests/integrationtests/DBusMethodsTests.cpp @@ -50,59 +50,57 @@ using ::testing::NotNull; using namespace std::chrono_literals; using namespace sdbus::test; -using SdbusTestObject = TestFixture; - /*-------------------------------------*/ /* -- TEST CASES -- */ /*-------------------------------------*/ -TEST_F(SdbusTestObject, CallsEmptyMethodSuccesfully) +TYPED_TEST(SdbusTestObject, CallsEmptyMethodSuccesfully) { - ASSERT_NO_THROW(m_proxy->noArgNoReturn()); + ASSERT_NO_THROW(this->m_proxy->noArgNoReturn()); } -TEST_F(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully) { - auto resInt = m_proxy->getInt(); + auto resInt = this->m_proxy->getInt(); ASSERT_THAT(resInt, Eq(INT32_VALUE)); - auto multiplyRes = m_proxy->multiply(INT64_VALUE, DOUBLE_VALUE); + auto multiplyRes = this->m_proxy->multiply(INT64_VALUE, DOUBLE_VALUE); ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodsWithTuplesSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodsWithTuplesSuccesfully) { - auto resTuple = m_proxy->getTuple(); + auto resTuple = this->m_proxy->getTuple(); ASSERT_THAT(std::get<0>(resTuple), Eq(UINT32_VALUE)); ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodsWithStructSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccesfully) { sdbus::Struct> a{}; - auto vectorRes = m_proxy->getInts16FromStruct(a); + auto vectorRes = this->m_proxy->getInts16FromStruct(a); ASSERT_THAT(vectorRes, Eq(std::vector{0})); // because second item is by default initialized to 0 sdbus::Struct> b{ UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE} }; - vectorRes = m_proxy->getInts16FromStruct(b); + vectorRes = this->m_proxy->getInts16FromStruct(b); ASSERT_THAT(vectorRes, Eq(std::vector{INT16_VALUE, INT16_VALUE, -INT16_VALUE})); } -TEST_F(SdbusTestObject, CallsMethodWithVariantSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithVariantSuccesfully) { sdbus::Variant v{DOUBLE_VALUE}; - auto variantRes = m_proxy->processVariant(v); + sdbus::Variant variantRes = this->m_proxy->processVariant(v); ASSERT_THAT(variantRes.get(), Eq(static_cast(DOUBLE_VALUE))); } -TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully) { std::vector x{-2, 0, 2}; sdbus::Struct y{false, true}; - auto mapOfVariants = m_proxy->getMapOfVariants(x, y); + std::map mapOfVariants = this->m_proxy->getMapOfVariants(x, y); decltype(mapOfVariants) res{ {sdbus::Variant{-2}, sdbus::Variant{false}} , {sdbus::Variant{0}, sdbus::Variant{false}} , {sdbus::Variant{2}, sdbus::Variant{true}}}; @@ -112,69 +110,69 @@ TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully) ASSERT_THAT(mapOfVariants[2].get(), Eq(res[2].get())); } -TEST_F(SdbusTestObject, CallsMethodWithStructInStructSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithStructInStructSuccesfully) { - auto val = m_proxy->getStructInStruct(); - ASSERT_THAT(val.get<0>(), Eq(STRING_VALUE)); + auto val = this->m_proxy->getStructInStruct(); + ASSERT_THAT(val.template get<0>(), Eq(STRING_VALUE)); ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully) { - auto val = m_proxy->sumStructItems({1, 2}, {3, 4}); + auto val = this->m_proxy->sumStructItems({1, 2}, {3, 4}); ASSERT_THAT(val, Eq(1 + 2 + 3 + 4)); } -TEST_F(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully) { - auto val = m_proxy->sumArrayItems({1, 7}, {2, 3, 4}); + auto val = this->m_proxy->sumArrayItems({1, 7}, {2, 3, 4}); ASSERT_THAT(val, Eq(1 + 7 + 2 + 3 + 4)); } -TEST_F(SdbusTestObject, CallsMethodWithSignatureSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithSignatureSuccesfully) { - auto resSignature = m_proxy->getSignature(); + auto resSignature = this->m_proxy->getSignature(); ASSERT_THAT(resSignature, Eq(SIGNATURE_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodWithObjectPathSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithObjectPathSuccesfully) { - auto resObjectPath = m_proxy->getObjPath(); + auto resObjectPath = this->m_proxy->getObjPath(); ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodWithUnixFdSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithUnixFdSuccesfully) { - auto resUnixFd = m_proxy->getUnixFd(); + auto resUnixFd = this->m_proxy->getUnixFd(); ASSERT_THAT(resUnixFd.get(), Gt(UNIX_FD_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully) { - auto resComplex = m_proxy->getComplex(); + auto resComplex = this->m_proxy->getComplex(); ASSERT_THAT(resComplex.count(0), Eq(1)); } -TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag) +TYPED_TEST(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag) { - m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE); + this->m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE); - ASSERT_TRUE(waitUntil(m_adaptor->m_wasMultiplyCalled)); - ASSERT_THAT(m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE)); + ASSERT_TRUE(waitUntil(this->m_adaptor->m_wasMultiplyCalled)); + ASSERT_THAT(this->m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE)); } -TEST_F(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully) +TYPED_TEST(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully) { - auto res = m_proxy->doOperationWithTimeout(500ms, 20); // The operation will take 20ms, but the timeout is 500ms, so we are fine + auto res = this->m_proxy->doOperationWithTimeout(500ms, (20ms).count()); // The operation will take 20ms, but the timeout is 500ms, so we are fine ASSERT_THAT(res, Eq(20)); } -TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut) +TYPED_TEST(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut) { auto start = std::chrono::steady_clock::now(); try { - m_proxy->doOperationWithTimeout(1us, 1000); // The operation will take 1s, but the timeout is 1us, so we should time out + this->m_proxy->doOperationWithTimeout(1us, (1s).count()); // The operation will take 1s, but the timeout is 1us, so we should time out FAIL() << "Expected sdbus::Error exception"; } catch (const sdbus::Error& e) @@ -190,11 +188,11 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut) } } -TEST_F(SdbusTestObject, CallsMethodThatThrowsError) +TYPED_TEST(SdbusTestObject, CallsMethodThatThrowsError) { try { - m_proxy->throwError(); + this->m_proxy->throwError(); FAIL() << "Expected sdbus::Error exception"; } catch (const sdbus::Error& e) @@ -208,74 +206,74 @@ TEST_F(SdbusTestObject, CallsMethodThatThrowsError) } } -TEST_F(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet) +TYPED_TEST(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet) { - ASSERT_NO_THROW(m_proxy->throwErrorWithNoReply()); + ASSERT_NO_THROW(this->m_proxy->throwErrorWithNoReply()); - ASSERT_TRUE(waitUntil(m_adaptor->m_wasThrowErrorCalled)); + ASSERT_TRUE(waitUntil(this->m_adaptor->m_wasThrowErrorCalled)); } -TEST_F(SdbusTestObject, FailsCallingNonexistentMethod) +TYPED_TEST(SdbusTestObject, FailsCallingNonexistentMethod) { - ASSERT_THROW(m_proxy->callNonexistentMethod(), sdbus::Error); + ASSERT_THROW(this->m_proxy->callNonexistentMethod(), sdbus::Error); } -TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentInterface) +TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentInterface) { - ASSERT_THROW(m_proxy->callMethodOnNonexistentInterface(), sdbus::Error); + ASSERT_THROW(this->m_proxy->callMethodOnNonexistentInterface(), sdbus::Error); } -TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination) +TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentDestination) { TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH); ASSERT_THROW(proxy.getInt(), sdbus::Error); } -TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject) +TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentObject) { TestProxy proxy(BUS_NAME, "/sdbuscpp/path/that/does/not/exist"); ASSERT_THROW(proxy.getInt(), sdbus::Error); } -TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall) +TYPED_TEST(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall) { - m_proxy->emitTwoSimpleSignals(); + this->m_proxy->emitTwoSimpleSignals(); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap)); + EXPECT_TRUE(waitUntil(this->m_proxy->m_gotSimpleSignal)); + EXPECT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithMap)); } -TEST_F(SdbusTestObject, CanAccessAssociatedMethodCallMessageInMethodCallHandler) +TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInMethodCallHandler) { - m_proxy->doOperation(10); // This will save pointer to method call message on server side + this->m_proxy->doOperation(10); // This will save pointer to method call message on server side - ASSERT_THAT(m_adaptor->m_methodCallMsg, NotNull()); - ASSERT_THAT(m_adaptor->m_methodCallMemberName, Eq("doOperation")); + ASSERT_THAT(this->m_adaptor->m_methodCallMsg, NotNull()); + ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperation")); } -TEST_F(SdbusTestObject, CanAccessAssociatedMethodCallMessageInAsyncMethodCallHandler) +TYPED_TEST(SdbusTestObject, CanAccessAssociatedMethodCallMessageInAsyncMethodCallHandler) { - m_proxy->doOperationAsync(10); // This will save pointer to method call message on server side + this->m_proxy->doOperationAsync(10); // This will save pointer to method call message on server side - ASSERT_THAT(m_adaptor->m_methodCallMsg, NotNull()); - ASSERT_THAT(m_adaptor->m_methodCallMemberName, Eq("doOperationAsync")); + ASSERT_THAT(this->m_adaptor->m_methodCallMsg, NotNull()); + ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperationAsync")); } #if LIBSYSTEMD_VERSION>=240 -TEST_F(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239) +TYPED_TEST(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239) { - s_adaptorConnection->setMethodCallTimeout(5000000); - ASSERT_THAT(s_adaptorConnection->getMethodCallTimeout(), Eq(5000000)); + this->s_adaptorConnection->setMethodCallTimeout(5000000); + ASSERT_THAT(this->s_adaptorConnection->getMethodCallTimeout(), Eq(5000000)); } #else -TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240) +TYPED_TEST(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240) { - ASSERT_THROW(s_adaptorConnection->setMethodCallTimeout(5000000), sdbus::Error); - ASSERT_THROW(s_adaptorConnection->getMethodCallTimeout(), sdbus::Error); + ASSERT_THROW(this->s_adaptorConnection->setMethodCallTimeout(5000000), sdbus::Error); + ASSERT_THROW(this->s_adaptorConnection->getMethodCallTimeout(), sdbus::Error); } #endif -TEST_F(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread) +TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread) { #if defined(__clang__) && defined(__FreeBSD__) GTEST_SKIP() << "https://github.com/Kistler-Group/sdbus-cpp/issues/359"; diff --git a/tests/integrationtests/DBusPropertiesTests.cpp b/tests/integrationtests/DBusPropertiesTests.cpp index 12fe326..fa90215 100644 --- a/tests/integrationtests/DBusPropertiesTests.cpp +++ b/tests/integrationtests/DBusPropertiesTests.cpp @@ -51,35 +51,33 @@ using ::testing::IsEmpty; using namespace std::chrono_literals; using namespace sdbus::test; -using SdbusTestObject = TestFixture; - /*-------------------------------------*/ /* -- TEST CASES -- */ /*-------------------------------------*/ -TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully) +TYPED_TEST(SdbusTestObject, ReadsReadOnlyPropertySuccesfully) { - ASSERT_THAT(m_proxy->state(), Eq(DEFAULT_STATE_VALUE)); + ASSERT_THAT(this->m_proxy->state(), Eq(DEFAULT_STATE_VALUE)); } -TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty) +TYPED_TEST(SdbusTestObject, FailsWritingToReadOnlyProperty) { - ASSERT_THROW(m_proxy->setStateProperty("new_value"), sdbus::Error); + ASSERT_THROW(this->m_proxy->setStateProperty("new_value"), sdbus::Error); } -TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully) +TYPED_TEST(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully) { uint32_t newActionValue = 5678; - m_proxy->action(newActionValue); + this->m_proxy->action(newActionValue); - ASSERT_THAT(m_proxy->action(), Eq(newActionValue)); + ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue)); } -TEST_F(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHandler) +TYPED_TEST(SdbusTestObject, CanAccessAssociatedPropertySetMessageInPropertySetHandler) { - m_proxy->blocking(true); // This will save pointer to property get message on server side + this->m_proxy->blocking(true); // This will save pointer to property get message on server side - ASSERT_THAT(m_adaptor->m_propertySetMsg, NotNull()); - ASSERT_THAT(m_adaptor->m_propertySetSender, Not(IsEmpty())); + ASSERT_THAT(this->m_adaptor->m_propertySetMsg, NotNull()); + ASSERT_THAT(this->m_adaptor->m_propertySetSender, Not(IsEmpty())); } diff --git a/tests/integrationtests/DBusSignalsTests.cpp b/tests/integrationtests/DBusSignalsTests.cpp index 6f907cd..d75dcb7 100644 --- a/tests/integrationtests/DBusSignalsTests.cpp +++ b/tests/integrationtests/DBusSignalsTests.cpp @@ -44,32 +44,30 @@ using ::testing::NotNull; using namespace std::chrono_literals; using namespace sdbus::test; -using SdbusTestObject = TestFixture; - /*-------------------------------------*/ /* -- TEST CASES -- */ /*-------------------------------------*/ -TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully) +TYPED_TEST(SdbusTestObject, EmitsSimpleSignalSuccesfully) { - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSimpleSignal)); } -TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully) +TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully) { - auto proxy1 = std::make_unique(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); - auto proxy2 = std::make_unique(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); + auto proxy1 = std::make_unique(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH); + auto proxy2 = std::make_unique(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSimpleSignal)); ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal)); ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal)); } -TEST_F(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName) +TYPED_TEST(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName) { auto otherBusName = BUS_NAME + "2"; auto connection2 = sdbus::createConnection(otherBusName); @@ -77,93 +75,94 @@ TEST_F(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName) adaptor2->emitSimpleSignal(); - ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s)); + ASSERT_FALSE(waitUntil(this->m_proxy->m_gotSimpleSignal, 1s)); } -TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully) +TYPED_TEST(SdbusTestObject, EmitsSignalWithMapSuccesfully) { - m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}}); + this->m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}}); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap)); - ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("zero")); - ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one")); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithMap)); + ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("zero")); + ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("one")); } -TEST_F(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully) +TYPED_TEST(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully) { std::map largeMap; for (int32_t i = 0; i < 20'000; ++i) largeMap.emplace(i, "This is string nr. " + std::to_string(i+1)); - m_adaptor->emitSignalWithMap(largeMap); + this->m_adaptor->emitSignalWithMap(largeMap); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap)); - ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1")); - ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2")); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithMap)); + ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1")); + ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("This is string nr. 2")); } -TEST_F(SdbusTestObject, EmitsSignalWithVariantSuccesfully) +TYPED_TEST(SdbusTestObject, EmitsSignalWithVariantSuccesfully) { double d = 3.14; - m_adaptor->emitSignalWithVariant(sdbus::Variant{d}); + this->m_adaptor->emitSignalWithVariant(sdbus::Variant{d}); + this->m_adaptor->emitSignalWithVariant(d); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithVariant)); - ASSERT_THAT(m_proxy->m_variantFromSignal, DoubleEq(d)); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithVariant)); + ASSERT_THAT(this->m_proxy->m_variantFromSignal, DoubleEq(d)); } -TEST_F(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully) +TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully) { - m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}}); + this->m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}}); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithSignature)); - ASSERT_THAT(m_proxy->m_signatureFromSignal["platform"], Eq("av")); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithSignature)); + ASSERT_THAT(this->m_proxy->m_signatureFromSignal["platform"], Eq("av")); } -TEST_F(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler) +TYPED_TEST(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler) { - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - waitUntil(m_proxy->m_gotSimpleSignal); + waitUntil(this->m_proxy->m_gotSimpleSignal); - ASSERT_THAT(m_proxy->m_signalMsg, NotNull()); - ASSERT_THAT(m_proxy->m_signalMemberName, Eq("simpleSignal")); + ASSERT_THAT(this->m_proxy->m_signalMsg, NotNull()); + ASSERT_THAT(this->m_proxy->m_signalMemberName, Eq("simpleSignal")); } -TEST_F(SdbusTestObject, UnregistersSignalHandler) +TYPED_TEST(SdbusTestObject, UnregistersSignalHandler) { - ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler()); + ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler()); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s)); + ASSERT_FALSE(waitUntil(this->m_proxy->m_gotSimpleSignal, 1s)); } -TEST_F(SdbusTestObject, UnregistersSignalHandlerForSomeProxies) +TYPED_TEST(SdbusTestObject, UnregistersSignalHandlerForSomeProxies) { - auto proxy1 = std::make_unique(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); - auto proxy2 = std::make_unique(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); + auto proxy1 = std::make_unique(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH); + auto proxy2 = std::make_unique(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH); - ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler()); + ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler()); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal)); ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal)); - ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s)); + ASSERT_FALSE(waitUntil(this->m_proxy->m_gotSimpleSignal, 1s)); } -TEST_F(SdbusTestObject, ReRegistersSignalHandler) +TYPED_TEST(SdbusTestObject, ReRegistersSignalHandler) { // unregister simple-signal handler - ASSERT_NO_THROW(m_proxy->unregisterSimpleSignalHandler()); + ASSERT_NO_THROW(this->m_proxy->unregisterSimpleSignalHandler()); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s)); + ASSERT_FALSE(waitUntil(this->m_proxy->m_gotSimpleSignal, 1s)); // re-register simple-signal handler - ASSERT_NO_THROW(m_proxy->reRegisterSimpleSignalHandler()); + ASSERT_NO_THROW(this->m_proxy->reRegisterSimpleSignalHandler()); - m_adaptor->emitSimpleSignal(); + this->m_adaptor->emitSimpleSignal(); - ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); + ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSimpleSignal)); } diff --git a/tests/integrationtests/DBusStandardInterfacesTests.cpp b/tests/integrationtests/DBusStandardInterfacesTests.cpp index e648fac..57e9340 100644 --- a/tests/integrationtests/DBusStandardInterfacesTests.cpp +++ b/tests/integrationtests/DBusStandardInterfacesTests.cpp @@ -48,43 +48,41 @@ using ::testing::SizeIs; using namespace std::chrono_literals; using namespace sdbus::test; -using SdbusTestObject = TestFixture; - /*-------------------------------------*/ /* -- TEST CASES -- */ /*-------------------------------------*/ -TEST_F(SdbusTestObject, PingsViaPeerInterface) +TYPED_TEST(SdbusTestObject, PingsViaPeerInterface) { - ASSERT_NO_THROW(m_proxy->Ping()); + ASSERT_NO_THROW(this->m_proxy->Ping()); } -TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface) +TYPED_TEST(SdbusTestObject, AnswersMachineUuidViaPeerInterface) { if (::access("/etc/machine-id", F_OK) == -1 && ::access("/var/lib/dbus/machine-id", F_OK) == -1) GTEST_SKIP() << "/etc/machine-id and /var/lib/dbus/machine-id files do not exist, GetMachineId() will not work"; - ASSERT_NO_THROW(m_proxy->GetMachineId()); + ASSERT_NO_THROW(this->m_proxy->GetMachineId()); } // TODO: Adjust expected xml and uncomment this test -//TEST_F(SdbusTestObject, AnswersXmlApiDescriptionViaIntrospectableInterface) +//TYPED_TEST(SdbusTestObject, AnswersXmlApiDescriptionViaIntrospectableInterface) //{ -// ASSERT_THAT(m_proxy->Introspect(), Eq(m_adaptor->getExpectedXmlApiDescription())); +// ASSERT_THAT(this->m_proxy->Introspect(), Eq(this->m_adaptor->getExpectedXmlApiDescription())); //} -TEST_F(SdbusTestObject, GetsPropertyViaPropertiesInterface) +TYPED_TEST(SdbusTestObject, GetsPropertyViaPropertiesInterface) { - ASSERT_THAT(m_proxy->Get(INTERFACE_NAME, "state").get(), Eq(DEFAULT_STATE_VALUE)); + ASSERT_THAT(this->m_proxy->Get(INTERFACE_NAME, "state").template get(), Eq(DEFAULT_STATE_VALUE)); } -TEST_F(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterface) +TYPED_TEST(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterface) { std::promise promise; auto future = promise.get_future(); - m_proxy->GetAsync(INTERFACE_NAME, "state", [&](const sdbus::Error* err, sdbus::Variant value) + this->m_proxy->GetAsync(INTERFACE_NAME, "state", [&](const sdbus::Error* err, sdbus::Variant value) { if (err == nullptr) promise.set_value(value.get()); @@ -95,29 +93,29 @@ TEST_F(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterface) ASSERT_THAT(future.get(), Eq(DEFAULT_STATE_VALUE)); } -TEST_F(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture) +TYPED_TEST(SdbusTestObject, GetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture) { - auto future = m_proxy->GetAsync(INTERFACE_NAME, "state", sdbus::with_future); + auto future = this->m_proxy->GetAsync(INTERFACE_NAME, "state", sdbus::with_future); - ASSERT_THAT(future.get().get(), Eq(DEFAULT_STATE_VALUE)); + ASSERT_THAT(future.get().template get(), Eq(DEFAULT_STATE_VALUE)); } -TEST_F(SdbusTestObject, SetsPropertyViaPropertiesInterface) +TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface) { uint32_t newActionValue = 2345; - m_proxy->Set(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}); + this->m_proxy->Set(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}); - ASSERT_THAT(m_proxy->action(), Eq(newActionValue)); + ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue)); } -TEST_F(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface) +TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface) { uint32_t newActionValue = 2346; std::promise promise; auto future = promise.get_future(); - m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, [&](const sdbus::Error* err) + this->m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, [&](const sdbus::Error* err) { if (err == nullptr) promise.set_value(); @@ -126,35 +124,35 @@ TEST_F(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterface) }); ASSERT_NO_THROW(future.get()); - ASSERT_THAT(m_proxy->action(), Eq(newActionValue)); + ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue)); } -TEST_F(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture) +TYPED_TEST(SdbusTestObject, SetsPropertyAsynchronouslyViaPropertiesInterfaceWithFuture) { uint32_t newActionValue = 2347; - auto future = m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, sdbus::with_future); + auto future = this->m_proxy->SetAsync(INTERFACE_NAME, "action", sdbus::Variant{newActionValue}, sdbus::with_future); ASSERT_NO_THROW(future.get()); - ASSERT_THAT(m_proxy->action(), Eq(newActionValue)); + ASSERT_THAT(this->m_proxy->action(), Eq(newActionValue)); } -TEST_F(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface) +TYPED_TEST(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface) { - const auto properties = m_proxy->GetAll(INTERFACE_NAME); + const auto properties = this->m_proxy->GetAll(INTERFACE_NAME); ASSERT_THAT(properties, SizeIs(3)); - EXPECT_THAT(properties.at("state").get(), Eq(DEFAULT_STATE_VALUE)); - EXPECT_THAT(properties.at("action").get(), Eq(DEFAULT_ACTION_VALUE)); - EXPECT_THAT(properties.at("blocking").get(), Eq(DEFAULT_BLOCKING_VALUE)); + EXPECT_THAT(properties.at("state").template get(), Eq(DEFAULT_STATE_VALUE)); + EXPECT_THAT(properties.at("action").template get(), Eq(DEFAULT_ACTION_VALUE)); + EXPECT_THAT(properties.at("blocking").template get(), Eq(DEFAULT_BLOCKING_VALUE)); } -TEST_F(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterface) +TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterface) { std::promise> promise; auto future = promise.get_future(); - m_proxy->GetAllAsync(INTERFACE_NAME, [&](const sdbus::Error* err, std::map value) + this->m_proxy->GetAllAsync(INTERFACE_NAME, [&](const sdbus::Error* err, std::map value) { if (err == nullptr) promise.set_value(std::move(value)); @@ -169,24 +167,24 @@ TEST_F(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterface) EXPECT_THAT(properties.at("blocking").get(), Eq(DEFAULT_BLOCKING_VALUE)); } -TEST_F(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfaceWithFuture) +TYPED_TEST(SdbusTestObject, GetsAllPropertiesAsynchronouslyViaPropertiesInterfaceWithFuture) { - auto future = m_proxy->GetAllAsync(INTERFACE_NAME, sdbus::with_future); + auto future = this->m_proxy->GetAllAsync(INTERFACE_NAME, sdbus::with_future); auto properties = future.get(); ASSERT_THAT(properties, SizeIs(3)); - EXPECT_THAT(properties.at("state").get(), Eq(DEFAULT_STATE_VALUE)); - EXPECT_THAT(properties.at("action").get(), Eq(DEFAULT_ACTION_VALUE)); - EXPECT_THAT(properties.at("blocking").get(), Eq(DEFAULT_BLOCKING_VALUE)); + EXPECT_THAT(properties.at("state").template get(), Eq(DEFAULT_STATE_VALUE)); + EXPECT_THAT(properties.at("action").template get(), Eq(DEFAULT_ACTION_VALUE)); + EXPECT_THAT(properties.at("blocking").template get(), Eq(DEFAULT_BLOCKING_VALUE)); } -TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties) +TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties) { std::atomic signalReceived{false}; - m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName - , const std::map& changedProperties - , const std::vector& /*invalidatedProperties*/ ) + this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName + , const std::map& changedProperties + , const std::vector& /*invalidatedProperties*/ ) { EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME)); EXPECT_THAT(changedProperties, SizeIs(1)); @@ -194,19 +192,19 @@ TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties) signalReceived = true; }; - m_proxy->blocking(!DEFAULT_BLOCKING_VALUE); - m_proxy->action(DEFAULT_ACTION_VALUE*2); - m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"}); + this->m_proxy->blocking(!DEFAULT_BLOCKING_VALUE); + this->m_proxy->action(DEFAULT_ACTION_VALUE*2); + this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"}); ASSERT_TRUE(waitUntil(signalReceived)); } -TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) +TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) { std::atomic signalReceived{false}; - m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName - , const std::map& changedProperties - , const std::vector& invalidatedProperties ) + this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName + , const std::map& changedProperties + , const std::vector& invalidatedProperties ) { EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME)); EXPECT_THAT(changedProperties, SizeIs(1)); @@ -216,38 +214,38 @@ TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) signalReceived = true; }; - m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME); + this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME); ASSERT_TRUE(waitUntil(signalReceived)); } -TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects) +TYPED_TEST(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects) { - m_adaptor.reset(); - const auto objectsInterfacesAndProperties = m_objectManagerProxy->GetManagedObjects(); + this->m_adaptor.reset(); + const auto objectsInterfacesAndProperties = this->m_objectManagerProxy->GetManagedObjects(); ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0)); } -TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully) +TYPED_TEST(SdbusTestObject, GetsManagedObjectsSuccessfully) { - auto adaptor2 = std::make_unique(*s_adaptorConnection, OBJECT_PATH_2); - const auto objectsInterfacesAndProperties = m_objectManagerProxy->GetManagedObjects(); + auto adaptor2 = std::make_unique(*this->s_adaptorConnection, OBJECT_PATH_2); + const auto objectsInterfacesAndProperties = this->m_objectManagerProxy->GetManagedObjects(); ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2)); EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH) .at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME) - .at("action").get(), Eq(DEFAULT_ACTION_VALUE)); + .at("action").template get(), Eq(DEFAULT_ACTION_VALUE)); EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH_2) .at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME) - .at("action").get(), Eq(DEFAULT_ACTION_VALUE)); + .at("action").template get(), Eq(DEFAULT_ACTION_VALUE)); } -TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) +TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) { std::atomic signalReceived{false}; - m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath - , const std::map>& interfacesAndProperties ) + this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::map>& interfacesAndProperties ) { EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); EXPECT_THAT(interfacesAndProperties, SizeIs(1)); @@ -269,16 +267,16 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) signalReceived = true; }; - m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME}); + this->m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME}); ASSERT_TRUE(waitUntil(signalReceived)); } -TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) +TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) { std::atomic signalReceived{false}; - m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath - , const std::map>& interfacesAndProperties ) + this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::map>& interfacesAndProperties ) { EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); #if LIBSYSTEMD_VERSION<=250 @@ -305,16 +303,16 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) signalReceived = true; }; - m_adaptor->emitInterfacesAddedSignal(); + this->m_adaptor->emitInterfacesAddedSignal(); ASSERT_TRUE(waitUntil(signalReceived)); } -TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces) +TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces) { std::atomic signalReceived{false}; - m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath - , const std::vector& interfaces ) + this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::vector& interfaces ) { EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); ASSERT_THAT(interfaces, SizeIs(1)); @@ -322,16 +320,16 @@ TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces) signalReceived = true; }; - m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME}); + this->m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME}); ASSERT_TRUE(waitUntil(signalReceived)); } -TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces) +TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces) { std::atomic signalReceived{false}; - m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath - , const std::vector& interfaces ) + this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::vector& interfaces ) { EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); #if LIBSYSTEMD_VERSION<=250 @@ -344,7 +342,7 @@ TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces) signalReceived = true; }; - m_adaptor->emitInterfacesRemovedSignal(); + this->m_adaptor->emitInterfacesRemovedSignal(); ASSERT_TRUE(waitUntil(signalReceived)); } diff --git a/tests/integrationtests/TestFixture.cpp b/tests/integrationtests/TestFixture.cpp index f4a0cc1..88f8def 100644 --- a/tests/integrationtests/TestFixture.cpp +++ b/tests/integrationtests/TestFixture.cpp @@ -2,7 +2,7 @@ * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2022 Stanislav Angelovic * - * @file TestAdaptor.cpp + * @file TestFixture.cpp * * Created on: May 23, 2020 * Project: sdbus-c++ @@ -28,7 +28,17 @@ namespace sdbus { namespace test { -std::unique_ptr TestFixture::s_adaptorConnection = sdbus::createSystemBusConnection(); -std::unique_ptr TestFixture::s_proxyConnection = sdbus::createSystemBusConnection(); +std::unique_ptr BaseTestFixture::s_adaptorConnection = sdbus::createSystemBusConnection(); +std::unique_ptr BaseTestFixture::s_proxyConnection = sdbus::createSystemBusConnection(); + +#ifndef SDBUS_basu // sd_event integration is not supported in basu-based sdbus-c++ + +std::thread TestFixture::s_adaptorEventLoopThread{}; +std::thread TestFixture::s_proxyEventLoopThread{}; +sd_event *TestFixture::s_adaptorSdEvent{}; +sd_event *TestFixture::s_proxySdEvent{}; +int TestFixture::s_eventExitFd{-1}; + +#endif // SDBUS_basu }} diff --git a/tests/integrationtests/TestFixture.h b/tests/integrationtests/TestFixture.h index f562851..914b782 100644 --- a/tests/integrationtests/TestFixture.h +++ b/tests/integrationtests/TestFixture.h @@ -2,7 +2,7 @@ * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2022 Stanislav Angelovic * - * @file TestAdaptor.h + * @file TestFixture.h * * Created on: Jan 2, 2017 * Project: sdbus-c++ @@ -33,6 +33,10 @@ #include #include +#ifndef SDBUS_basu // sd_event integration is not supported in basu-based sdbus-c++ +#include +#endif // SDBUS_basu +#include #include #include @@ -46,22 +50,17 @@ namespace sdbus { namespace test { -class TestFixture : public ::testing::Test +class BaseTestFixture : public ::testing::Test { public: static void SetUpTestCase() { - s_proxyConnection->enterEventLoopAsync(); s_adaptorConnection->requestName(BUS_NAME); - s_adaptorConnection->enterEventLoopAsync(); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals } static void TearDownTestCase() { s_adaptorConnection->releaseName(BUS_NAME); - s_adaptorConnection->leaveEventLoop(); - s_proxyConnection->leaveEventLoop(); } private: @@ -89,6 +88,108 @@ public: std::unique_ptr m_proxy; }; +struct SdBusCppLoop{}; +struct SdEventLoop{}; + +template +class TestFixture : public BaseTestFixture{}; + +// Fixture working upon internal sdbus-c++ event loop +template <> +class TestFixture : public BaseTestFixture +{ +public: + static void SetUpTestCase() + { + BaseTestFixture::SetUpTestCase(); + s_proxyConnection->enterEventLoopAsync(); + s_adaptorConnection->enterEventLoopAsync(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals + } + + static void TearDownTestCase() + { + BaseTestFixture::TearDownTestCase(); + s_adaptorConnection->leaveEventLoop(); + s_proxyConnection->leaveEventLoop(); + } +}; + +#ifndef SDBUS_basu // sd_event integration is not supported in basu-based sdbus-c++ + +// Fixture working upon attached external sd-event loop +template <> +class TestFixture : public BaseTestFixture +{ +public: + static void SetUpTestCase() + { + sd_event_new(&s_adaptorSdEvent); + sd_event_new(&s_proxySdEvent); + + s_adaptorConnection->attachSdEventLoop(s_adaptorSdEvent); + s_proxyConnection->attachSdEventLoop(s_proxySdEvent); + + s_eventExitFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + auto exitHandler = [](sd_event_source *s, auto...){ return sd_event_exit(sd_event_source_get_event(s), 0); }; + sd_event_add_io(s_adaptorSdEvent, nullptr, s_eventExitFd, EPOLLIN, exitHandler, nullptr); + sd_event_add_io(s_proxySdEvent, nullptr, s_eventExitFd, EPOLLIN, exitHandler, nullptr); + + s_adaptorEventLoopThread = std::thread([]() + { + sd_event_loop(s_adaptorSdEvent); + }); + s_proxyEventLoopThread = std::thread([]() + { + sd_event_loop(s_proxySdEvent); + }); + + BaseTestFixture::SetUpTestCase(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals + } + + static void TearDownTestCase() + { + (void)eventfd_write(s_eventExitFd, 1); + + s_adaptorEventLoopThread.join(); + s_proxyEventLoopThread.join(); + + sd_event_unref(s_adaptorSdEvent); + sd_event_unref(s_proxySdEvent); + close(s_eventExitFd); + + BaseTestFixture::TearDownTestCase(); + } + +private: + static std::thread s_adaptorEventLoopThread; + static std::thread s_proxyEventLoopThread; + static sd_event *s_adaptorSdEvent; + static sd_event *s_proxySdEvent; + static int s_eventExitFd; +}; + +typedef ::testing::Types EventLoopTags; + +#else // SDBUS_basu +typedef ::testing::Types EventLoopTags; +#endif // SDBUS_basu + +TYPED_TEST_SUITE(TestFixture, EventLoopTags); + +template +using SdbusTestObject = TestFixture<_EventLoop>; +TYPED_TEST_SUITE(SdbusTestObject, EventLoopTags); + +template +using AsyncSdbusTestObject = TestFixture<_EventLoop>; +TYPED_TEST_SUITE(AsyncSdbusTestObject, EventLoopTags); + +template +using AConnection = TestFixture<_EventLoop>; +TYPED_TEST_SUITE(AConnection, EventLoopTags); + class TestFixtureWithDirectConnection : public ::testing::Test { private: