feat: add integration for sd-event

This commit is contained in:
Stanislav Angelovic
2023-01-09 00:05:20 +01:00
parent f332f46087
commit 3acd20c2fd
18 changed files with 502 additions and 271 deletions

View File

@ -34,6 +34,8 @@
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
struct sd_event;
namespace sdbus { namespace sdbus {
/********************************************//** /********************************************//**
@ -127,7 +129,7 @@ namespace sdbus {
virtual void releaseName(const std::string& name) = 0; virtual void releaseName(const std::string& name) = 0;
/*! /*!
* @brief Retrieve the unique name of a connection. E.g. ":1.xx" * @brief Retrieves the unique name of a connection. E.g. ":1.xx"
* *
* @throws sdbus::Error in case of failure * @throws sdbus::Error in case of failure
*/ */
@ -305,6 +307,32 @@ namespace sdbus {
*/ */
virtual void addMatch(const std::string& match, message_handler callback, floating_slot_t) = 0; virtual void addMatch(const std::string& match, message_handler callback, floating_slot_t) = 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;
/*! /*!
* @copydoc IConnection::enterEventLoop() * @copydoc IConnection::enterEventLoop()
* *

View File

@ -32,6 +32,7 @@
#include <sdbus-c++/Error.h> #include <sdbus-c++/Error.h>
#include "ScopeGuard.h" #include "ScopeGuard.h"
#include <systemd/sd-bus.h> #include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <unistd.h> #include <unistd.h>
#include <poll.h> #include <poll.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
@ -223,6 +224,102 @@ void Connection::addMatch(const std::string& match, message_handler callback, fl
floatingMatchRules_.push_back(addMatch(match, std::move(callback))); floatingMatchRules_.push_back(addMatch(match, std::move(callback)));
} }
void Connection::attachSdEventLoop(sd_event *event, int priority)
{
// 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);
Slot sdEvent{event, [](void* event){ sd_event_unref((sd_event*)event); }};
// TODO: auto sdEvent = createSdEventSlot(...);
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){ sd_event_source_disable_unref((sd_event_source*)source); }};
r = sd_event_source_set_priority(timeEventSource, priority); // TODO maybe use custom EventSourceSlot with custom type? Then we can use slot.get() here
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);
// TODO: auto sdTimeEventSource = createSdTimeEventSourceSlot(...);
sd_event_source *ioEventSource{};
auto pollData = getEventLoopPollData();
r = sd_event_add_io(event, &ioEventSource, pollData.fd, 0, onSdIoEvent, this);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to add io event", -r);
Slot sdIoEventSource{ioEventSource, [](void* source){ sd_event_source_disable_unref((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);
// TODO: auto sdIoEventSource = createSdIoEventSourceSlot(...);
sdEvent_ = std::make_unique<SdEvent>(SdEvent{std::move(sdEvent), std::move(sdTimeEventSource), std::move(sdIoEventSource)});
}
void Connection::detachSdEventLoop()
{
sdEvent_.reset();
}
sd_event *Connection::getSdEventLoop()
{
return iface_->sd_bus_get_event(bus_.get());
}
int Connection::onSdTimerEvent(sd_event_source */*s*/, uint64_t /*usec*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
connection->processPendingRequest();
return 1;
}
int Connection::onSdIoEvent(sd_event_source */*s*/, int /*fd*/, uint32_t /*revents*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
connection->processPendingRequest();
return 1;
}
int Connection::onSdEventPrepare(sd_event_source */*s*/, void *userdata)
{
auto connection = static_cast<Connection*>(userdata);
assert(connection != nullptr);
auto sdbusPollData = connection->getEventLoopPollData();
// Set poll events to watch out for
auto* sdIoEventSource = static_cast<sd_event_source*>(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 current timeout to the time event source (may be zero if there are messages in the sd-bus queues to be processed)
auto* sdTimeEventSource = static_cast<sd_event_source*>(connection->sdEvent_->sdTimeEventSource_.get());
r = sd_event_source_set_time(sdTimeEventSource, sdbusPollData.timeout_usec);
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);
// TODO: Continue with integration tests
return 1;
}
Slot Connection::addObjectVTable( const std::string& objectPath Slot Connection::addObjectVTable( const std::string& objectPath
, const std::string& interfaceName , const std::string& interfaceName
, const sd_bus_vtable* vtable , const sd_bus_vtable* vtable

View File

@ -87,6 +87,10 @@ namespace sdbus::internal {
[[nodiscard]] Slot addMatch(const std::string& match, message_handler callback) override; [[nodiscard]] Slot addMatch(const std::string& match, message_handler callback) override;
void addMatch(const std::string& match, message_handler callback, floating_slot_t) override; void addMatch(const std::string& match, message_handler callback, floating_slot_t) override;
void attachSdEventLoop(sd_event *event, int priority) override;
void detachSdEventLoop() override;
sd_event *getSdEventLoop() override;
const ISdBus& getSdBusInterface() const override; const ISdBus& getSdBusInterface() const override;
ISdBus& getSdBusInterface() override; ISdBus& getSdBusInterface() override;
@ -141,10 +145,13 @@ namespace sdbus::internal {
void clearEventLoopNotification(int fd) const; void clearEventLoopNotification(int fd) const;
void notifyEventLoopNewTimeout() const override; void notifyEventLoopNewTimeout() const override;
private:
void joinWithEventLoop(); void joinWithEventLoop();
static std::vector</*const */char*> to_strv(const std::vector<std::string>& strings); static std::vector</*const */char*> to_strv(const std::vector<std::string>& strings);
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 onSdEventPrepare(sd_event_source *s, void *userdata);
struct EventFd struct EventFd
{ {
EventFd(); EventFd();
@ -169,6 +176,15 @@ namespace sdbus::internal {
EventFd eventFd_; EventFd eventFd_;
std::atomic<uint64_t> activeTimeout_{}; std::atomic<uint64_t> activeTimeout_{};
std::vector<Slot> floatingMatchRules_; std::vector<Slot> floatingMatchRules_;
// sd-event integration
struct SdEvent
{
Slot sdEvent_;
Slot sdTimeEventSource_;
Slot sdIoEventSource_{};
};
std::unique_ptr<SdEvent> sdEvent_;
}; };
} }

View File

@ -101,6 +101,8 @@ namespace sdbus::internal {
virtual int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) = 0; virtual int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) = 0;
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) = 0; virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) = 0;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) = 0; virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) = 0;
virtual sd_event *sd_bus_get_event(sd_bus *bus) = 0;
}; };
} }

