This commit is contained in:
sangelovic
2019-01-31 21:42:37 +01:00
parent dd0a975243
commit 9292f293ec
9 changed files with 354 additions and 125 deletions

View File

@@ -13,7 +13,9 @@ include(GNUInstallDirs) # Installation directories for `install` command and pkg
#-------------------------------
find_package(PkgConfig REQUIRED)
pkg_check_modules(SYSTEMD REQUIRED libsystemd>=236)
#pkg_check_modules(SYSTEMD REQUIRED libsystemd>=236)
set(CMAKE_CXX_FLAGS "-O0 -g")
#-------------------------------
# SOURCE FILES CONFIGURATION
@@ -80,7 +82,7 @@ set(SDBUSCPP_VERSION "${PROJECT_VERSION}")
# We are building in two steps: first objects, then link them into a library,
# and that's because we need object files since unit tests link against them.
add_library(sdbuscppobjects OBJECT ${SDBUSCPP_SRCS})
target_include_directories(sdbuscppobjects PUBLIC ${SYSTEMD_INCLUDE_DIRS})
#target_include_directories(sdbuscppobjects PUBLIC ${SYSTEMD_INCLUDE_DIRS})
target_compile_definitions(sdbuscppobjects PRIVATE BUILDLIB=1)
set_target_properties(sdbuscppobjects PROPERTIES POSITION_INDEPENDENT_CODE ON)
@@ -91,7 +93,7 @@ set_target_properties(sdbus-c++
VERSION "${SDBUSCPP_VERSION}"
SOVERSION "${SDBUSCPP_VERSION_MAJOR}"
OUTPUT_NAME "sdbus-c++")
target_link_libraries(sdbus-c++ ${SYSTEMD_LIBRARIES})
target_link_libraries(sdbus-c++ -L/home/aeywalee/data/repos/systemd/.libs/ -lsystemd)
#----------------------------------
# INSTALLATION

View File

