blob: 1006323a11ca83df76eb097f88e7d1c9eaf0438e [file] [log] [blame]
#pragma once
#include "types/duration_types.hpp"
#include "utils/set_exception.hpp"
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/asio/property.hpp>
#include <future>
#include <thread>
#include <gmock/gmock.h>
class DbusEnvironment : public ::testing::Environment
{
public:
~DbusEnvironment();
void SetUp() override;
void TearDown() override;
void teardown();
static boost::asio::io_context& getIoc();
static std::shared_ptr<sdbusplus::asio::connection> getBus();
static std::shared_ptr<sdbusplus::asio::object_server> getObjServer();
static const char* serviceName();
static std::function<void()> setPromise(std::string_view name);
static void sleepFor(Milliseconds);
static Milliseconds measureTime(std::function<void()>);
static void synchronizeIoc()
{
while (ioc.poll() > 0)
{}
}
template <class Functor>
static void synchronizedPost(Functor&& functor)
{
boost::asio::post(ioc, std::forward<Functor>(functor));
synchronizeIoc();
}
template <class T, class F>
static T waitForFutures(std::vector<std::future<T>> futures, T init,
F&& accumulator,
Milliseconds timeout = std::chrono::seconds(10))
{
constexpr auto precission = Milliseconds(10);
auto elapsed = Milliseconds(0);
auto sum = init;
for (auto& future : futures)
{
while (future.valid() && elapsed < timeout)
{
synchronizeIoc();
if (future.wait_for(precission) == std::future_status::ready)
{
sum = accumulator(sum, future.get());
}
else
{
elapsed += precission;
}
}
}
if (elapsed >= timeout)
{
throw std::runtime_error("Timed out while waiting for future");
}
return sum;
}
template <class T>
static T waitForFuture(std::future<T> future,
Milliseconds timeout = std::chrono::seconds(10))
{
std::vector<std::future<T>> futures;
futures.emplace_back(std::move(future));
return waitForFutures(
std::move(futures), T{},
[](auto, const auto& value) { return value; }, timeout);
}
static bool waitForFuture(std::string_view name,
Milliseconds timeout = std::chrono::seconds(10));
static bool waitForFutures(std::string_view name,
Milliseconds timeout = std::chrono::seconds(10));
template <class T>
static T getProperty(const std::string& path,
const std::string& interfaceName,
const std::string& property)
{
auto propertyPromise = std::promise<T>();
auto propertyFuture = propertyPromise.get_future();
sdbusplus::asio::getProperty<T>(
*DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
interfaceName, property,
[&propertyPromise](const boost::system::error_code& ec, T t) {
if (ec)
{
utils::setException(propertyPromise, "GetProperty failed");
return;
}
propertyPromise.set_value(t);
});
return DbusEnvironment::waitForFuture(std::move(propertyFuture));
}
template <class T>
static boost::system::error_code
setProperty(const std::string& path, const std::string& interfaceName,
const std::string& property, const T& newValue)
{
auto promise = std::promise<boost::system::error_code>();
auto future = promise.get_future();
sdbusplus::asio::setProperty(
*DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
interfaceName, property, std::move(newValue),
[promise = std::move(promise)](
boost::system::error_code ec) mutable {
promise.set_value(ec);
});
return DbusEnvironment::waitForFuture(std::move(future));
}
template <class... Args>
static boost::system::error_code
callMethod(const std::string& path, const std::string& interface,
const std::string& method, Args&&... args)
{
auto promise = std::promise<boost::system::error_code>();
auto future = promise.get_future();
DbusEnvironment::getBus()->async_method_call(
[promise = std::move(promise)](
boost::system::error_code ec) mutable {
promise.set_value(ec);
},
DbusEnvironment::serviceName(), path, interface, method,
std::forward<Args>(args)...);
return DbusEnvironment::waitForFuture(std::move(future));
}
private:
static std::future<bool> getFuture(std::string_view name);
static boost::asio::io_context ioc;
static std::shared_ptr<sdbusplus::asio::connection> bus;
static std::shared_ptr<sdbusplus::asio::object_server> objServer;
static std::map<std::string, std::vector<std::future<bool>>> futures;
static bool setUp;
};