Mock sdbus lib, add unit tests of Connection class.

Introduce mock of sdbus library through extracting its interface. Set up unit tests of Connection class through injection of sdbusMock to constructor. Clients of Connections class should use fabrics instead.
This commit is contained in:
ardazishvili
2019-03-17 18:02:47 +03:00
parent 8c5c774727
commit 2b83d7ca2d
12 changed files with 529 additions and 35 deletions

View File

@ -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

View File

@ -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
------------

View File

@ -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:
```
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.sdbuscpp.concatenator"/>
<allow send_destination="org.sdbuscpp"/>
<allow send_interface="org.sdbuscpp.concatenator"/>
</policy>
</busconfig>
```
If you need access from other user `root` should be substituted by desired username. For more refer to `man dbus-daemon`.

View File

@ -24,6 +24,7 @@
*/
#include "Connection.h"
#include "SdBus.h"
#include <sdbus-c++/Message.h>
#include <sdbus-c++/Error.h>
#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<ISdBus>&& 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<sdbus::internal::IConnection> Connection::clone() const
{
return std::make_unique<sdbus::internal::Connection>(busType_);
auto interface = std::make_unique<SdBus>(SdBus());
assert(interface != nullptr);
return std::make_unique<sdbus::internal::Connection>(busType_, std::move(interface));
}
sd_bus* Connection::openBus(Connection::BusType type)
{
static std::map<sdbus::internal::Connection::BusType, int(*)(sd_bus **)> 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<sdbus::IConnection> createConnection(const std::string& name)
std::unique_ptr<sdbus::IConnection> createSystemBusConnection()
{
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSystem);
auto interface = std::make_unique<SdBus>(SdBus());
assert(interface != nullptr);
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSystem,
std::move(interface));
}
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name)
@ -368,7 +374,10 @@ std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string&
std::unique_ptr<sdbus::IConnection> createSessionBusConnection()
{
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSession);
auto interface = std::make_unique<SdBus>(SdBus());
assert(interface != nullptr);
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSession,
std::move(interface));
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name)

View File

@ -29,6 +29,8 @@
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/Message.h>
#include "IConnection.h"
#include "ISdBus.h"
#include <systemd/sd-bus.h>
#include <memory>
#include <thread>
@ -49,7 +51,7 @@ namespace sdbus { namespace internal {
eSession
};
Connection(BusType type);
Connection(BusType type, std::unique_ptr<ISdBus>&& 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<sd_bus, decltype(&sd_bus_flush_close_unref)> bus_{nullptr, &sd_bus_flush_close_unref};
std::unique_ptr<ISdBus> iface_;
std::unique_ptr<sd_bus, std::function<sd_bus*(sd_bus*)>> bus_ {nullptr, [this](sd_bus* bus)
{
return iface_->sd_bus_flush_close_unref(bus);
}};
std::thread asyncLoopThread_;
std::mutex mutex_;
std::queue<MethodReply> asyncReplies_;

55
src/ISdBus.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CXX_ISDBUS_H
#define SDBUS_CXX_ISDBUS_H
#include <systemd/sd-bus.h>
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

107
src/SdBus.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);
}

53
src/SdBus.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -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

View File

@ -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<TestingProxy> 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>(SdBus())};
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "Connection.h"
#include "unittests/mocks/SdBusMock.h"
#include <gtest/gtest.h>
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<NiceMock<SdBusMock>> mock_ { std::make_unique<NiceMock<SdBusMock>>() };
sd_bus* STUB_ { reinterpret_cast<sd_bus*>(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<BusType>
{
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<NiceMock<SdBusMock>> mock_ { std::make_unique<NiceMock<SdBusMock>>() };
sd_bus* STUB_ { reinterpret_cast<sd_bus*>(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));

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef SDBUS_CXX_SDBUS_MOCK_H
#define SDBUS_CXX_SDBUS_MOCK_H
#include "ISdBus.h"
#include <gmock/gmock.h>
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