diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc5d56f..6a9d6b5 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,7 +33,8 @@ set(SDBUSCPP_CPP_SRCS
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.cpp
${SDBUSCPP_SOURCE_DIR}/Types.cpp
${SDBUSCPP_SOURCE_DIR}/Flags.cpp
- ${SDBUSCPP_SOURCE_DIR}/VTableUtils.c)
+ ${SDBUSCPP_SOURCE_DIR}/VTableUtils.c
+ ${SDBUSCPP_SOURCE_DIR}/SdBus.cpp)
set(SDBUSCPP_HDR_SRCS
${SDBUSCPP_SOURCE_DIR}/Connection.h
@@ -42,7 +43,9 @@ set(SDBUSCPP_HDR_SRCS
${SDBUSCPP_SOURCE_DIR}/Object.h
${SDBUSCPP_SOURCE_DIR}/ObjectProxy.h
${SDBUSCPP_SOURCE_DIR}/ScopeGuard.h
- ${SDBUSCPP_SOURCE_DIR}/VTableUtils.h)
+ ${SDBUSCPP_SOURCE_DIR}/VTableUtils.h
+ ${SDBUSCPP_SOURCE_DIR}/SdBus.h
+ ${SDBUSCPP_SOURCE_DIR}/ISdBus.h)
set(SDBUSCPP_PUBLIC_HDRS
${SDBUSCPP_INCLUDE_DIR}/ConvenienceClasses.h
diff --git a/README.md b/README.md
index 582a036..4447f2e 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,7 @@ References/documentation
* [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html)
* [sd-bus Overview](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html)
* [Tutorial: Using sdbus-c++](doc/using-sdbus-c++.md)
+* [Systemd and dbus configuration](doc/systemd-dbus-config.md)
Contributing
------------
diff --git a/doc/systemd-dbus-config.md b/doc/systemd-dbus-config.md
new file mode 100644
index 0000000..b32a632
--- /dev/null
+++ b/doc/systemd-dbus-config.md
@@ -0,0 +1,54 @@
+Systemd and dbus configuration
+=======================
+
+**Table of contents**
+
+1. [Introduction](#introduction)
+2. [Systemd configuration](#systemd-configuration)
+3. [Dbus configuration](#dbus-configuration)
+
+Introduction
+------------
+
+To run executable as a systemd service you may need some additional setup. For example, you may need explicitly allow
+the usage of your service. Following chapters contain template configurations.
+
+
+Systemd configuration
+---------------------------------------
+
+Filename should use `.service` extension. It also must be placed in configuration directory (/etc/systemd/system in
+Ubuntu 18.04.1 LTS)
+
+```
+[Unit]
+Description=nameOfService
+
+[Service]
+ExecStart=/path/to/executable
+
+[Install]
+WantedBy=multi-user.target
+```
+
+Dbus configuration
+------------------
+
+Typical default D-Bus configuration does not allow to register services except explicitly allowed. Filename should
+contain name of your service, e.g `/etc/dbus-1/system.d/org.sdbuscpp.concatenator.conf`. So, here is template
+configuration to use dbus interface under root:
+
+```
+
+
+
+
+
+
+
+
+```
+
+If you need access from other user `root` should be substituted by desired username. For more refer to `man dbus-daemon`.
\ No newline at end of file
diff --git a/src/Connection.cpp b/src/Connection.cpp
index e5815d7..cc9c3c4 100755
--- a/src/Connection.cpp
+++ b/src/Connection.cpp
@@ -24,6 +24,7 @@
*/
#include "Connection.h"
+#include "SdBus.h"
#include
#include
#include "ScopeGuard.h"
@@ -34,8 +35,9 @@
namespace sdbus { namespace internal {
-Connection::Connection(Connection::BusType type)
- : busType_(type)
+Connection::Connection(Connection::BusType type, std::unique_ptr&& interface)
+ : busType_(type),
+ iface_(std::move(interface))
{
auto bus = openBus(busType_);
bus_.reset(bus);
@@ -53,13 +55,13 @@ Connection::~Connection()
void Connection::requestName(const std::string& name)
{
- auto r = sd_bus_request_name(bus_.get(), name.c_str(), 0);
+ auto r = iface_->sd_bus_request_name(bus_.get(), name.c_str(), 0);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to request bus name", -r);
}
void Connection::releaseName(const std::string& name)
{
- auto r = sd_bus_release_name(bus_.get(), name.c_str());
+ auto r = iface_->sd_bus_release_name(bus_.get(), name.c_str());
SDBUS_THROW_ERROR_IF(r < 0, "Failed to release bus name", -r);
}
@@ -97,7 +99,7 @@ void* Connection::addObjectVTable( const std::string& objectPath
{
sd_bus_slot *slot{};
- auto r = sd_bus_add_object_vtable( bus_.get()
+ auto r = iface_->sd_bus_add_object_vtable( bus_.get()
, &slot
, objectPath.c_str()
, interfaceName.c_str()
@@ -111,7 +113,7 @@ void* Connection::addObjectVTable( const std::string& objectPath
void Connection::removeObjectVTable(void* vtableHandle)
{
- sd_bus_slot_unref((sd_bus_slot *)vtableHandle);
+ iface_->sd_bus_slot_unref((sd_bus_slot *)vtableHandle);
}
sdbus::MethodCall Connection::createMethodCall( const std::string& destination
@@ -122,9 +124,9 @@ sdbus::MethodCall Connection::createMethodCall( const std::string& destination
sd_bus_message *sdbusMsg{};
// Returned message will become an owner of sdbusMsg
- SCOPE_EXIT{ sd_bus_message_unref(sdbusMsg); };
+ SCOPE_EXIT{ iface_->sd_bus_message_unref(sdbusMsg); };
- auto r = sd_bus_message_new_method_call( bus_.get()
+ auto r = iface_->sd_bus_message_new_method_call( bus_.get()
, &sdbusMsg
, destination.c_str()
, objectPath.c_str()
@@ -145,7 +147,7 @@ sdbus::Signal Connection::createSignal( const std::string& objectPath
// Returned message will become an owner of sdbusSignal
SCOPE_EXIT{ sd_bus_message_unref(sdbusSignal); };
- auto r = sd_bus_message_new_signal( bus_.get()
+ auto r = iface_->sd_bus_message_new_signal( bus_.get()
, &sdbusSignal
, objectPath.c_str()
, interfaceName.c_str()
@@ -165,7 +167,7 @@ void* Connection::registerSignalHandler( const std::string& objectPath
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 r = iface_->sd_bus_add_match(bus_.get(), &slot, filter.c_str(), callback, userData);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to register signal handler", -r);
@@ -174,7 +176,7 @@ void* Connection::registerSignalHandler( const std::string& objectPath
void Connection::unregisterSignalHandler(void* handlerCookie)
{
- sd_bus_slot_unref((sd_bus_slot *)handlerCookie);
+ iface_->sd_bus_slot_unref((sd_bus_slot *)handlerCookie);
}
void Connection::sendReplyAsynchronously(const sdbus::MethodReply& reply)
@@ -186,20 +188,21 @@ void Connection::sendReplyAsynchronously(const sdbus::MethodReply& reply)
std::unique_ptr Connection::clone() const
{
- return std::make_unique(busType_);
+ auto interface = std::make_unique(SdBus());
+ assert(interface != nullptr);
+ return std::make_unique(busType_, std::move(interface));
}
sd_bus* Connection::openBus(Connection::BusType type)
{
- static std::map busTypeToFactory
- {
- {sdbus::internal::Connection::BusType::eSystem, &sd_bus_open_system},
- {sdbus::internal::Connection::BusType::eSession, &sd_bus_open_user}
- };
-
sd_bus* bus{};
-
- auto r = busTypeToFactory[type](&bus);
+ int r = 0;
+ if (type == BusType::eSystem)
+ r = iface_->sd_bus_open_system(&bus);
+ else if (type == BusType::eSession)
+ r = iface_->sd_bus_open_user(&bus);
+ else
+ assert(false);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open bus", -r);
assert(bus != nullptr);
@@ -215,7 +218,7 @@ void Connection::finishHandshake(sd_bus* bus)
assert(bus != nullptr);
- auto r = sd_bus_flush(bus);
+ auto r = iface_->sd_bus_flush(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to flush bus on opening", -r);
}
@@ -263,7 +266,7 @@ bool Connection::processPendingRequest()
assert(bus != nullptr);
- int r = sd_bus_process(bus, nullptr);
+ int r = iface_->sd_bus_process(bus, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to process bus requests", -r);
@@ -288,16 +291,16 @@ Connection::WaitResult Connection::waitForNextRequest()
assert(bus != nullptr);
assert(notificationFd_ != 0);
- auto r = sd_bus_get_fd(bus);
+ auto r = iface_->sd_bus_get_fd(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus descriptor", -r);
auto sdbusFd = r;
- r = sd_bus_get_events(bus);
+ r = iface_->sd_bus_get_events(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus events", -r);
short int sdbusEvents = r;
uint64_t usec;
- sd_bus_get_timeout(bus, &usec);
+ iface_->sd_bus_get_timeout(bus, &usec);
struct pollfd fds[] = {{sdbusFd, sdbusEvents, 0}, {notificationFd_, POLLIN, 0}};
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
@@ -356,7 +359,10 @@ std::unique_ptr createConnection(const std::string& name)
std::unique_ptr createSystemBusConnection()
{
- return std::make_unique(sdbus::internal::Connection::BusType::eSystem);
+ auto interface = std::make_unique(SdBus());
+ assert(interface != nullptr);
+ return std::make_unique(sdbus::internal::Connection::BusType::eSystem,
+ std::move(interface));
}
std::unique_ptr createSystemBusConnection(const std::string& name)
@@ -368,7 +374,10 @@ std::unique_ptr createSystemBusConnection(const std::string&
std::unique_ptr createSessionBusConnection()
{
- return std::make_unique(sdbus::internal::Connection::BusType::eSession);
+ auto interface = std::make_unique(SdBus());
+ assert(interface != nullptr);
+ return std::make_unique(sdbus::internal::Connection::BusType::eSession,
+ std::move(interface));
}
std::unique_ptr createSessionBusConnection(const std::string& name)
diff --git a/src/Connection.h b/src/Connection.h
index 40abc12..68bd15e 100755
--- a/src/Connection.h
+++ b/src/Connection.h
@@ -29,6 +29,8 @@
#include
#include
#include "IConnection.h"
+#include "ISdBus.h"
+
#include
#include
#include
@@ -49,7 +51,7 @@ namespace sdbus { namespace internal {
eSession
};
- Connection(BusType type);
+ Connection(BusType type, std::unique_ptr&& interface);
~Connection();
void requestName(const std::string& name) override;
@@ -93,8 +95,8 @@ namespace sdbus { namespace internal {
return msgsToProcess || asyncMsgsToProcess;
}
};
- static sd_bus* openBus(Connection::BusType type);
- static void finishHandshake(sd_bus* bus);
+ sd_bus* openBus(Connection::BusType type);
+ void finishHandshake(sd_bus* bus);
static int createLoopNotificationDescriptor();
static void closeLoopNotificationDescriptor(int fd);
bool processPendingRequest();
@@ -108,7 +110,11 @@ namespace sdbus { namespace internal {
void joinWithProcessingLoop();
private:
- std::unique_ptr bus_{nullptr, &sd_bus_flush_close_unref};
+ std::unique_ptr iface_;
+ std::unique_ptr> bus_ {nullptr, [this](sd_bus* bus)
+ {
+ return iface_->sd_bus_flush_close_unref(bus);
+ }};
std::thread asyncLoopThread_;
std::mutex mutex_;
std::queue asyncReplies_;
diff --git a/src/ISdBus.h b/src/ISdBus.h
new file mode 100644
index 0000000..bcbb4b4
--- /dev/null
+++ b/src/ISdBus.h
@@ -0,0 +1,55 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file ISdBus.h
+ * @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
+ *
+ * Created on: Mar 12, 2019
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_ISDBUS_H
+#define SDBUS_CXX_ISDBUS_H
+
+#include
+
+class ISdBus
+{
+public:
+ virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) = 0;
+ virtual int sd_bus_release_name(sd_bus *bus, const char *name) = 0;
+ virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) = 0;
+ virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 0;
+ virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) = 0;
+ virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 0;
+ virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) = 0;
+ virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) = 0;
+ virtual int sd_bus_open_user(sd_bus **ret) = 0;
+ virtual int sd_bus_open_system(sd_bus **ret) = 0;
+ virtual int sd_bus_flush(sd_bus *bus) = 0;
+ virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 0;
+ virtual int sd_bus_get_fd(sd_bus *bus) = 0;
+ virtual int sd_bus_get_events(sd_bus *bus) = 0;
+ virtual int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) = 0;
+ virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) = 0;
+
+ virtual ~ISdBus() = default;
+};
+
+#endif //SDBUS_CXX_ISDBUS_H
diff --git a/src/SdBus.cpp b/src/SdBus.cpp
new file mode 100644
index 0000000..3e64721
--- /dev/null
+++ b/src/SdBus.cpp
@@ -0,0 +1,107 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file SdBus.cpp
+ * @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
+ *
+ * Created on: Mar 3, 2019
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#include "SdBus.h"
+
+int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
+{
+ return ::sd_bus_request_name(bus, name, flags);
+}
+
+int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
+{
+ return ::sd_bus_release_name(bus, name);
+}
+
+int SdBus::sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata)
+{
+ return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
+}
+
+sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
+{
+ return ::sd_bus_slot_unref(slot);
+}
+
+int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member)
+{
+ return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
+}
+
+sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *m)
+{
+ return ::sd_bus_message_unref(m);
+}
+
+int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)
+{
+ return ::sd_bus_message_new_signal(bus, m, path, interface, member);
+}
+
+int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
+{
+ return :: sd_bus_add_match(bus, slot, match, callback, userdata);
+}
+
+int SdBus::sd_bus_open_user(sd_bus **ret)
+{
+ return ::sd_bus_open_user(ret);
+}
+
+int SdBus::sd_bus_open_system(sd_bus **ret)
+{
+ return ::sd_bus_open_system(ret);
+}
+
+int SdBus::sd_bus_flush(sd_bus *bus)
+{
+ return ::sd_bus_flush(bus);
+}
+
+int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
+{
+ return ::sd_bus_process(bus, r);
+}
+
+int SdBus::sd_bus_get_fd(sd_bus *bus)
+{
+ return ::sd_bus_get_fd(bus);
+}
+
+int SdBus::sd_bus_get_events(sd_bus *bus)
+{
+ return ::sd_bus_get_events(bus);
+}
+
+int SdBus::sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec)
+{
+ return ::sd_bus_get_timeout(bus, timeout_usec);
+}
+
+sd_bus* SdBus::sd_bus_flush_close_unref(sd_bus *bus)
+{
+ return ::sd_bus_flush_close_unref(bus);
+}
diff --git a/src/SdBus.h b/src/SdBus.h
new file mode 100644
index 0000000..521f9e8
--- /dev/null
+++ b/src/SdBus.h
@@ -0,0 +1,53 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file SdBus.h
+ * @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
+ *
+ * Created on: Mar 3, 2019
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_SDBUS_H
+#define SDBUS_CXX_SDBUS_H
+
+#include "ISdBus.h"
+
+class SdBus : public ISdBus
+{
+public:
+ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
+ int sd_bus_release_name(sd_bus *bus, const char *name) override;
+ int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
+ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
+ int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) override;
+ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
+ int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override;
+ int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
+ int sd_bus_open_user(sd_bus **ret) override;
+ int sd_bus_open_system(sd_bus **ret) override;
+ int sd_bus_flush(sd_bus *bus) override;
+ int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
+ int sd_bus_get_fd(sd_bus *bus) override;
+ int sd_bus_get_events(sd_bus *bus) override;
+ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) override;
+ sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
+};
+
+#endif //SDBUS_C_SDBUS_H
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 1905f2d..99be990 100755
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -36,7 +36,8 @@ set(UNITTESTS_SRCS
${UNITTESTS_SOURCE_DIR}/libsdbus-c++_unittests.cpp
${UNITTESTS_SOURCE_DIR}/Message_test.cpp
${UNITTESTS_SOURCE_DIR}/Types_test.cpp
- ${UNITTESTS_SOURCE_DIR}/TypeTraits_test.cpp)
+ ${UNITTESTS_SOURCE_DIR}/TypeTraits_test.cpp
+ ${UNITTESTS_SOURCE_DIR}/Connection_test.cpp)
set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests)
set(INTEGRATIONTESTS_SRCS
diff --git a/test/integrationtests/AdaptorAndProxy_test.cpp b/test/integrationtests/AdaptorAndProxy_test.cpp
index b904a5b..56b0682 100644
--- a/test/integrationtests/AdaptorAndProxy_test.cpp
+++ b/test/integrationtests/AdaptorAndProxy_test.cpp
@@ -25,6 +25,7 @@
// Own
#include "Connection.h"
+#include "SdBus.h"
#include "TestingAdaptor.h"
#include "TestingProxy.h"
@@ -87,7 +88,8 @@ public:
std::unique_ptr m_proxy;
};
-sdbus::internal::Connection AdaptorAndProxyFixture::m_connection{sdbus::internal::Connection::BusType::eSystem};
+sdbus::internal::Connection AdaptorAndProxyFixture::m_connection{sdbus::internal::Connection::BusType::eSystem,
+ std::make_unique(SdBus())};
}
diff --git a/test/unittests/Connection_test.cpp b/test/unittests/Connection_test.cpp
new file mode 100644
index 0000000..bc8d765
--- /dev/null
+++ b/test/unittests/Connection_test.cpp
@@ -0,0 +1,148 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file Connection_test.cpp
+ * @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
+ *
+ * Created on: Feb 4, 2019
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#include "Connection.h"
+#include "unittests/mocks/SdBusMock.h"
+
+#include
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::SetArgPointee;
+using ::testing::Return;
+using ::testing::NiceMock;
+
+using BusType = sdbus::internal::Connection::BusType;
+
+
+class ConnectionCreationTest : public ::testing::Test
+{
+protected:
+ ConnectionCreationTest() = default;
+
+ std::unique_ptr> mock_ { std::make_unique>() };
+ sd_bus* STUB_ { reinterpret_cast(1) };
+};
+
+using ASystemBusConnection = ConnectionCreationTest;
+using ASessionBusConnection = ConnectionCreationTest;
+
+TEST_F(ASystemBusConnection, OpensAndFlushesBusWhenCreated)
+{
+ EXPECT_CALL(*mock_, sd_bus_open_system(_)).WillOnce(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ EXPECT_CALL(*mock_, sd_bus_flush(_)).Times(1);
+ sdbus::internal::Connection(BusType::eSystem, std::move(mock_));
+}
+
+TEST_F(ASessionBusConnection, OpensAndFlushesBusWhenCreated)
+{
+ EXPECT_CALL(*mock_, sd_bus_open_user(_)).WillOnce(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ EXPECT_CALL(*mock_, sd_bus_flush(_)).Times(1);
+ sdbus::internal::Connection(BusType::eSession, std::move(mock_));
+}
+
+TEST_F(ASystemBusConnection, ClosesAndUnrefsBusWhenDestructed)
+{
+ ON_CALL(*mock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ EXPECT_CALL(*mock_, sd_bus_flush_close_unref(_)).Times(1);
+ sdbus::internal::Connection(BusType::eSession, std::move(mock_));
+}
+
+TEST_F(ASessionBusConnection, ClosesAndUnrefsBusWhenDestructed)
+{
+ ON_CALL(*mock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ EXPECT_CALL(*mock_, sd_bus_flush_close_unref(_)).Times(1);
+ sdbus::internal::Connection(BusType::eSession, std::move(mock_));
+}
+
+TEST_F(ASystemBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction)
+{
+ ON_CALL(*mock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(STUB_), Return(-1)));
+ ASSERT_THROW(sdbus::internal::Connection(BusType::eSystem, std::move(mock_)), sdbus::Error);
+}
+
+TEST_F(ASessionBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction)
+{
+ ON_CALL(*mock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(STUB_), Return(-1)));
+ ASSERT_THROW(sdbus::internal::Connection(BusType::eSession, std::move(mock_)), sdbus::Error);
+}
+
+TEST_F(ASystemBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction)
+{
+ ON_CALL(*mock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ ON_CALL(*mock_, sd_bus_flush(_)).WillByDefault(Return(-1));
+ ASSERT_THROW(sdbus::internal::Connection(BusType::eSystem, std::move(mock_)), sdbus::Error);
+}
+
+TEST_F(ASessionBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction)
+{
+ ON_CALL(*mock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ ON_CALL(*mock_, sd_bus_flush(_)).WillByDefault(Return(-1));
+ ASSERT_THROW(sdbus::internal::Connection(BusType::eSession, std::move(mock_)), sdbus::Error);
+}
+
+class ConnectionRequestTest : public ::testing::TestWithParam
+{
+protected:
+ ConnectionRequestTest() = default;
+ void SetUp() override
+ {
+ switch (GetParam())
+ {
+ case BusType::eSystem:
+ EXPECT_CALL(*mock_, sd_bus_open_system(_)).WillOnce(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ break;
+ case BusType::eSession:
+ EXPECT_CALL(*mock_, sd_bus_open_user(_)).WillOnce(DoAll(SetArgPointee<0>(STUB_), Return(1)));
+ break;
+ default:
+ break;
+ }
+ ON_CALL(*mock_, sd_bus_flush(_)).WillByDefault(Return(1));
+ ON_CALL(*mock_, sd_bus_flush_close_unref(_)).WillByDefault(Return(STUB_));
+ }
+
+ std::unique_ptr> mock_ { std::make_unique>() };
+ sd_bus* STUB_ { reinterpret_cast(1) };
+};
+
+using AConnectionNameRequest = ConnectionRequestTest;
+
+TEST_P(AConnectionNameRequest, DoesNotThrowOnSuccess)
+{
+ EXPECT_CALL(*mock_, sd_bus_request_name(_, _, _)).WillOnce(Return(1));
+ sdbus::internal::Connection(GetParam(), std::move(mock_)).requestName("");
+}
+
+TEST_P(AConnectionNameRequest, ThrowsOnFail)
+{
+ EXPECT_CALL(*mock_, sd_bus_request_name(_, _, _)).WillOnce(Return(-1));
+
+ auto conn_ = sdbus::internal::Connection(GetParam(), std::move(mock_)) ;
+ ASSERT_THROW(conn_.requestName(""), sdbus::Error);
+}
+
+INSTANTIATE_TEST_SUITE_P(Request, AConnectionNameRequest, ::testing::Values(BusType::eSystem, BusType::eSession));
diff --git a/test/unittests/mocks/SdBusMock.h b/test/unittests/mocks/SdBusMock.h
new file mode 100644
index 0000000..9506c23
--- /dev/null
+++ b/test/unittests/mocks/SdBusMock.h
@@ -0,0 +1,55 @@
+/**
+ * (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
+ *
+ * @file SdBusMock.h
+ * @author Ardazishvili Roman (ardazishvili.roman@yandex.ru)
+ *
+ * Created on: Mar 12, 2019
+ * Project: sdbus-c++
+ * Description: High-level D-Bus IPC C++ library based on sd-bus
+ *
+ * This file is part of sdbus-c++.
+ *
+ * sdbus-c++ is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * sdbus-c++ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with sdbus-c++. If not, see .
+ */
+
+#ifndef SDBUS_CXX_SDBUS_MOCK_H
+#define SDBUS_CXX_SDBUS_MOCK_H
+
+#include "ISdBus.h"
+
+#include
+
+class SdBusMock : public ISdBus
+{
+public:
+ MOCK_METHOD3(sd_bus_request_name, int(sd_bus *bus, const char *name, uint64_t flags));
+ MOCK_METHOD2(sd_bus_release_name, int(sd_bus *bus, const char *name));
+ MOCK_METHOD6(sd_bus_add_object_vtable, int(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata));
+ MOCK_METHOD1(sd_bus_slot_unref, sd_bus_slot*(sd_bus_slot *slot));
+ MOCK_METHOD6(sd_bus_message_new_method_call, int(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member));
+ MOCK_METHOD1(sd_bus_message_unref, sd_bus_message* (sd_bus_message *m));
+ MOCK_METHOD5(sd_bus_message_new_signal, int(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member));
+ MOCK_METHOD5(sd_bus_add_match, int(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata));
+ MOCK_METHOD1(sd_bus_open_user, int(sd_bus **ret));
+ MOCK_METHOD1(sd_bus_open_system, int(sd_bus **ret));
+ MOCK_METHOD1(sd_bus_flush, int(sd_bus *bus));
+ MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **r));
+ MOCK_METHOD1(sd_bus_get_fd, int(sd_bus *bus));
+ MOCK_METHOD1(sd_bus_get_events, int(sd_bus *bus));
+ MOCK_METHOD2(sd_bus_get_timeout, int(sd_bus *bus, uint64_t *timeout_usec));
+ MOCK_METHOD1(sd_bus_flush_close_unref, sd_bus *(sd_bus *bus));
+};
+
+#endif //SDBUS_CXX_SDBUS_MOCK_H