@@ -79,7 +79,7 @@ void Connection::enterProcessingLoop()
if (!success)
break; // Exit processing loop
if (success.asyncMsgsToProcess)
processAsynchronousMessages();
processUserRequests();
}
loopThreadId_ = std::thread::id{};
@@ -122,10 +122,10 @@ void Connection::removeObjectVTable(void* vtableHandle)
sd_bus_slot_unref((sd_bus_slot *)vtableHandle);
}
sdbus::MethodCall Connection::createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const
MethodCall Connection::createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const
{
sd_bus_message *sdbusMsg{};
@@ -145,44 +145,9 @@ sdbus::MethodCall Connection::createMethodCall( const std::string& destination
return MethodCall(sdbusMsg);
}
sdbus::MethodReply Connection::callMethod(const MethodCall& message)
{
std::thread::id loopThreadId = loopThreadId_;
// Is the loop not yet on? => Go make synchronous call
while (loopThreadId == std::thread::id{})
{
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
if (!loopMutex_.try_lock())
continue;
// Synchronous call
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
return message.send();
}
// Is the loop on and we are in the same thread? => Go for synchronous call
if (loopThreadId == std::this_thread::get_id())
{
assert(!loopMutex_.try_lock());
return message.send(); // Synchronous call
}
// We are in a different thread than the loop thread => Asynchronous call
UserRequest request{message, Message::Type::METHOD_CALL, {}, Message::Type::METHOD_REPLY};
auto future = request.ret.get_future();
{
std::lock_guard<std::mutex> guard(userRequestsMutex_);
userRequests_.push(request);
}
// Wait for the reply from the loop thread
auto reply = future.get();
return *static_cast<const MethodReply*>(&reply);
}
sdbus::Signal Connection::createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const
Signal Connection::createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const
{
sd_bus_message *sdbusSignal{};
@@ -207,14 +172,61 @@ void* Connection::registerSignalHandler( const std::string& objectPath
, sd_bus_message_handler_t callback
, void* userData )
{
sd_bus_slot *slot{};
auto registerSignalHandler = [this]( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName
, sd_bus_message_handler_t callback
, void* userData )
{
sd_bus_slot *slot{};
auto filter = composeSignalMatchFilter(objectPath, interfaceName, signalName);
auto r = sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
auto filter = composeSignalMatchFilter(objectPath, interfaceName, signalName);
auto r = sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
return slot;
return slot;
};
std::thread::id loopThreadId = loopThreadId_;
// Is the loop not yet on? => Go make synchronous call
while (loopThreadId == std::thread::id{})
{
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
if (!loopMutex_.try_lock())
continue;
// Synchronous call
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
return registerSignalHandler(objectPath, interfaceName, signalName, callback, userData);
}
// Is the loop on and we are in the same thread? => Go for synchronous call
if (loopThreadId == std::this_thread::get_id())
{
assert(!loopMutex_.try_lock());
return registerSignalHandler(objectPath, interfaceName, signalName, callback, userData);
}
// We are in a different thread than the loop thread => Asynchronous call
std::promise<void*> result;
auto future = result.get_future();
queueUserRequest([registerSignalHandler, objectPath, interfaceName, signalName, callback, userData, &result]()
{
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
void* slot = registerSignalHandler(objectPath, interfaceName, signalName, callback, userData);
result.set_value(slot);
onSdbusError.dismiss();
});
auto request = std::make_unique<SignalRegistrationRequest>();
request->registerSignalHandler = registerSignalHandler;
auto future = request->result.get_future();
queueUserRequest(std::move(request));
// Wait for the reply from the loop thread
return future.get();
}
void Connection::unregisterSignalHandler(void* handlerCookie)
@@ -222,11 +234,129 @@ void Connection::unregisterSignalHandler(void* handlerCookie)
sd_bus_slot_unref((sd_bus_slot *)handlerCookie);
}
void Connection::sendReplyAsynchronously(const sdbus::MethodReply& reply)
//class AsyncExecutor
//ifPossibleExecuteSync()
MethodReply Connection::callMethod(const MethodCall& message)
{
std::lock_guard<std::mutex> guard(mutex_);
asyncReplies_.push(reply);
notifyProcessingLoop();
//ifPossibleExecuteSync().otherwiseExecuteAsync();
std::thread::id loopThreadId = loopThreadId_;
// Is the loop not yet on? => Go make synchronous call
while (loopThreadId == std::thread::id{})
{
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
if (!loopMutex_.try_lock())
continue;
// Synchronous call
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
return message.send();
}
// Is the loop on and we are in the same thread? => Go for synchronous call
if (loopThreadId == std::this_thread::get_id())
{
assert(!loopMutex_.try_lock());
return message.send(); // Synchronous call
}
// We are in a different thread than the loop thread => Asynchronous call
auto request = std::make_unique<MethodCallRequest>();
request->msg = message;
auto future = request->result.get_future();
queueUserRequest(std::move(request));
// Wait for the reply from the loop thread
return future.get();
}
void Connection::callMethod(const AsyncMethodCall& message, void* callback, void* userData)
{
std::thread::id loopThreadId = loopThreadId_;
// Is the loop not yet on? => Go make synchronous call
while (loopThreadId == std::thread::id{})
{
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
if (!loopMutex_.try_lock())
continue;
// Synchronous call
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
return message.send(callback, userData);
}
// Is the loop on and we are in the same thread? => Go for synchronous call
if (loopThreadId == std::this_thread::get_id())
{
assert(!loopMutex_.try_lock());
return message.send(callback, userData); // Synchronous call
}
// We are in a different thread than the loop thread => Asynchronous call
auto request = std::make_unique<AsyncMethodCallRequest>();
request->msg = message;
request->callback = callback;
request->userData = userData;
queueUserRequest(std::move(request));
}
void Connection::sendMethodReply(const MethodReply& message)
{
std::thread::id loopThreadId = loopThreadId_;
// Is the loop not yet on? => Go make synchronous call
while (loopThreadId == std::thread::id{})
{
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
if (!loopMutex_.try_lock())
continue;
// Synchronous call
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
return message.send();
}
// Is the loop on and we are in the same thread? => Go for synchronous call
if (loopThreadId == std::this_thread::get_id())
{
assert(!loopMutex_.try_lock());
return message.send(); // Synchronous call
}
// We are in a different thread than the loop thread => Asynchronous call
auto request = std::make_unique<MethodReplyRequest>();
request->msg = message;
queueUserRequest(std::move(request));
}
void Connection::emitSignal(const Signal& message)
{
std::thread::id loopThreadId = loopThreadId_;
// Is the loop not yet on? => Go make synchronous call
while (loopThreadId == std::thread::id{})
{
// Did the loop begin in the meantime? Or try_lock() failed spuriously?
if (!loopMutex_.try_lock())
continue;
// Synchronous call
std::lock_guard<std::mutex> guard(loopMutex_, std::adopt_lock);
return message.send();
}
// Is the loop on and we are in the same thread? => Go for synchronous call
if (loopThreadId == std::this_thread::get_id())
{
assert(!loopMutex_.try_lock());
return message.send(); // Synchronous call
}
// We are in a different thread than the loop thread => Asynchronous call
auto request = std::make_unique<SignalEmissionRequest>();
request->msg = message;
queueUserRequest(std::move(request));
}
std::unique_ptr<sdbus::internal::IConnection> Connection::clone() const
@@ -315,14 +445,23 @@ bool Connection::processPendingRequest()
return r > 0;
}
void Connection::processAsynchronousMessages()
void Connection::queueUserRequest(std::unique_ptr<IUserRequest>&& request)
{
std::lock_guard<std::mutex> guard(mutex_);
while (!asyncReplies_.empty())
{
auto reply = asyncReplies_.front();
asyncReplies_.pop();
reply.send();
std::lock_guard<std::mutex> guard(userRequestsMutex_);
userRequests_.push(std::move(request));
}
notifyProcessingLoop();
}
void Connection::processUserRequests()
{
std::lock_guard<std::mutex> guard(userRequestsMutex_);
while (!userRequests_.empty())
{
auto& reply = userRequests_.front();
reply->process();
userRequests_.pop();
}
}