View File

@ -401,4 +401,11 @@ int SdBus::sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label)
return ::sd_bus_creds_get_selinux_context(c, label); return ::sd_bus_creds_get_selinux_context(c, label);
} }
sd_event *SdBus::sd_bus_get_event(sd_bus *bus)
{
std::lock_guard lock(sdbusMutex_);
return ::sd_bus_get_event(bus);
}
} }

View File

@ -94,6 +94,8 @@ public:
virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) override; virtual int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) override;
virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) override; virtual int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **label) override;
virtual sd_event *sd_bus_get_event(sd_bus *bus) override;
private: private:
std::recursive_mutex sdbusMutex_; std::recursive_mutex sdbusMutex_;
}; };

View File

@ -109,7 +109,8 @@ target_link_libraries(sdbus-c++-unit-tests sdbus-c++-objlib GTest::gmock)
add_executable(sdbus-c++-integration-tests ${INTEGRATIONTESTS_SRCS}) add_executable(sdbus-c++-integration-tests ${INTEGRATIONTESTS_SRCS})
target_compile_definitions(sdbus-c++-integration-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION}) target_compile_definitions(sdbus-c++-integration-tests PRIVATE LIBSYSTEMD_VERSION=${LIBSYSTEMD_VERSION})
target_link_libraries(sdbus-c++-integration-tests sdbus-c++ GTest::gmock) # 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)
# Manual performance and stress tests # Manual performance and stress tests
option(ENABLE_PERF_TESTS "Build and install manual performance tests (default OFF)" OFF) option(ENABLE_PERF_TESTS "Build and install manual performance tests (default OFF)" OFF)

View File

@ -49,20 +49,18 @@ using ::testing::SizeIs;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace sdbus::test; using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/ /*-------------------------------------*/
/* -- TEST CASES -- */ /* -- TEST CASES -- */
/*-------------------------------------*/ /*-------------------------------------*/
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) TYPED_TEST(AsyncSdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
{ {
std::chrono::time_point<std::chrono::steady_clock> start; std::chrono::time_point<std::chrono::steady_clock> start;
try try
{ {
std::promise<uint32_t> promise; std::promise<uint32_t> promise;
auto future = promise.get_future(); 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) if (err == nullptr)
promise.set_value(res); promise.set_value(res);
@ -71,7 +69,7 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut)
}); });
start = std::chrono::steady_clock::now(); 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, 1000); // The operation will take 1s, but the timeout is 1us, so we should time out
future.get(); future.get();
FAIL() << "Expected sdbus::Error exception"; 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... // Yeah, this is kinda timing-dependent test, but times should be safe...
std::mutex mtx; std::mutex mtx;
@ -114,7 +112,7 @@ TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
ASSERT_THAT(results, ElementsAre(500, 1000, 1500)); ASSERT_THAT(results, ElementsAre(500, 1000, 1500));
} }
TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods) TYPED_TEST(AsyncSdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
{ {
std::atomic<size_t> resultCount{}; std::atomic<size_t> resultCount{};
std::atomic<bool> invoke{}; std::atomic<bool> invoke{};
@ -144,11 +142,11 @@ TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
ASSERT_THAT(resultCount, Eq(1500)); ASSERT_THAT(resultCount, Eq(1500));
} }
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide) TYPED_TEST(AsyncSdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
{ {
std::promise<uint32_t> promise; std::promise<uint32_t> promise;
auto future = promise.get_future(); 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) if (err == nullptr)
promise.set_value(res); promise.set_value(res);
@ -156,77 +154,77 @@ TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
promise.set_exception(std::make_exception_ptr(*err)); promise.set_exception(std::make_exception_ptr(*err));
}); });
m_proxy->doOperationClientSideAsync(100); this->m_proxy->doOperationClientSideAsync(100);
ASSERT_THAT(future.get(), Eq(100)); ASSERT_THAT(future.get(), 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()); ASSERT_TRUE(call.isPending());
} }
TEST_F(SdbusTestObject, CancelsPendingAsyncCallOnClientSide) TYPED_TEST(AsyncSdbusTestObject, CancelsPendingAsyncCallOnClientSide)
{ {
std::promise<uint32_t> promise; std::promise<uint32_t> promise;
auto future = promise.get_future(); 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(100); auto call = this->m_proxy->doOperationClientSideAsync(100);
call.cancel(); call.cancel();
ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout)); ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout));
} }
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled) TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled)
{ {
std::promise<uint32_t> promise; std::promise<uint32_t> promise;
auto future = promise.get_future(); 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(100); auto call = this->m_proxy->doOperationClientSideAsync(100);
call.cancel(); call.cancel();
ASSERT_FALSE(call.isPending()); ASSERT_FALSE(call.isPending());
} }
TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted) TYPED_TEST(AsyncSdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted)
{ {
std::promise<uint32_t> promise; std::promise<uint32_t> promise;
auto future = promise.get_future(); 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 (void) future.get(); // Wait for the call to finish
ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); })); ASSERT_TRUE(this->waitUntil([&call](){ return !call.isPending(); }));
} }
TEST_F(SdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending) TYPED_TEST(AsyncSdbusTestObject, AnswersThatDefaultConstructedAsyncCallIsNotPending)
{ {
sdbus::PendingAsyncCall call; sdbus::PendingAsyncCall call;
ASSERT_FALSE(call.isPending()); ASSERT_FALSE(call.isPending());
} }
TEST_F(SdbusTestObject, SupportsAsyncCallCopyAssignment) TYPED_TEST(AsyncSdbusTestObject, SupportsAsyncCallCopyAssignment)
{ {
sdbus::PendingAsyncCall call; sdbus::PendingAsyncCall call;
call = m_proxy->doOperationClientSideAsync(100); call = this->m_proxy->doOperationClientSideAsync(100);
ASSERT_TRUE(call.isPending()); ASSERT_TRUE(call.isPending());
} }
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide) TYPED_TEST(AsyncSdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
{ {
std::promise<uint32_t> promise; std::promise<uint32_t> promise;
auto future = promise.get_future(); 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) if (err == nullptr)
promise.set_value(res); promise.set_value(res);
@ -234,7 +232,7 @@ TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
promise.set_exception(std::make_exception_ptr(*err)); promise.set_exception(std::make_exception_ptr(*err));
}); });
m_proxy->doErroneousOperationClientSideAsync(); this->m_proxy->doErroneousOperationClientSideAsync();
ASSERT_THROW(future.get(), sdbus::Error); ASSERT_THROW(future.get(), sdbus::Error);
} }

