blob: 558445e2b54deeaf52506952211ffc2c36ff2af4 [file] [log] [blame]
Szymon Dompkef763c9e2021-03-12 09:19:22 +01001#pragma once
2
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +01003#include "types/duration_types.hpp"
Szymon Dompkee28aa532021-10-27 12:33:12 +02004#include "utils/set_exception.hpp"
Krzysztof Grobelny80697712021-03-04 09:49:27 +00005
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +02006#include <sdbusplus/asio/object_server.hpp>
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +02007#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +02008
9#include <future>
10#include <thread>
11
12#include <gmock/gmock.h>
13
14class DbusEnvironment : public ::testing::Environment
15{
16 public:
17 ~DbusEnvironment();
18
19 void SetUp() override;
20 void TearDown() override;
21 void teardown();
22
23 static boost::asio::io_context& getIoc();
24 static std::shared_ptr<sdbusplus::asio::connection> getBus();
25 static std::shared_ptr<sdbusplus::asio::object_server> getObjServer();
26 static const char* serviceName();
27 static std::function<void()> setPromise(std::string_view name);
Krzysztof Grobelny80697712021-03-04 09:49:27 +000028 static void sleepFor(Milliseconds);
29 static Milliseconds measureTime(std::function<void()>);
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020030
31 static void synchronizeIoc()
32 {
33 while (ioc.poll() > 0)
Patrick Williams92cfff42021-02-22 17:15:39 -060034 {}
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020035 }
36
37 template <class Functor>
38 static void synchronizedPost(Functor&& functor)
39 {
40 boost::asio::post(ioc, std::forward<Functor>(functor));
41 synchronizeIoc();
42 }
43
Szymon Dompkef763c9e2021-03-12 09:19:22 +010044 template <class T, class F>
Krzysztof Grobelny80697712021-03-04 09:49:27 +000045 static T waitForFutures(std::vector<std::future<T>> futures, T init,
46 F&& accumulator,
47 Milliseconds timeout = std::chrono::seconds(10))
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020048 {
Krzysztof Grobelny80697712021-03-04 09:49:27 +000049 constexpr auto precission = Milliseconds(10);
50 auto elapsed = Milliseconds(0);
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020051
Szymon Dompkef763c9e2021-03-12 09:19:22 +010052 auto sum = init;
53 for (auto& future : futures)
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020054 {
Szymon Dompkef763c9e2021-03-12 09:19:22 +010055 while (future.valid() && elapsed < timeout)
56 {
57 synchronizeIoc();
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020058
Szymon Dompkef763c9e2021-03-12 09:19:22 +010059 if (future.wait_for(precission) == std::future_status::ready)
60 {
61 sum = accumulator(sum, future.get());
62 }
63 else
64 {
65 elapsed += precission;
66 }
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020067 }
68 }
69
Szymon Dompkef763c9e2021-03-12 09:19:22 +010070 if (elapsed >= timeout)
71 {
72 throw std::runtime_error("Timed out while waiting for future");
73 }
74
75 return sum;
76 }
77
78 template <class T>
Krzysztof Grobelny80697712021-03-04 09:49:27 +000079 static T waitForFuture(std::future<T> future,
80 Milliseconds timeout = std::chrono::seconds(10))
Szymon Dompkef763c9e2021-03-12 09:19:22 +010081 {
82 std::vector<std::future<T>> futures;
83 futures.emplace_back(std::move(future));
84
85 return waitForFutures(
86 std::move(futures), T{},
87 [](auto, const auto& value) { return value; }, timeout);
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020088 }
89
Krzysztof Grobelny80697712021-03-04 09:49:27 +000090 static bool waitForFuture(std::string_view name,
91 Milliseconds timeout = std::chrono::seconds(10));
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020092
Krzysztof Grobelny80697712021-03-04 09:49:27 +000093 static bool waitForFutures(std::string_view name,
94 Milliseconds timeout = std::chrono::seconds(10));
Szymon Dompkef763c9e2021-03-12 09:19:22 +010095
Szymon Dompkee28aa532021-10-27 12:33:12 +020096 template <class T>
97 static T getProperty(const std::string& path,
98 const std::string& interfaceName,
99 const std::string& property)
100 {
101 auto propertyPromise = std::promise<T>();
102 auto propertyFuture = propertyPromise.get_future();
103 sdbusplus::asio::getProperty<T>(
104 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
105 interfaceName, property,
106 [&propertyPromise](const boost::system::error_code& ec, T t) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500107 if (ec)
108 {
109 utils::setException(propertyPromise, "GetProperty failed");
110 return;
111 }
112 propertyPromise.set_value(t);
Szymon Dompkee28aa532021-10-27 12:33:12 +0200113 });
114 return DbusEnvironment::waitForFuture(std::move(propertyFuture));
115 }
116
117 template <class T>
118 static boost::system::error_code
119 setProperty(const std::string& path, const std::string& interfaceName,
120 const std::string& property, const T& newValue)
121 {
Krzysztof Grobelnyfbeb5bf2022-01-03 09:41:29 +0100122 auto promise = std::promise<boost::system::error_code>();
123 auto future = promise.get_future();
Szymon Dompkee28aa532021-10-27 12:33:12 +0200124 sdbusplus::asio::setProperty(
125 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
126 interfaceName, property, std::move(newValue),
Patrick Williams3a1c2972023-05-10 07:51:04 -0500127 [promise = std::move(promise)](
128 boost::system::error_code ec) mutable {
129 promise.set_value(ec);
Szymon Dompkee28aa532021-10-27 12:33:12 +0200130 });
131 return DbusEnvironment::waitForFuture(std::move(future));
132 }
133
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +0200134 private:
135 static std::future<bool> getFuture(std::string_view name);
136
137 static boost::asio::io_context ioc;
138 static std::shared_ptr<sdbusplus::asio::connection> bus;
139 static std::shared_ptr<sdbusplus::asio::object_server> objServer;
140 static std::map<std::string, std::vector<std::future<bool>>> futures;
141 static bool setUp;
142};