rippled
multi_runner.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2017 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef TEST_UNIT_TEST_MULTI_RUNNER_H
21 #define TEST_UNIT_TEST_MULTI_RUNNER_H
22 
23 #include <boost/beast/core/static_string.hpp>
24 #include <beast/unit_test/global_suites.hpp>
25 #include <beast/unit_test/runner.hpp>
26 
27 #include <boost/container/static_vector.hpp>
28 #include <boost/interprocess/ipc/message_queue.hpp>
29 #include <boost/interprocess/mapped_region.hpp>
30 #include <boost/interprocess/shared_memory_object.hpp>
31 #include <boost/interprocess/sync/interprocess_mutex.hpp>
32 
33 #include <atomic>
34 #include <chrono>
35 #include <numeric>
36 #include <string>
37 #include <thread>
38 #include <unordered_set>
39 #include <utility>
40 
41 namespace ripple {
42 namespace test {
43 
44 namespace detail {
45 
47 
49 {
53 
54  explicit case_results(std::string name_ = "") : name(std::move(name_))
55  {
56  }
57 };
58 
60 {
65  typename clock_type::time_point start = clock_type::now();
66 
67  explicit suite_results(std::string name_ = "") : name(std::move(name_))
68  {
69  }
70 
71  void
72  add(case_results const& r);
73 };
74 
75 struct results
76 {
77  using static_string = boost::beast::static_string<256>;
78  // results may be stored in shared memory. Use `static_string` to ensure
79  // pointers from different memory spaces do not co-mingle
81 
82  enum { max_top = 10 };
83 
88  boost::container::static_vector<run_time, max_top> top;
89  typename clock_type::time_point start = clock_type::now();
90 
91  void
92  add(suite_results const& r);
93 
94  void
95  merge(results const& r);
96 
97  template <class S>
98  void
99  print(S& s);
100 };
101 
102 template <bool IsParent>
104 {
105  // `inner` will be created in shared memory. This is one way
106  // multi_runner_parent and multi_runner_child object communicate. The other
107  // way they communicate is through message queues.
108  struct inner
109  {
113  // A parent process will periodically increment `keep_alive_`. The child
114  // processes will check if `keep_alive_` is being incremented. If it is
115  // not incremented for a sufficiently long time, the child will assume
116  // the parent process has died.
118 
119  mutable boost::interprocess::interprocess_mutex m_;
121 
124 
127 
128  bool
129  any_failed() const;
130 
131  void
132  any_failed(bool v);
133 
135  tests() const;
136 
138  suites() const;
139 
140  void
142 
145 
146  void
147  add(results const& r);
148 
149  template <class S>
150  void
151  print_results(S& s);
152  };
153 
154  static constexpr const char* shared_mem_name_ = "RippledUnitTestSharedMem";
155  // name of the message queue a multi_runner_child will use to communicate
156  // with multi_runner_parent
157  static constexpr const char* message_queue_name_ =
158  "RippledUnitTestMessageQueue";
159 
160  // `inner_` will be created in shared memory
161  inner* inner_;
162  // shared memory to use for the `inner` member
163  boost::interprocess::shared_memory_object shared_mem_;
164  boost::interprocess::mapped_region region_;
165 
166 protected:
168 
170  void
172 
173 public:
176 
179 
182 
183  void
184  any_failed(bool v);
185 
186  void
187  add(results const& r);
188 
189  void
191 
194 
195  template <class S>
196  void
197  print_results(S& s);
198 
199  bool
200  any_failed() const;
201 
203  tests() const;
204 
206  suites() const;
207 
208  void
209  add_failures(std::size_t failures);
210 };
211 
212 } // namespace detail
213 
214 //------------------------------------------------------------------------------
215 
218 class multi_runner_parent : private detail::multi_runner_base</*IsParent*/ true>
219 {
220 private:
221  // message_queue_ is used to collect log messages from the children
225  // track running suites so if a child crashes the culprit can be flagged
227 
228 public:
229  multi_runner_parent(multi_runner_parent const&) = delete;
231  operator=(multi_runner_parent const&) = delete;
232 
235 
236  bool
237  any_failed() const;
238 
240  tests() const;
241 
243  suites() const;
244 
245  void
246  add_failures(std::size_t failures);
247 };
248 
249 //------------------------------------------------------------------------------
250 
253 class multi_runner_child : public beast::unit_test::runner,
254  private detail::multi_runner_base</*IsParent*/ false>
255 {
256 private:
262  bool quiet_{false};
263  bool print_log_{true};
264 
267 
268 public:
269  multi_runner_child(multi_runner_child const&) = delete;
271  operator=(multi_runner_child const&) = delete;
272 
273  multi_runner_child(std::size_t num_jobs, bool quiet, bool print_log);
275 
277  tests() const;
278 
280  suites() const;
281 
282  void
283  add_failures(std::size_t failures);
284 
285  template <class Pred>
286  bool
287  run_multi(Pred pred);
288 
289 private:
290  virtual void
291  on_suite_begin(beast::unit_test::suite_info const& info) override;
292 
293  virtual void
294  on_suite_end() override;
295 
296  virtual void
297  on_case_begin(std::string const& name) override;
298 
299  virtual void
300  on_case_end() override;
301 
302  virtual void
303  on_pass() override;
304 
305  virtual void
306  on_fail(std::string const& reason) override;
307 
308  virtual void
309  on_log(std::string const& s) override;
310 };
311 
312 //------------------------------------------------------------------------------
313 
314 template <class Pred>
315 bool
317 {
318  auto const& suite = beast::unit_test::global_suites();
319  auto const num_tests = suite.size();
320  bool failed = false;
321 
322  auto get_test = [&]() -> beast::unit_test::suite_info const* {
323  auto const cur_test_index = checkout_test_index();
324  if (cur_test_index >= num_tests)
325  return nullptr;
326  auto iter = suite.begin();
327  std::advance(iter, cur_test_index);
328  return &*iter;
329  };
330  while (auto t = get_test())
331  {
332  if (!pred(*t))
333  continue;
334  try
335  {
336  failed = run(*t) || failed;
337  }
338  catch (...)
339  {
340  if (num_jobs_ <= 1)
341  throw; // a single process can die
342 
343  // inform the parent
345  s << job_index_ << "> failed Unhandled exception in test.\n";
346  message_queue_send(MessageType::log, s.str());
347  failed = true;
348  }
349  }
350  any_failed(failed);
351  return failed;
352 }
353 
354 } // namespace test
355 } // namespace ripple
356 
357 #endif
ripple::test::detail::results::suites
std::size_t suites
Definition: multi_runner.h:84
ripple::test::detail::multi_runner_base::suites
std::size_t suites() const
Definition: multi_runner.cpp:376
ripple::test::detail::multi_runner_base::checkout_test_index
std::size_t checkout_test_index()
Definition: multi_runner.cpp:300
ripple::test::detail::multi_runner_base::inner::print_results
void print_results(S &s)
Definition: multi_runner.cpp:226
std::chrono::steady_clock
ripple::test::multi_runner_child::run_multi
bool run_multi(Pred pred)
Definition: multi_runner.h:316
ripple::test::detail::suite_results::failed
std::size_t failed
Definition: multi_runner.h:64
ripple::test::detail::multi_runner_base::inner
Definition: multi_runner.h:108
std::string
STL class.
ripple::test::detail::suite_results::total
std::size_t total
Definition: multi_runner.h:63
ripple::test::multi_runner_parent::add_failures
void add_failures(std::size_t failures)
Definition: multi_runner.cpp:501
ripple::test::detail::multi_runner_base::MessageType::test_start
@ test_start
ripple::test::multi_runner_parent::operator=
multi_runner_parent & operator=(multi_runner_parent const &)=delete
utility
ripple::test::detail::case_results
Definition: multi_runner.h:48
ripple::test::multi_runner_child::quiet_
bool quiet_
Definition: multi_runner.h:262
ripple::test::detail::multi_runner_base::inner::inc_keep_alive_count
void inc_keep_alive_count()
Definition: multi_runner.cpp:203
ripple::test::detail::suite_results::name
std::string name
Definition: multi_runner.h:61
ripple::test::detail::suite_results::suite_results
suite_results(std::string name_="")
Definition: multi_runner.h:67
ripple::test::detail::multi_runner_base::print_results
void print_results(S &s)
Definition: multi_runner.cpp:350
ripple::test::detail::multi_runner_base::get_keep_alive_count
std::size_t get_keep_alive_count()
Definition: multi_runner.cpp:342
ripple::test::detail::multi_runner_base::shared_mem_
boost::interprocess::shared_memory_object shared_mem_
Definition: multi_runner.h:163
ripple::test::detail::multi_runner_base::add
void add(results const &r)
Definition: multi_runner.cpp:328
ripple::test::detail::multi_runner_base::inner::checkout_test_index
std::size_t checkout_test_index()
Definition: multi_runner.cpp:166
unordered_set
std::pair
ripple::test::detail::case_results::total
std::size_t total
Definition: multi_runner.h:51
ripple::test::multi_runner_child::print_log_
bool print_log_
Definition: multi_runner.h:263
ripple::test::detail::case_results::name
std::string name
Definition: multi_runner.h:50
ripple::test::detail::suite_results::start
clock_type::time_point start
Definition: multi_runner.h:65
ripple::test::detail::multi_runner_base::region_
boost::interprocess::mapped_region region_
Definition: multi_runner.h:164
ripple::test::multi_runner_parent::running_suites_
std::set< std::string > running_suites_
Definition: multi_runner.h:226
ripple::test::multi_runner_child::continue_keep_alive_
std::atomic< bool > continue_keep_alive_
Definition: multi_runner.h:265
ripple::test::detail::multi_runner_base::inner::results_
detail::results results_
Definition: multi_runner.h:120
std::stringstream
STL class.
ripple::test::detail::multi_runner_base::message_queue_send
void message_queue_send(MessageType mt, std::string const &s)
Definition: multi_runner.cpp:357
ripple::test::detail::multi_runner_base::inner::m_
boost::interprocess::interprocess_mutex m_
Definition: multi_runner.h:119
ripple::test::multi_runner_child::on_suite_end
virtual void on_suite_end() override
Definition: multi_runner.cpp:589
ripple::test::multi_runner_child::tests
std::size_t tests() const
Definition: multi_runner.cpp:563
ripple::test::detail::multi_runner_base::inner::job_index_
std::atomic< std::size_t > job_index_
Definition: multi_runner.h:110
ripple::test::detail::suite_results
Definition: multi_runner.h:59
ripple::test::detail::results::add
void add(suite_results const &r)
Definition: multi_runner.cpp:64
ripple::test::detail::multi_runner_base::inner::keep_alive_
std::atomic< std::size_t > keep_alive_
Definition: multi_runner.h:117
ripple::test::detail::results
Definition: multi_runner.h:75
ripple::test::multi_runner_parent::suites
std::size_t suites() const
Definition: multi_runner.cpp:495
ripple::test::multi_runner_child::~multi_runner_child
~multi_runner_child()
Definition: multi_runner.cpp:551
ripple::test::detail::case_results::case_results
case_results(std::string name_="")
Definition: multi_runner.h:54
ripple::test::detail::multi_runner_base::inner::test_index_
std::atomic< std::size_t > test_index_
Definition: multi_runner.h:111
ripple::test::multi_runner_child::on_suite_begin
virtual void on_suite_begin(beast::unit_test::suite_info const &info) override
Definition: multi_runner.cpp:582
ripple::test::detail::multi_runner_base::add_failures
void add_failures(std::size_t failures)
Definition: multi_runner.cpp:383
ripple::test::detail::multi_runner_base::inner_
inner * inner_
Definition: multi_runner.h:161
ripple::test::detail::results::cases
std::size_t cases
Definition: multi_runner.h:85
ripple::test::multi_runner_child::suites
std::size_t suites() const
Definition: multi_runner.cpp:569
thread
ripple::test::multi_runner_parent::continue_message_queue_
std::atomic< bool > continue_message_queue_
Definition: multi_runner.h:223
ripple::test::detail::multi_runner_base::checkout_job_index
std::size_t checkout_job_index()
Definition: multi_runner.cpp:307
std::ostream
STL class.
ripple::test::multi_runner_child::suite_results_
detail::suite_results suite_results_
Definition: multi_runner.h:259
ripple::test::detail::multi_runner_base::any_failed
bool any_failed() const
Definition: multi_runner.cpp:314
chrono
ripple::test::detail::multi_runner_base::inner::checkout_job_index
std::size_t checkout_job_index()
Definition: multi_runner.cpp:159
ripple::test::detail::multi_runner_base::inner::add
void add(results const &r)
Definition: multi_runner.cpp:217
ripple::test::multi_runner_parent::~multi_runner_parent
~multi_runner_parent()
Definition: multi_runner.cpp:466
ripple::test::detail::multi_runner_base::shared_mem_name_
static constexpr const char * shared_mem_name_
Definition: multi_runner.h:154
ripple::test::multi_runner_child::results_
detail::results results_
Definition: multi_runner.h:258
ripple::test::detail::multi_runner_base< true >::MessageType
MessageType
Definition: multi_runner.h:169
ripple::test::detail::results::total
std::size_t total
Definition: multi_runner.h:86
ripple::test::multi_runner_child::on_log
virtual void on_log(std::string const &s) override
Definition: multi_runner.cpp:637
ripple::test::detail::suite_results::cases
std::size_t cases
Definition: multi_runner.h:62
ripple::test::multi_runner_child::add_failures
void add_failures(std::size_t failures)
Definition: multi_runner.cpp:575
ripple::test::multi_runner_child::num_jobs_
std::size_t num_jobs_
Definition: multi_runner.h:261
ripple::test::multi_runner_child::case_results_
detail::case_results case_results_
Definition: multi_runner.h:260
ripple::test::multi_runner_parent::any_failed
bool any_failed() const
Definition: multi_runner.cpp:483
std::uint8_t
ripple::test::multi_runner_parent::multi_runner_parent
multi_runner_parent()
Definition: multi_runner.cpp:400
ripple::test::detail::suite_results::add
void add(case_results const &r)
Definition: multi_runner.cpp:54
atomic
ripple::test::detail::multi_runner_base::inner::suites
std::size_t suites() const
Definition: multi_runner.cpp:195
ripple::test::detail::results::start
clock_type::time_point start
Definition: multi_runner.h:89
ripple::test::detail::results::print
void print(S &s)
Definition: multi_runner.cpp:138
std::advance
T advance(T... args)
ripple::test::multi_runner_child::on_case_end
virtual void on_case_end() override
Definition: multi_runner.cpp:612
ripple::test::multi_runner_parent::message_queue_thread_
std::thread message_queue_thread_
Definition: multi_runner.h:224
ripple::test::detail::multi_runner_base
Definition: multi_runner.h:103
ripple::test::detail::results::failed
std::size_t failed
Definition: multi_runner.h:87
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::multi_runner_child::on_pass
virtual void on_pass() override
Definition: multi_runner.cpp:618
ripple::test::multi_runner_child::on_fail
virtual void on_fail(std::string const &reason) override
Definition: multi_runner.cpp:624
ripple::test::detail::results::merge
void merge(results const &r)
Definition: multi_runner.cpp:110
ripple::test::detail::results::top
boost::container::static_vector< run_time, max_top > top
Definition: multi_runner.h:88
std
STL namespace.
ripple::test::detail::multi_runner_base::MessageType::test_end
@ test_end
ripple::test::multi_runner_child::operator=
multi_runner_child & operator=(multi_runner_child const &)=delete
ripple::test::multi_runner_parent::tests
std::size_t tests() const
Definition: multi_runner.cpp:489
ripple::test::detail::multi_runner_base::tests
std::size_t tests() const
Definition: multi_runner.cpp:369
ripple::test::detail::multi_runner_base::inner::tests
std::size_t tests() const
Definition: multi_runner.cpp:187
ripple::test::multi_runner_child
A class to run a subset of unit tests.
Definition: multi_runner.h:253
ripple::test::detail::multi_runner_base::inner::any_failed_
std::atomic< bool > any_failed_
Definition: multi_runner.h:112
ripple::test::detail::multi_runner_base::~multi_runner_base
~multi_runner_base()
Definition: multi_runner.cpp:288
std::stringstream::str
T str(T... args)
std::size_t
ripple::test::multi_runner_child::multi_runner_child
multi_runner_child(multi_runner_child const &)=delete
ripple::test::detail::multi_runner_base::inc_keep_alive_count
void inc_keep_alive_count()
Definition: multi_runner.cpp:335
ripple::test::detail::multi_runner_base::MessageType::log
@ log
ripple::test::detail::results::static_string
boost::beast::static_string< 256 > static_string
Definition: multi_runner.h:77
numeric
ripple::test::multi_runner_parent
Manager for children running unit tests.
Definition: multi_runner.h:218
ripple::test::detail::multi_runner_base::inner::any_failed
bool any_failed() const
Definition: multi_runner.cpp:173
ripple::test::detail::multi_runner_base::message_queue_name_
static constexpr const char * message_queue_name_
Definition: multi_runner.h:157
ripple::test::multi_runner_child::on_case_begin
virtual void on_case_begin(std::string const &name) override
Definition: multi_runner.cpp:596
ripple::test::multi_runner_child::job_index_
std::size_t job_index_
Definition: multi_runner.h:257
ripple::test::detail::multi_runner_base::message_queue_
std::unique_ptr< boost::interprocess::message_queue > message_queue_
Definition: multi_runner.h:167
std::unique_ptr< boost::interprocess::message_queue >
ripple::test::multi_runner_parent::os_
std::ostream & os_
Definition: multi_runner.h:222
std::set< std::string >
ripple::test::detail::multi_runner_base::multi_runner_base
multi_runner_base()
Definition: multi_runner.cpp:233
ripple::test::detail::results::max_top
@ max_top
Definition: multi_runner.h:82
ripple::test::detail::multi_runner_base::inner::get_keep_alive_count
std::size_t get_keep_alive_count()
Definition: multi_runner.cpp:210
ripple::test::multi_runner_child::keep_alive_thread_
std::thread keep_alive_thread_
Definition: multi_runner.h:266
ripple::test::detail::case_results::failed
std::size_t failed
Definition: multi_runner.h:52
string
std::chrono::steady_clock::now
T now(T... args)