View File

@ -45,8 +45,6 @@ using ::testing::Eq;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace sdbus::test; using namespace sdbus::test;
using AConnection = TestFixture;
/*-------------------------------------*/ /*-------------------------------------*/
/* -- TEST CASES -- */ /* -- TEST CASES -- */
/*-------------------------------------*/ /*-------------------------------------*/
@ -72,38 +70,38 @@ TEST(AnAdaptor, SupportsMoveSemantics)
static_assert(std::is_move_assignable_v<DummyTestAdaptor>); static_assert(std::is_move_assignable_v<DummyTestAdaptor>);
} }
TEST_F(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule) TYPED_TEST(AConnection, WillCallCallbackHandlerForIncomingMessageMatchingMatchRule)
{ {
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false}; std::atomic<bool> 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) if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true; matchingMessageReceived = true;
}); });
m_adaptor->emitSimpleSignal(); this->m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(matchingMessageReceived)); ASSERT_TRUE(this->waitUntil(matchingMessageReceived));
} }
TEST_F(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot) TYPED_TEST(AConnection, WillUnsubscribeMatchRuleWhenClientDestroysTheAssociatedSlot)
{ {
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false}; std::atomic<bool> 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) if(msg.getPath() == OBJECT_PATH)
matchingMessageReceived = true; matchingMessageReceived = true;
}); });
slot.reset(); slot.reset();
m_adaptor->emitSimpleSignal(); this->m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(matchingMessageReceived, 2s)); ASSERT_FALSE(this->waitUntil(matchingMessageReceived, 2s));
} }
TEST_F(AConnection, CanAddFloatingMatchRule) TYPED_TEST(AConnection, CanAddFloatingMatchRule)
{ {
auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'"; auto matchRule = "sender='" + BUS_NAME + "',path='" + OBJECT_PATH + "'";
std::atomic<bool> matchingMessageReceived{false}; std::atomic<bool> matchingMessageReceived{false};
@ -115,32 +113,32 @@ TEST_F(AConnection, CanAddFloatingMatchRule)
matchingMessageReceived = true; matchingMessageReceived = true;
}; };
con->addMatch(matchRule, std::move(callback), sdbus::floating_slot); con->addMatch(matchRule, std::move(callback), sdbus::floating_slot);
m_adaptor->emitSimpleSignal(); this->m_adaptor->emitSimpleSignal();
[[maybe_unused]] auto gotMessage = waitUntil(matchingMessageReceived, 2s); [[maybe_unused]] auto gotMessage = this->waitUntil(matchingMessageReceived, 2s);
assert(gotMessage); assert(gotMessage);
matchingMessageReceived = false; matchingMessageReceived = false;
con.reset(); con.reset();
m_adaptor->emitSimpleSignal(); this->m_adaptor->emitSimpleSignal();
ASSERT_FALSE(waitUntil(matchingMessageReceived, 2s)); ASSERT_FALSE(this->waitUntil(matchingMessageReceived, 2s));
} }
TEST_F(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule) TYPED_TEST(AConnection, WillNotPassToMatchCallbackMessagesThatDoNotMatchTheRule)
{ {
auto matchRule = "type='signal',interface='" + INTERFACE_NAME + "',member='simpleSignal'"; auto matchRule = "type='signal',interface='" + INTERFACE_NAME + "',member='simpleSignal'";
std::atomic<size_t> numberOfMatchingMessages{}; std::atomic<size_t> numberOfMatchingMessages{};
auto slot = s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg) auto slot = this->s_proxyConnection->addMatch(matchRule, [&](sdbus::Message& msg)
{ {
if(msg.getMemberName() == "simpleSignal") if(msg.getMemberName() == "simpleSignal")
numberOfMatchingMessages++; numberOfMatchingMessages++;
}); });
auto adaptor2 = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH_2); auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
m_adaptor->emitSignalWithMap({}); this->m_adaptor->emitSignalWithMap({});
adaptor2->emitSimpleSignal(); adaptor2->emitSimpleSignal();
m_adaptor->emitSimpleSignal(); this->m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil([&](){ return numberOfMatchingMessages == 2; })); ASSERT_TRUE(this->waitUntil([&](){ return numberOfMatchingMessages == 2; }));
ASSERT_FALSE(waitUntil([&](){ return numberOfMatchingMessages > 2; }, 1s)); ASSERT_FALSE(this->waitUntil([&](){ return numberOfMatchingMessages > 2; }, 1s));
} }