View File

@@ -29,6 +29,7 @@
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/Message.h>
#include "IConnection.h"
#include "ScopeGuard.h"
#include <systemd/sd-bus.h>
#include <memory>
#include <thread>
@@ -51,7 +52,7 @@ namespace sdbus { namespace internal {
};
Connection(BusType type);
~Connection();
~Connection() override;
void requestName(const std::string& name) override;
void releaseName(const std::string& name) override;
@@ -65,13 +66,13 @@ namespace sdbus { namespace internal {
, void* userData ) override;
void removeObjectVTable(void* vtableHandle) override;
sdbus::MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const override;
sdbus::Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const override;
MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const override;
Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const override;
void* registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
@@ -80,8 +81,10 @@ namespace sdbus { namespace internal {
, void* userData ) override;
void unregisterSignalHandler(void* handlerCookie) override;
MethodReply callMethod(const MethodCall& message);
void sendReplyAsynchronously(const sdbus::MethodReply& reply) override;
MethodReply callMethod(const MethodCall& message) override;
void callMethod(const AsyncMethodCall& message, void* callback, void* userData) override;
void sendMethodReply(const MethodReply& message) override;
void emitSignal(const Signal& message) override;
std::unique_ptr<sdbus::internal::IConnection> clone() const override;
@@ -95,12 +98,106 @@ namespace sdbus { namespace internal {
return msgsToProcess || asyncMsgsToProcess;
}
};
// TODO move down
struct IUserRequest
{
virtual void process() = 0;
virtual ~IUserRequest() = default;
};
struct MethodCallRequest : IUserRequest
{
MethodCall msg;
std::promise<MethodReply> result;
void process() override
{
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
auto reply = msg.send();
result.set_value(std::move(reply));
onSdbusError.dismiss();
}
};
struct AsyncMethodCallRequest : IUserRequest
{
AsyncMethodCall msg;
void* callback;
void* userData;
// TODO: Catch exception and store to promise?
void process() override
{
msg.send(callback, userData);
}
};
struct MethodReplyRequest : IUserRequest
{
MethodReply msg;
// TODO: Catch exception and store to promise?
void process() override
{
msg.send();
}
};
struct SignalEmissionRequest : IUserRequest
{
Signal msg;
// TODO: Catch exception and store to promise?
void process() override
{
msg.send();
}
};
struct SignalRegistrationRequest : IUserRequest
{
std::function<void*()> registerSignalHandler;
std::promise<void*> result;
void process() override
{
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
assert(registerSignalHandler);
void* slot = registerSignalHandler();
result.set_value(slot);
onSdbusError.dismiss();
}
};
struct SignalUnregistrationRequest : IUserRequest
{
std::function<void()> unregisterSignalHandler;
std::promise<void> result;
void process() override
{
SCOPE_EXIT_NAMED(onSdbusError){ result.set_exception(std::current_exception()); };
assert(unregisterSignalHandler);
unregisterSignalHandler();
result.set_value();
onSdbusError.dismiss();
}
};
static sd_bus* openBus(Connection::BusType type);
static void finishHandshake(sd_bus* bus);
static int createLoopNotificationDescriptor();
static void closeLoopNotificationDescriptor(int fd);
bool processPendingRequest();
void processAsynchronousMessages();
void queueUserRequest(std::unique_ptr<IUserRequest>&& request);
void processUserRequests();
WaitResult waitForNextRequest();
static std::string composeSignalMatchFilter( const std::string& objectPath
, const std::string& interfaceName
@@ -115,20 +212,7 @@ namespace sdbus { namespace internal {
std::atomic<std::thread::id> loopThreadId_;
std::mutex loopMutex_;
//std::queue<MethodReply> asyncReplies_;
struct UserRequest
{
Message msg;
Message::Type msgType;
std::promise<Message> ret;
Message::Type retType;
static_assert(sizeof(Message) == sizeof(MethodCall));
static_assert(sizeof(Message) == sizeof(AsyncMethodCall));
static_assert(sizeof(Message) == sizeof(MethodReply));
static_assert(sizeof(Message) == sizeof(Signal));
};
std::queue<UserRequest> userRequests_;
std::queue<std::unique_ptr<IUserRequest>> userRequests_;
std::mutex userRequestsMutex_;
std::atomic<bool> exitLoopThread_;

View File

@@ -33,6 +33,7 @@
// Forward declaration
namespace sdbus {
class MethodCall;
class AsyncMethodCall;
class MethodReply;
class Signal;
}
@@ -49,14 +50,14 @@ namespace internal {
, void* userData ) = 0;
virtual void removeObjectVTable(void* vtableHandle) = 0;
virtual sdbus::MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const = 0;
virtual MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const = 0;
virtual sdbus::Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const = 0;
virtual Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const = 0;
virtual void* registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
@@ -68,7 +69,10 @@ namespace internal {
virtual void enterProcessingLoopAsync() = 0;
virtual void leaveProcessingLoop() = 0;
virtual void sendReplyAsynchronously(const sdbus::MethodReply& reply) = 0;
virtual MethodReply callMethod(const MethodCall& message) = 0;
virtual void callMethod(const AsyncMethodCall& message, void* callback, void* userData) = 0;
virtual void sendMethodReply(const MethodReply& message) = 0;
virtual void emitSignal(const Signal& message) = 0;
virtual std::unique_ptr<sdbus::internal::IConnection> clone() const = 0;

View File

@@ -37,7 +37,7 @@ MethodResult::MethodResult(const MethodCall& msg, sdbus::internal::Object& objec
void MethodResult::send(const MethodReply& reply) const
{
assert(object_ != nullptr);
object_->sendReplyAsynchronously(reply);
object_->sendMethodReply(reply);
}
}

View File

@@ -156,15 +156,12 @@ sdbus::Signal Object::createSignal(const std::string& interfaceName, const std::
void Object::emitSignal(const sdbus::Signal& message)
{
// TODO: Make signal emitting asynchronous. Now signal can probably be emitted only from user code
// handled within the D-Bus processing loop thread, but not from any thread. In principle it will
// be the same as async replies.
message.send();
connection_.emitSignal(message);
}
void Object::sendReplyAsynchronously(const MethodReply& reply)
void Object::sendMethodReply(const MethodReply& reply)
{
connection_.sendReplyAsynchronously(reply);
connection_.sendMethodReply(reply);
}
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)

View File

@@ -84,7 +84,7 @@ namespace internal {
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
void emitSignal(const sdbus::Signal& message) override;
void sendReplyAsynchronously(const MethodReply& reply);
void sendMethodReply(const MethodReply& reply);
private:
using InterfaceName = std::string;

View File

@@ -49,7 +49,7 @@ ObjectProxy::ObjectProxy( std::unique_ptr<sdbus::internal::IConnection>&& connec
{
// The connection is ours only, so we have to manage event loop upon this connection,
// so we get signals, async replies, and other messages from D-Bus.
connection_->enterProcessingLoopAsync();
// TODO uncomment connection_->enterProcessingLoopAsync();
}
MethodCall ObjectProxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
@@ -64,13 +64,16 @@ AsyncMethodCall ObjectProxy::createAsyncMethodCall(const std::string& interfaceN
MethodReply ObjectProxy::callMethod(const MethodCall& message)
{
return message.send();
return connection_->callMethod(message);
}
void ObjectProxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback)
{
// The new-ed handler gets deleted in the sdbus_async_reply_handler
message.send((void*)&ObjectProxy::sdbus_async_reply_handler, new async_reply_handler(std::move(asyncReplyCallback)));
auto callback = (void*)&ObjectProxy::sdbus_async_reply_handler;
// Allocated userData gets deleted in the sdbus_async_reply_handler
auto userData = new async_reply_handler(std::move(asyncReplyCallback));
connection_->callMethod(message, callback, userData);
}
void ObjectProxy::registerSignalHandler( const std::string& interfaceName

View File

@@ -3,25 +3,25 @@
# https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project
#-------------------------------
#configure_file(googletest-download/CMakeLists.txt.in googletest-download/CMakeLists.txt)
configure_file(googletest-download/CMakeLists.txt.in googletest-download/CMakeLists.txt)
#execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
# RESULT_VARIABLE result
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
#if(result)
# message(FATAL_ERROR "CMake step for googletest failed: ${result}")
#endif()
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
#execute_process(COMMAND ${CMAKE_COMMAND} --build .
# RESULT_VARIABLE result
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
#if(result)
# message(FATAL_ERROR "Build step for googletest failed: ${result}")
#endif()
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
#set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
@@ -63,8 +63,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# targets even when INTERFACE_INCLUDE_DIRECTORIES is used.
set(CMAKE_NO_SYSTEM_FROM_IMPORTED "1")
add_executable(libsdbus-c++_unittests ${UNITTESTS_SRCS} $<TARGET_OBJECTS:sdbuscppobjects>)
target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_main)
#add_executable(libsdbus-c++_unittests ${UNITTESTS_SRCS} $<TARGET_OBJECTS:sdbuscppobjects>)
#target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_main)
add_executable(libsdbus-c++_integrationtests ${INTEGRATIONTESTS_SRCS})
target_link_libraries(libsdbus-c++_integrationtests sdbus-c++ gmock gmock_main)
@@ -82,7 +82,7 @@ endif()
# INSTALLATION
#----------------------------------
install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
#install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
install(TARGETS libsdbus-c++_integrationtests DESTINATION /opt/test/bin)
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/libsdbus-cpp-test.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
@@ -107,9 +107,9 @@ if(CMAKE_CROSSCOMPILING)
if(NOT (UNIT_TESTS_RUNNER AND TEST_DEVICE_IP))
message(WARNING "UNIT_TESTS_RUNNER and TEST_DEVICE_IP variables must be defined to run tests remotely")
endif()
add_test(NAME libsdbus-c++_unittests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_unittests)
#add_test(NAME libsdbus-c++_unittests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_unittests)
add_test(NAME libsdbus-c++_integrationtests COMMAND ${UNIT_TESTS_RUNNER} --deviceip=${TEST_DEVICE_IP} --testbin=libsdbus-c++_integrationtests)
else()
add_test(NAME libsdbus-c++_unittests COMMAND libsdbus-c++_unittests)
#add_test(NAME libsdbus-c++_unittests COMMAND libsdbus-c++_unittests)
add_test(NAME libsdbus-c++_integrationtests COMMAND libsdbus-c++_integrationtests)
endif()