blob: 8519b2987b9dda286750650cd18896dc949b4696 [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;
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020021
22 static boost::asio::io_context& getIoc();
23 static std::shared_ptr<sdbusplus::asio::connection> getBus();
24 static std::shared_ptr<sdbusplus::asio::object_server> getObjServer();
25 static const char* serviceName();
26 static std::function<void()> setPromise(std::string_view name);
Krzysztof Grobelny80697712021-03-04 09:49:27 +000027 static void sleepFor(Milliseconds);
28 static Milliseconds measureTime(std::function<void()>);
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020029
30 static void synchronizeIoc()
31 {
32 while (ioc.poll() > 0)
Patrick Williams92cfff42021-02-22 17:15:39 -060033 {}
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020034 }
35
36 template <class Functor>
37 static void synchronizedPost(Functor&& functor)
38 {
39 boost::asio::post(ioc, std::forward<Functor>(functor));
40 synchronizeIoc();
41 }
42
Szymon Dompkef763c9e2021-03-12 09:19:22 +010043 template <class T, class F>
Krzysztof Grobelny80697712021-03-04 09:49:27 +000044 static T waitForFutures(std::vector<std::future<T>> futures, T init,
45 F&& accumulator,
46 Milliseconds timeout = std::chrono::seconds(10))
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020047 {
Krzysztof Grobelny80697712021-03-04 09:49:27 +000048 constexpr auto precission = Milliseconds(10);
49 auto elapsed = Milliseconds(0);
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020050
Szymon Dompkef763c9e2021-03-12 09:19:22 +010051 auto sum = init;
52 for (auto& future : futures)
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020053 {
Szymon Dompkef763c9e2021-03-12 09:19:22 +010054 while (future.valid() && elapsed < timeout)
55 {
56 synchronizeIoc();
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020057
Szymon Dompkef763c9e2021-03-12 09:19:22 +010058 if (future.wait_for(precission) == std::future_status::ready)
59 {
60 sum = accumulator(sum, future.get());
61 }
62 else
63 {
64 elapsed += precission;
65 }
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020066 }
67 }
68
Szymon Dompkef763c9e2021-03-12 09:19:22 +010069 if (elapsed >= timeout)
70 {
71 throw std::runtime_error("Timed out while waiting for future");
72 }
73
74 return sum;
75 }
76
77 template <class T>
Krzysztof Grobelny80697712021-03-04 09:49:27 +000078 static T waitForFuture(std::future<T> future,
79 Milliseconds timeout = std::chrono::seconds(10))
Szymon Dompkef763c9e2021-03-12 09:19:22 +010080 {
81 std::vector<std::future<T>> futures;
82 futures.emplace_back(std::move(future));
83
Patrick Williamsf535cad2024-08-16 15:21:20 -040084 return waitForFutures(std::move(futures), T{},
85 [](auto, const auto& value) { return value; },
86 timeout);
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020087 }
88
Krzysztof Grobelny80697712021-03-04 09:49:27 +000089 static bool waitForFuture(std::string_view name,
90 Milliseconds timeout = std::chrono::seconds(10));
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +020091
Krzysztof Grobelny80697712021-03-04 09:49:27 +000092 static bool waitForFutures(std::string_view name,
93 Milliseconds timeout = std::chrono::seconds(10));
Szymon Dompkef763c9e2021-03-12 09:19:22 +010094
Szymon Dompkee28aa532021-10-27 12:33:12 +020095 template <class T>
96 static T getProperty(const std::string& path,
97 const std::string& interfaceName,
98 const std::string& property)
99 {
100 auto propertyPromise = std::promise<T>();
101 auto propertyFuture = propertyPromise.get_future();
102 sdbusplus::asio::getProperty<T>(
103 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
104 interfaceName, property,
105 [&propertyPromise](const boost::system::error_code& ec, T t) {
Patrick Williams3a1c2972023-05-10 07:51:04 -0500106 if (ec)
107 {
108 utils::setException(propertyPromise, "GetProperty failed");
109 return;
110 }
111 propertyPromise.set_value(t);
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500112 });
Szymon Dompkee28aa532021-10-27 12:33:12 +0200113 return DbusEnvironment::waitForFuture(std::move(propertyFuture));
114 }
115
116 template <class T>
117 static boost::system::error_code
118 setProperty(const std::string& path, const std::string& interfaceName,
119 const std::string& property, const T& newValue)
120 {
Krzysztof Grobelnyfbeb5bf2022-01-03 09:41:29 +0100121 auto promise = std::promise<boost::system::error_code>();
122 auto future = promise.get_future();
Szymon Dompkee28aa532021-10-27 12:33:12 +0200123 sdbusplus::asio::setProperty(
124 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
125 interfaceName, property, std::move(newValue),
Patrick Williams3a1c2972023-05-10 07:51:04 -0500126 [promise = std::move(promise)](
127 boost::system::error_code ec) mutable {
128 promise.set_value(ec);
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500129 });
Szymon Dompkee28aa532021-10-27 12:33:12 +0200130 return DbusEnvironment::waitForFuture(std::move(future));
131 }
132
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000133 template <class... Args>
134 static boost::system::error_code
135 callMethod(const std::string& path, const std::string& interface,
136 const std::string& method, Args&&... args)
137 {
138 auto promise = std::promise<boost::system::error_code>();
139 auto future = promise.get_future();
140 DbusEnvironment::getBus()->async_method_call(
141 [promise = std::move(promise)](
142 boost::system::error_code ec) mutable {
143 promise.set_value(ec);
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500144 },
Krzysztof Grobelnycff70c12022-10-27 07:16:08 +0000145 DbusEnvironment::serviceName(), path, interface, method,
146 std::forward<Args>(args)...);
147 return DbusEnvironment::waitForFuture(std::move(future));
148 }
149
Krzysztof Grobelnyb5645942020-09-29 11:52:45 +0200150 private:
151 static std::future<bool> getFuture(std::string_view name);
152
153 static boost::asio::io_context ioc;
154 static std::shared_ptr<sdbusplus::asio::connection> bus;
155 static std::shared_ptr<sdbusplus::asio::object_server> objServer;
156 static std::map<std::string, std::vector<std::future<bool>>> futures;
157 static bool setUp;
158};