View File

@ -50,59 +50,57 @@ using ::testing::NotNull;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace sdbus::test; using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/ /*-------------------------------------*/
/* -- TEST CASES -- */ /* -- 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)); 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)); 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<0>(resTuple), Eq(UINT32_VALUE));
ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE)); ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE));
} }
TEST_F(SdbusTestObject, CallsMethodsWithStructSuccesfully) TYPED_TEST(SdbusTestObject, CallsMethodsWithStructSuccesfully)
{ {
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{}; sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> a{};
auto vectorRes = m_proxy->getInts16FromStruct(a); auto vectorRes = this->m_proxy->getInts16FromStruct(a);
ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{0})); // because second item is by default initialized to 0 ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{0})); // because second item is by default initialized to 0
sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{ sdbus::Struct<uint8_t, int16_t, double, std::string, std::vector<int16_t>> b{
UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE} 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_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE})); ASSERT_THAT(vectorRes, Eq(std::vector<int16_t>{INT16_VALUE, INT16_VALUE, -INT16_VALUE}));
} }
TEST_F(SdbusTestObject, CallsMethodWithVariantSuccesfully) TYPED_TEST(SdbusTestObject, CallsMethodWithVariantSuccesfully)
{ {
sdbus::Variant v{DOUBLE_VALUE}; sdbus::Variant v{DOUBLE_VALUE};
auto variantRes = m_proxy->processVariant(v); sdbus::Variant variantRes = this->m_proxy->processVariant(v);
ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE))); ASSERT_THAT(variantRes.get<int32_t>(), Eq(static_cast<int32_t>(DOUBLE_VALUE)));
} }
TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully) TYPED_TEST(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
{ {
std::vector<int32_t> x{-2, 0, 2}; std::vector<int32_t> x{-2, 0, 2};
sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true}; sdbus::Struct<sdbus::Variant, sdbus::Variant> y{false, true};
auto mapOfVariants = m_proxy->getMapOfVariants(x, y); std::map<int32_t, sdbus::Variant> mapOfVariants = this->m_proxy->getMapOfVariants(x, y);
decltype(mapOfVariants) res{{-2, false}, {0, false}, {2, true}}; decltype(mapOfVariants) res{{-2, false}, {0, false}, {2, true}};
ASSERT_THAT(mapOfVariants[-2].get<bool>(), Eq(res[-2].get<bool>())); ASSERT_THAT(mapOfVariants[-2].get<bool>(), Eq(res[-2].get<bool>()));
@ -110,69 +108,69 @@ TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully)
ASSERT_THAT(mapOfVariants[2].get<bool>(), Eq(res[2].get<bool>())); ASSERT_THAT(mapOfVariants[2].get<bool>(), Eq(res[2].get<bool>()));
} }
TEST_F(SdbusTestObject, CallsMethodWithStructInStructSuccesfully) TYPED_TEST(SdbusTestObject, CallsMethodWithStructInStructSuccesfully)
{ {
auto val = m_proxy->getStructInStruct(); auto val = this->m_proxy->getStructInStruct();
ASSERT_THAT(val.get<0>(), Eq(STRING_VALUE)); ASSERT_THAT(val.template get<0>(), Eq(STRING_VALUE));
ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_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)); ASSERT_THAT(val, Eq(1 + 2 + 3 + 4));
} }
TEST_F(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully) TYPED_TEST(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully)
{ {
auto val = m_proxy->sumVectorItems({1, 7}, {2, 3}); auto val = this->m_proxy->sumVectorItems({1, 7}, {2, 3});
ASSERT_THAT(val, Eq(1 + 7 + 2 + 3)); ASSERT_THAT(val, Eq(1 + 7 + 2 + 3));
} }
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)); 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)); 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)); 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)); 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_TRUE(this->waitUntil(this->m_adaptor->m_wasMultiplyCalled));
ASSERT_THAT(m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE)); 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, 20); // The operation will take 20ms, but the timeout is 500ms, so we are fine
ASSERT_THAT(res, Eq(20)); ASSERT_THAT(res, Eq(20));
} }
TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut) TYPED_TEST(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut)
{ {
auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now();
try 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, 1000); // The operation will take 1s, but the timeout is 1us, so we should time out
FAIL() << "Expected sdbus::Error exception"; FAIL() << "Expected sdbus::Error exception";
} }
catch (const sdbus::Error& e) catch (const sdbus::Error& e)
@ -188,11 +186,11 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut)
} }
} }
TEST_F(SdbusTestObject, CallsMethodThatThrowsError) TYPED_TEST(SdbusTestObject, CallsMethodThatThrowsError)
{ {
try try
{ {
m_proxy->throwError(); this->m_proxy->throwError();
FAIL() << "Expected sdbus::Error exception"; FAIL() << "Expected sdbus::Error exception";
} }
catch (const sdbus::Error& e) catch (const sdbus::Error& e)
@ -206,74 +204,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(this->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); TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH);
ASSERT_THROW(proxy.getInt(), sdbus::Error); ASSERT_THROW(proxy.getInt(), sdbus::Error);
} }
TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject) TYPED_TEST(SdbusTestObject, FailsCallingMethodOnNonexistentObject)
{ {
TestProxy proxy(BUS_NAME, "/sdbuscpp/path/that/does/not/exist"); TestProxy proxy(BUS_NAME, "/sdbuscpp/path/that/does/not/exist");
ASSERT_THROW(proxy.getInt(), sdbus::Error); 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(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap)); ASSERT_TRUE(this->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(this->m_adaptor->m_methodCallMsg, NotNull());
ASSERT_THAT(m_adaptor->m_methodCallMemberName, Eq("doOperation")); 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(this->m_adaptor->m_methodCallMsg, NotNull());
ASSERT_THAT(m_adaptor->m_methodCallMemberName, Eq("doOperationAsync")); ASSERT_THAT(this->m_adaptor->m_methodCallMemberName, Eq("doOperationAsync"));
} }
#if LIBSYSTEMD_VERSION>=240 #if LIBSYSTEMD_VERSION>=240
TEST_F(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239) TYPED_TEST(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239)
{ {
s_adaptorConnection->setMethodCallTimeout(5000000); this->s_adaptorConnection->setMethodCallTimeout(5000000);
ASSERT_THAT(s_adaptorConnection->getMethodCallTimeout(), Eq(5000000)); ASSERT_THAT(this->s_adaptorConnection->getMethodCallTimeout(), Eq(5000000));
} }
#else #else
TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240) TYPED_TEST(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240)
{ {
ASSERT_THROW(s_adaptorConnection->setMethodCallTimeout(5000000), sdbus::Error); ASSERT_THROW(this->s_adaptorConnection->setMethodCallTimeout(5000000), sdbus::Error);
ASSERT_THROW(s_adaptorConnection->getMethodCallTimeout(), sdbus::Error); ASSERT_THROW(this->s_adaptorConnection->getMethodCallTimeout(), sdbus::Error);
} }
#endif #endif
TEST_F(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread) TYPED_TEST(SdbusTestObject, CanCallMethodSynchronouslyWithoutAnEventLoopThread)
{ {
auto proxy = std::make_unique<TestProxy>(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread); auto proxy = std::make_unique<TestProxy>(BUS_NAME, OBJECT_PATH, sdbus::dont_run_event_loop_thread);

View File

@ -51,35 +51,33 @@ using ::testing::IsEmpty;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace sdbus::test; using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/ /*-------------------------------------*/
/* -- TEST CASES -- */ /* -- 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; 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(this->m_adaptor->m_propertySetMsg, NotNull());
ASSERT_THAT(m_adaptor->m_propertySetSender, Not(IsEmpty())); ASSERT_THAT(this->m_adaptor->m_propertySetSender, Not(IsEmpty()));
} }

View File

@ -44,32 +44,30 @@ using ::testing::NotNull;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace sdbus::test; using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/ /*-------------------------------------*/
/* -- TEST CASES -- */ /* -- 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(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
} }
TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully) TYPED_TEST(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully)
{ {
auto proxy1 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); auto proxy2 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
m_adaptor->emitSimpleSignal(); this->m_adaptor->emitSimpleSignal();
ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal)); ASSERT_TRUE(this->waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal)); ASSERT_TRUE(this->waitUntil(proxy2->m_gotSimpleSignal));
} }
TEST_F(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName) TYPED_TEST(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName)
{ {
auto otherBusName = BUS_NAME + "2"; auto otherBusName = BUS_NAME + "2";
auto connection2 = sdbus::createConnection(otherBusName); auto connection2 = sdbus::createConnection(otherBusName);
@ -77,93 +75,93 @@ TEST_F(SdbusTestObject, ProxyDoesNotReceiveSignalFromOtherBusName)
adaptor2->emitSimpleSignal(); adaptor2->emitSimpleSignal();
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s)); ASSERT_FALSE(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 2s));
} }
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_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithMap));
ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("zero")); ASSERT_THAT(this->m_proxy->m_mapFromSignal[0], Eq("zero"));
ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one")); ASSERT_THAT(this->m_proxy->m_mapFromSignal[1], Eq("one"));
} }
TEST_F(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully) TYPED_TEST(SdbusTestObject, EmitsSignalWithLargeMapSuccesfully)
{ {
std::map<int32_t, std::string> largeMap; std::map<int32_t, std::string> largeMap;
for (int32_t i = 0; i < 20'000; ++i) for (int32_t i = 0; i < 20'000; ++i)
largeMap.emplace(i, "This is string nr. " + std::to_string(i+1)); 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_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithMap));
ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("This is string nr. 1")); ASSERT_THAT(this->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_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; double d = 3.14;
m_adaptor->emitSignalWithVariant(d); this->m_adaptor->emitSignalWithVariant(d);
ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithVariant)); ASSERT_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithVariant));
ASSERT_THAT(m_proxy->m_variantFromSignal, DoubleEq(d)); 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_TRUE(this->waitUntil(this->m_proxy->m_gotSignalWithSignature));
ASSERT_THAT(m_proxy->m_signatureFromSignal["platform"], Eq("av")); 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); this->waitUntil(this->m_proxy->m_gotSimpleSignal);
ASSERT_THAT(m_proxy->m_signalMsg, NotNull()); ASSERT_THAT(this->m_proxy->m_signalMsg, NotNull());
ASSERT_THAT(m_proxy->m_signalMemberName, Eq("simpleSignal")); 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(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 2s));
} }
TEST_F(SdbusTestObject, UnregistersSignalHandlerForSomeProxies) TYPED_TEST(SdbusTestObject, UnregistersSignalHandlerForSomeProxies)
{ {
auto proxy1 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); auto proxy1 = std::make_unique<TestProxy>(*this->s_adaptorConnection, BUS_NAME, OBJECT_PATH);
auto proxy2 = std::make_unique<TestProxy>(*s_adaptorConnection, BUS_NAME, OBJECT_PATH); auto proxy2 = std::make_unique<TestProxy>(*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(this->waitUntil(proxy1->m_gotSimpleSignal));
ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal)); ASSERT_TRUE(this->waitUntil(proxy2->m_gotSimpleSignal));
ASSERT_FALSE(waitUntil(m_proxy->m_gotSimpleSignal, 2s)); ASSERT_FALSE(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 2s));
} }
TEST_F(SdbusTestObject, ReRegistersSignalHandler) TYPED_TEST(SdbusTestObject, ReRegistersSignalHandler)
{ {
// unregister simple-signal handler // 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(this->waitUntil(this->m_proxy->m_gotSimpleSignal, 2s));
// re-register simple-signal handler // 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(this->waitUntil(this->m_proxy->m_gotSimpleSignal));
} }

View File

@ -48,18 +48,16 @@ using ::testing::SizeIs;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using namespace sdbus::test; using namespace sdbus::test;
using SdbusTestObject = TestFixture;
/*-------------------------------------*/ /*-------------------------------------*/
/* -- TEST CASES -- */ /* -- 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 /etc/machine-id does not exist in your system (which is very likely because you have // If /etc/machine-id does not exist in your system (which is very likely because you have
// a non-systemd Linux), org.freedesktop.DBus.Peer.GetMachineId() will not work. To solve // a non-systemd Linux), org.freedesktop.DBus.Peer.GetMachineId() will not work. To solve
@ -68,45 +66,45 @@ TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface)
if (::access("/etc/machine-id", F_OK) == -1) if (::access("/etc/machine-id", F_OK) == -1)
GTEST_SKIP() << "/etc/machine-id file does not exist, GetMachineId() will not work"; GTEST_SKIP() << "/etc/machine-id file does 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 // 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<std::string>(), Eq(DEFAULT_STATE_VALUE)); ASSERT_THAT(this->m_proxy->Get(INTERFACE_NAME, "state").template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
} }
TEST_F(SdbusTestObject, SetsPropertyViaPropertiesInterface) TYPED_TEST(SdbusTestObject, SetsPropertyViaPropertiesInterface)
{ {
uint32_t newActionValue = 2345; uint32_t newActionValue = 2345;
m_proxy->Set(INTERFACE_NAME, "action", newActionValue); this->m_proxy->Set(INTERFACE_NAME, "action", newActionValue);
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)); ASSERT_THAT(properties, SizeIs(3));
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE)); EXPECT_THAT(properties.at("state").template get<std::string>(), Eq(DEFAULT_STATE_VALUE));
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE)); EXPECT_THAT(properties.at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE)); EXPECT_THAT(properties.at("blocking").template get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
} }
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties) TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
{ {
std::atomic<bool> signalReceived{false}; std::atomic<bool> signalReceived{false};
m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties , const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& /*invalidatedProperties*/ ) , const std::vector<std::string>& /*invalidatedProperties*/ )
{ {
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME)); EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
EXPECT_THAT(changedProperties, SizeIs(1)); EXPECT_THAT(changedProperties, SizeIs(1));
@ -114,19 +112,19 @@ TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties)
signalReceived = true; signalReceived = true;
}; };
m_proxy->blocking(!DEFAULT_BLOCKING_VALUE); this->m_proxy->blocking(!DEFAULT_BLOCKING_VALUE);
m_proxy->action(DEFAULT_ACTION_VALUE*2); this->m_proxy->action(DEFAULT_ACTION_VALUE*2);
m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"}); this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"});
ASSERT_TRUE(waitUntil(signalReceived)); ASSERT_TRUE(this->waitUntil(signalReceived));
} }
TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) TYPED_TEST(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
{ {
std::atomic<bool> signalReceived{false}; std::atomic<bool> signalReceived{false};
m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName this->m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties , const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties ) , const std::vector<std::string>& invalidatedProperties )
{ {
EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME)); EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
EXPECT_THAT(changedProperties, SizeIs(1)); EXPECT_THAT(changedProperties, SizeIs(1));
@ -136,38 +134,38 @@ TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties)
signalReceived = true; signalReceived = true;
}; };
m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME); this->m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME);
ASSERT_TRUE(waitUntil(signalReceived)); ASSERT_TRUE(this->waitUntil(signalReceived));
} }
TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects) TYPED_TEST(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects)
{ {
m_adaptor.reset(); this->m_adaptor.reset();
const auto objectsInterfacesAndProperties = m_objectManagerProxy->GetManagedObjects(); const auto objectsInterfacesAndProperties = this->m_objectManagerProxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0)); ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0));
} }
TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully) TYPED_TEST(SdbusTestObject, GetsManagedObjectsSuccessfully)
{ {
auto adaptor2 = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH_2); auto adaptor2 = std::make_unique<TestAdaptor>(*this->s_adaptorConnection, OBJECT_PATH_2);
const auto objectsInterfacesAndProperties = m_objectManagerProxy->GetManagedObjects(); const auto objectsInterfacesAndProperties = this->m_objectManagerProxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2)); ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH) EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH)
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME) .at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE)); .at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH_2) EXPECT_THAT(objectsInterfacesAndProperties.at(OBJECT_PATH_2)
.at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME) .at(org::sdbuscpp::integrationtests_adaptor::INTERFACE_NAME)
.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE)); .at("action").template get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
} }
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
{ {
std::atomic<bool> signalReceived{false}; std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties ) , const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{ {
EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
EXPECT_THAT(interfacesAndProperties, SizeIs(1)); EXPECT_THAT(interfacesAndProperties, SizeIs(1));
@ -189,16 +187,16 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces)
signalReceived = true; signalReceived = true;
}; };
m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME}); this->m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME});
ASSERT_TRUE(waitUntil(signalReceived)); ASSERT_TRUE(this->waitUntil(signalReceived));
} }
TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) TYPED_TEST(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
{ {
std::atomic<bool> signalReceived{false}; std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath this->m_objectManagerProxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties ) , const std::map<std::string, std::map<std::string, sdbus::Variant>>& interfacesAndProperties )
{ {
EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
#if LIBSYSTEMD_VERSION<=250 #if LIBSYSTEMD_VERSION<=250
@ -225,16 +223,16 @@ TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces)
signalReceived = true; signalReceived = true;
}; };
m_adaptor->emitInterfacesAddedSignal(); this->m_adaptor->emitInterfacesAddedSignal();
ASSERT_TRUE(waitUntil(signalReceived)); ASSERT_TRUE(this->waitUntil(signalReceived));
} }
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces) TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
{ {
std::atomic<bool> signalReceived{false}; std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces ) , const std::vector<std::string>& interfaces )
{ {
EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
ASSERT_THAT(interfaces, SizeIs(1)); ASSERT_THAT(interfaces, SizeIs(1));
@ -242,16 +240,16 @@ TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces)
signalReceived = true; signalReceived = true;
}; };
m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME}); this->m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME});
ASSERT_TRUE(waitUntil(signalReceived)); ASSERT_TRUE(this->waitUntil(signalReceived));
} }
TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces) TYPED_TEST(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
{ {
std::atomic<bool> signalReceived{false}; std::atomic<bool> signalReceived{false};
m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath this->m_objectManagerProxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath
, const std::vector<std::string>& interfaces ) , const std::vector<std::string>& interfaces )
{ {
EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); EXPECT_THAT(objectPath, Eq(OBJECT_PATH));
#if LIBSYSTEMD_VERSION<=250 #if LIBSYSTEMD_VERSION<=250
@ -264,7 +262,7 @@ TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces)
signalReceived = true; signalReceived = true;
}; };
m_adaptor->emitInterfacesRemovedSignal(); this->m_adaptor->emitInterfacesRemovedSignal();
ASSERT_TRUE(waitUntil(signalReceived)); ASSERT_TRUE(this->waitUntil(signalReceived));
} }

