1 #pragma once 2 3 #include "types/duration_types.hpp" 4 #include "utils/set_exception.hpp" 5 6 #include <sdbusplus/asio/object_server.hpp> 7 #include <sdbusplus/asio/property.hpp> 8 9 #include <future> 10 #include <thread> 11 12 #include <gmock/gmock.h> 13 14 class 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); 28 static void sleepFor(Milliseconds); 29 static Milliseconds measureTime(std::function<void()>); 30 31 static void synchronizeIoc() 32 { 33 while (ioc.poll() > 0) 34 {} 35 } 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 44 template <class T, class F> 45 static T waitForFutures(std::vector<std::future<T>> futures, T init, 46 F&& accumulator, 47 Milliseconds timeout = std::chrono::seconds(10)) 48 { 49 constexpr auto precission = Milliseconds(10); 50 auto elapsed = Milliseconds(0); 51 52 auto sum = init; 53 for (auto& future : futures) 54 { 55 while (future.valid() && elapsed < timeout) 56 { 57 synchronizeIoc(); 58 59 if (future.wait_for(precission) == std::future_status::ready) 60 { 61 sum = accumulator(sum, future.get()); 62 } 63 else 64 { 65 elapsed += precission; 66 } 67 } 68 } 69 70 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> 79 static T waitForFuture(std::future<T> future, 80 Milliseconds timeout = std::chrono::seconds(10)) 81 { 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); 88 } 89 90 static bool waitForFuture(std::string_view name, 91 Milliseconds timeout = std::chrono::seconds(10)); 92 93 static bool waitForFutures(std::string_view name, 94 Milliseconds timeout = std::chrono::seconds(10)); 95 96 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) { 107 if (ec) 108 { 109 utils::setException(propertyPromise, "GetProperty failed"); 110 return; 111 } 112 propertyPromise.set_value(t); 113 }); 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 { 122 auto promise = std::promise<boost::system::error_code>(); 123 auto future = promise.get_future(); 124 sdbusplus::asio::setProperty( 125 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path, 126 interfaceName, property, std::move(newValue), 127 [promise = std::move(promise)]( 128 boost::system::error_code ec) mutable { 129 promise.set_value(ec); 130 }); 131 return DbusEnvironment::waitForFuture(std::move(future)); 132 } 133 134 template <class... Args> 135 static boost::system::error_code 136 callMethod(const std::string& path, const std::string& interface, 137 const std::string& method, Args&&... args) 138 { 139 auto promise = std::promise<boost::system::error_code>(); 140 auto future = promise.get_future(); 141 DbusEnvironment::getBus()->async_method_call( 142 [promise = std::move(promise)]( 143 boost::system::error_code ec) mutable { 144 promise.set_value(ec); 145 }, 146 DbusEnvironment::serviceName(), path, interface, method, 147 std::forward<Args>(args)...); 148 return DbusEnvironment::waitForFuture(std::move(future)); 149 } 150 151 private: 152 static std::future<bool> getFuture(std::string_view name); 153 154 static boost::asio::io_context ioc; 155 static std::shared_ptr<sdbusplus::asio::connection> bus; 156 static std::shared_ptr<sdbusplus::asio::object_server> objServer; 157 static std::map<std::string, std::vector<std::future<bool>>> futures; 158 static bool setUp; 159 }; 160