ifw-daq  3.0.0-pre2
IFW Data Acquisition modules
progress.hpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_common_utsupport
4  * @copyright (c) Copyright ESO 2022
5  * All Rights Reserved
6  * ESO (eso.org) is an Intergovernmental Organisation, and therefore special legal conditions apply.
7  *
8  * @brief Defines shared test progress utilities.
9  */
10 #ifndef OCM_DAQ_TEST_PROGRESS_HPP
11 #define OCM_DAQ_TEST_PROGRESS_HPP
12 // GCOVR_EXCL_START
13 #include <thread>
14 #include <chrono>
15 
16 #include <boost/chrono.hpp>
17 
18 #include <boost/asio/io_context.hpp>
19 #include <gtest/gtest.h>
20 
21 namespace daq::test {
22 /**
23  * Executes io_ctx::poll until @a pred returns true or it times out.
24  */
25 template<class Predicate>
26 void MakeTestProgressUntil(boost::asio::io_context& io_ctx, Predicate&& pred, std::chrono::milliseconds
27  timeout = std::chrono::seconds(3)) {
28  auto until = std::chrono::steady_clock::now() + timeout;
29 
30  while(std::chrono::steady_clock::now() < until) {
31  io_ctx.restart();
32  io_ctx.poll();
33  if (pred()) {
34  return;
35  }
36  }
37  FAIL() << "MakeTestProgressUntil timed out";
38 }
39 
40 /**
41  * Test helper that progress the test by executing pending jobs and optionally wait for
42  * a future to be ready.
43  *
44  * @ingroup daq_ocm_libdaq_test
45  */
46 template <class Future = void>
47 void MakeTestProgress(boost::asio::io_context& io_ctx, Future* fut = nullptr) {
48  using namespace std::chrono;
49  using namespace ::testing;
50 
51  auto work = std::make_unique<boost::asio::io_context::work>(io_ctx);
52 
53  // Run asio in its own thread so we can independenty wait for future
54  std::thread t([&]() {
55  try {
56  io_ctx.restart();
57  io_ctx.run();
58  // The run() function blocks until all work has finished and there are no more handlers to be dispatched
59  // or until the io_context has been stopped.
60  } catch (std::exception const& e) {
61  FAIL() << "MakeTestProgress caught std::exception: " << e.what();
62  } catch (...) {
63  FAIL() << "MakeTestProgress caught unknown exception";
64  }
65  });
66  std::this_thread::yield();
67  if constexpr (!std::is_same_v<Future, void>) {
68  if (fut) {
69  EXPECT_NO_THROW(fut->wait_for(boost::chrono::seconds(3)));
70  }
71  // remove work so that asio::io_context::run returns
72  work.reset();
73  // Explicitly stop io_ctx if future is ready. I.e. even if there are handlers pending
74  // we want to stop here since the caller might set up next step in the test.
75  io_ctx.stop();
76  t.join();
77  if (fut) {
78  ASSERT_TRUE(fut->is_ready()) << "Future is not ready after 1s, aborting";
79  }
80  } else {
81  // remove work so that asio::io_context::run returns
82  work.reset();
83  t.join();
84  }
85 }
86 
87 } // namespace daq::test
88 // GCOVR_EXCL_STOP
89 #endif // #ifndef OCM_DAQ_TEST_PROGRESS_HPP
90 
void MakeTestProgress(boost::asio::io_context &io_ctx, Future *fut=nullptr)
Test helper that progress the test by executing pending jobs and optionally wait for a future to be r...
Definition: progress.hpp:47
void MakeTestProgressUntil(boost::asio::io_context &io_ctx, Predicate &&pred, std::chrono::milliseconds timeout=std::chrono::seconds(3))
Executes io_ctx::poll until pred returns true or it times out.
Definition: progress.hpp:26