View File

@ -2,7 +2,7 @@
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com> * (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* *
* @file TestAdaptor.cpp * @file TestFixture.cpp
* *
* Created on: May 23, 2020 * Created on: May 23, 2020
* Project: sdbus-c++ * Project: sdbus-c++
@ -27,8 +27,12 @@
#include "TestFixture.h" #include "TestFixture.h"
namespace sdbus { namespace test { namespace sdbus { namespace test {
std::unique_ptr<sdbus::IConnection> TestFixture::s_adaptorConnection = sdbus::createSystemBusConnection(); std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_adaptorConnection = sdbus::createSystemBusConnection();
std::unique_ptr<sdbus::IConnection> TestFixture::s_proxyConnection = sdbus::createSystemBusConnection(); std::unique_ptr<sdbus::IConnection> BaseTestFixture::s_proxyConnection = sdbus::createSystemBusConnection();
std::thread TestFixture<SdEventLoop>::s_eventLoopThread{};
sd_event *TestFixture<SdEventLoop>::s_sdEvent{};
int TestFixture<SdEventLoop>::s_eventExitFd{-1};
}} }}

View File

@ -2,7 +2,7 @@
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com> * (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* *
* @file TestAdaptor.h * @file TestFixture.h
* *
* Created on: Jan 2, 2017 * Created on: Jan 2, 2017
* Project: sdbus-c++ * Project: sdbus-c++
@ -33,6 +33,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <systemd/sd-event.h>
#include <sys/eventfd.h>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
@ -41,22 +43,17 @@
namespace sdbus { namespace test { namespace sdbus { namespace test {
class TestFixture : public ::testing::Test class BaseTestFixture : public ::testing::Test
{ {
public: public:
static void SetUpTestCase() static void SetUpTestCase()
{ {
s_proxyConnection->enterEventLoopAsync();
s_adaptorConnection->requestName(BUS_NAME); 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() static void TearDownTestCase()
{ {
s_adaptorConnection->releaseName(BUS_NAME); s_adaptorConnection->releaseName(BUS_NAME);
s_adaptorConnection->leaveEventLoop();
s_proxyConnection->leaveEventLoop();
} }
template <typename _Fnc> template <typename _Fnc>
@ -84,17 +81,17 @@ public:
private: private:
void SetUp() override void SetUp() override
{ {
m_objectManagerProxy = std::make_unique<ObjectManagerTestProxy>(*s_proxyConnection, BUS_NAME, MANAGER_PATH); m_objectManagerProxy = std::make_unique<ObjectManagerTestProxy>(*s_proxyConnection, BUS_NAME, MANAGER_PATH);
m_proxy = std::make_unique<TestProxy>(*s_proxyConnection, BUS_NAME, OBJECT_PATH); m_proxy = std::make_unique<TestProxy>(*s_proxyConnection, BUS_NAME, OBJECT_PATH);
m_objectManagerAdaptor = std::make_unique<ObjectManagerTestAdaptor>(*s_adaptorConnection, MANAGER_PATH); m_objectManagerAdaptor = std::make_unique<ObjectManagerTestAdaptor>(*s_adaptorConnection, MANAGER_PATH);
m_adaptor = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH); m_adaptor = std::make_unique<TestAdaptor>(*s_adaptorConnection, OBJECT_PATH);
} }
void TearDown() override void TearDown() override
{ {
m_proxy.reset(); m_proxy.reset();
m_adaptor.reset(); m_adaptor.reset();
} }
public: public:
@ -106,6 +103,93 @@ public:
std::unique_ptr<TestProxy> m_proxy; std::unique_ptr<TestProxy> m_proxy;
}; };
struct SdBusCppLoop{};
struct SdEventLoop{};
template <typename _EventLoop>
class TestFixture : public BaseTestFixture{};
// Fixture working upon internal sdbus-c++ event loop
template <>
class TestFixture<SdBusCppLoop> : 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();
}
};
// Fixture working upon attached external sd-event loop
template <>
class TestFixture<SdEventLoop> : public BaseTestFixture
{
public:
static void SetUpTestCase()
{
sd_event_new(&s_sdEvent);
s_proxyConnection->attachSdEventLoop(s_sdEvent);
s_adaptorConnection->attachSdEventLoop(s_sdEvent);
s_eventExitFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
// No callback means that the event loop will exit when this event source triggers
sd_event_add_io(s_sdEvent, nullptr, s_eventExitFd, EPOLLIN, nullptr, NULL);
s_eventLoopThread = std::thread([]()
{
sd_event_loop(s_sdEvent);
});
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()
{
uint64_t value = 1;
write(s_eventExitFd, &value, sizeof(value));
s_eventLoopThread.join();
sd_event_unref(s_sdEvent);
close(s_eventExitFd);
BaseTestFixture::TearDownTestCase();
}
private:
static std::thread s_eventLoopThread;
static sd_event *s_sdEvent;
static int s_eventExitFd;
};
typedef ::testing::Types<SdBusCppLoop, SdEventLoop> EventLoopTags;
TYPED_TEST_SUITE(TestFixture, EventLoopTags);
template <typename _EventLoop>
using SdbusTestObject = TestFixture<_EventLoop>;
TYPED_TEST_SUITE(SdbusTestObject, EventLoopTags);
template <typename _EventLoop>
using AsyncSdbusTestObject = TestFixture<_EventLoop>;
TYPED_TEST_SUITE(AsyncSdbusTestObject, EventLoopTags);
template <typename _EventLoop>
using AConnection = TestFixture<_EventLoop>;
TYPED_TEST_SUITE(AConnection, EventLoopTags);
}} }}
#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */ #endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */

View File

@ -2,7 +2,7 @@
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com> * (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* *
* @file TestAdaptor.cpp * @file TestProxy.cpp
* *
* Created on: May 23, 2020 * Created on: May 23, 2020
* Project: sdbus-c++ * Project: sdbus-c++

View File

@ -2,7 +2,7 @@
* (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
* (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com> * (C) 2016 - 2022 Stanislav Angelovic <stanislav.angelovic@protonmail.com>
* *
* @file TestAdaptor.h * @file TestProxy.h
* *
* Created on: Jan 2, 2017 * Created on: Jan 2, 2017
* Project: sdbus-c++ * Project: sdbus-c++

View File

@ -92,6 +92,8 @@ public:
MOCK_METHOD2(sd_bus_creds_get_egid, int(sd_bus_creds *, gid_t *)); MOCK_METHOD2(sd_bus_creds_get_egid, int(sd_bus_creds *, gid_t *));
MOCK_METHOD2(sd_bus_creds_get_supplementary_gids, int(sd_bus_creds *, const gid_t **)); MOCK_METHOD2(sd_bus_creds_get_supplementary_gids, int(sd_bus_creds *, const gid_t **));
MOCK_METHOD2(sd_bus_creds_get_selinux_context, int(sd_bus_creds *, const char **)); MOCK_METHOD2(sd_bus_creds_get_selinux_context, int(sd_bus_creds *, const char **));
MOCK_METHOD1(sd_bus_get_event, sd_event *(sd_bus *bus));
}; };
#endif //SDBUS_CXX_SDBUS_MOCK_H #endif //SDBUS_CXX_SDBUS_MOCK_H