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 <ripple/beast/unit_test/global_suites.hpp>
24 #include <ripple/beast/unit_test/runner.hpp>
25 #include <boost/beast/core/static_string.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 <sstream>
37 #include <string>
38 #include <thread>
39 #include <unordered_set>
40 #include <utility>
41 
42 namespace ripple {
43 namespace test {
44 
45 namespace detail {
46 
48 
50 {
54 
55  explicit case_results(std::string name_ = "") : name(std::move(name_))
56  {
57  }
58 };
59 
61 {
66  typename clock_type::time_point start = clock_type::now();
67 
68  explicit suite_results(std::string name_ = "") : name(std::move(name_))
69  {
70  }
71 
72  void
73  add(case_results const& r);
74 };
75 
76 struct results
77 {
78  using static_string = boost::beast::static_string<256>;
79  // results may be stored in shared memory. Use `static_string` to ensure
80  // pointers from different memory spaces do not co-mingle
82 
83  enum { max_top = 10 };
84 
89  boost::container::static_vector<run_time, max_top> top;
90  typename clock_type::time_point start = clock_type::now();
91 
92  void
93  add(suite_results const& r);
94 
95  void
96  merge(results const& r);
97 
98  template <class S>
99  void
100  print(S& s);
101 };
102 
103 template <bool IsParent>
105 {
106  // `inner` will be created in shared memory. This is one way
107  // multi_runner_parent and multi_runner_child object communicate. The other
108  // way they communicate is through message queues.
109  struct inner
110  {
114  // A parent process will periodically increment `keep_alive_`. The child
115  // processes will check if `keep_alive_` is being incremented. If it is
116  // not incremented for a sufficiently long time, the child will assume
117  // the parent process has died.
119 
120  mutable boost::interprocess::interprocess_mutex m_;
122 
125 
128 
129  bool
130  any_failed() const;
131 
132  void
133  any_failed(bool v);
134 
136  tests() const;
137 
139  suites() const;
140 
141  void
143 
146 
147  void
148  add(results const& r);
149 
150  template <class S>
151  void
152  print_results(S& s);
153  };
154 
155  static constexpr const char* shared_mem_name_ = "RippledUnitTestSharedMem";
156  // name of the message queue a multi_runner_child will use to communicate
157  // with multi_runner_parent
158  static constexpr const char* message_queue_name_ =
159  "RippledUnitTestMessageQueue";
160 
161  // `inner_` will be created in shared memory
162  inner* inner_;
163  // shared memory to use for the `inner` member
164  boost::interprocess::shared_memory_object shared_mem_;
165  boost::interprocess::mapped_region region_;
166 
167 protected:
169 
171  void
173 
174 public:
177 
180 
183 
184  void
185  any_failed(bool v);
186 
187  void
188  add(results const& r);
189 
190  void
192 
195 
196  template <class S>
197  void
198  print_results(S& s);
199 
200  bool
201  any_failed() const;
202 
204  tests() const;
205 
207  suites() const;
208 
209  void
210  add_failures(std::size_t failures);
211 };
212 
213 } // namespace detail
214 
215 //------------------------------------------------------------------------------
216 
219 class multi_runner_parent : private detail::multi_runner_base</*IsParent*/ true>
220 {
221 private:
222  // message_queue_ is used to collect log messages from the children
226  // track running suites so if a child crashes the culprit can be flagged
228 
229 public:
230  multi_runner_parent(multi_runner_parent const&) = delete;
232  operator=(multi_runner_parent const&) = delete;
233 
236 
237  bool
238  any_failed() const;
239 
241  tests() const;
242 
244  suites() const;
245 
246  void
247  add_failures(std::size_t failures);
248 };
249 
250 //------------------------------------------------------------------------------
251 
254 class multi_runner_child : public beast::unit_test::runner,
255  private detail::multi_runner_base</*IsParent*/ false>
256 {
257 private:
263  bool quiet_{false};
264  bool print_log_{true};
265 
268 
269 public:
270  multi_runner_child(multi_runner_child const&) = delete;
272  operator=(multi_runner_child const&) = delete;
273 
274  multi_runner_child(std::size_t num_jobs, bool quiet, bool print_log);
276 
278  tests() const;
279 
281  suites() const;
282 
283  void
284  add_failures(std::size_t failures);
285 
286  template <class Pred>
287  bool
288  run_multi(Pred pred);
289 
290 private:
291  virtual void
292  on_suite_begin(beast::unit_test::suite_info const& info) override;
293 
294  virtual void
295  on_suite_end() override;
296 
297  virtual void
298  on_case_begin(std::string const& name) override;
299 
300  virtual void
301  on_case_end() override;
302 
303  virtual void
304  on_pass() override;
305 
306  virtual void
307  on_fail(std::string const& reason) override;
308 
309  virtual void
310  on_log(std::string const& s) override;
311 };
312 
313 //------------------------------------------------------------------------------
314 
315 template <class Pred>
316 bool
318 {
319  auto const& suite = beast::unit_test::global_suites();
320  auto const num_tests = suite.size();
321  bool failed = false;
322 
323  auto get_test = [&]() -> beast::unit_test::suite_info const* {
324  auto const cur_test_index = checkout_test_index();
325  if (cur_test_index >= num_tests)
326  return nullptr;
327  auto iter = suite.begin();
328  std::advance(iter, cur_test_index);
329  return &*iter;
330  };
331  while (auto t = get_test())
332  {
333  if (!pred(*t))
334  continue;
335  try
336  {
337  failed = run(*t) || failed;
338  }
339  catch (...)
340  {
341  if (num_jobs_ <= 1)
342  throw; // a single process can die
343 
344  // inform the parent
346  s << job_index_ << "> failed Unhandled exception in test.\n";
347  message_queue_send(MessageType::log, s.str());
348  failed = true;
349  }
350  }
351  any_failed(failed);
352  return failed;
353 }
354 
355 } // namespace test
356 } // namespace ripple
357 
358 #endif
ripple::test::detail::results::suites
std::size_t suites
Definition: multi_runner.h:85
ripple::test::detail::multi_runner_base::suites
std::size_t suites() const
Definition: multi_runner.cpp:377
ripple::test::detail::multi_runner_base::checkout_test_index
std::size_t checkout_test_index()
Definition: multi_runner.cpp:301
sstream
ripple::test::detail::multi_runner_base::inner::print_results
void print_results(S &s)
Definition: multi_runner.cpp:227
std::chrono::steady_clock
ripple::test::multi_runner_child::run_multi
bool run_multi(Pred pred)
Definition: multi_runner.h:317
ripple::test::detail::suite_results::failed
std::size_t failed
Definition: multi_runner.h:65
ripple::test::detail::multi_runner_base::inner
Definition: multi_runner.h:109
std::string
STL class.
ripple::test::detail::suite_results::total
std::size_t total
Definition: multi_runner.h:64
ripple::test::multi_runner_parent::add_failures
void add_failures(std::size_t failures)
Definition: multi_runner.cpp:497
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:49
ripple::test::multi_runner_child::quiet_
bool quiet_
Definition: multi_runner.h:263
ripple::test::detail::multi_runner_base::inner::inc_keep_alive_count
void inc_keep_alive_count()
Definition: multi_runner.cpp:204
ripple::test::detail::suite_results::name
std::string name
Definition: multi_runner.h:62
ripple::test::detail::suite_results::suite_results
suite_results(std::string name_="")
Definition: multi_runner.h:68
ripple::test::detail::multi_runner_base::print_results
void print_results(S &s)
Definition: multi_runner.cpp:351
ripple::test::detail::multi_runner_base::shared_mem_name_
static constexpr const char * shared_mem_name_
Definition: multi_runner.h:155
ripple::test::detail::multi_runner_base::get_keep_alive_count
std::size_t get_keep_alive_count()
Definition: multi_runner.cpp:343
ripple::test::detail::multi_runner_base::shared_mem_
boost::interprocess::shared_memory_object shared_mem_
Definition: multi_runner.h:164
ripple::test::detail::multi_runner_base::add
void add(results const &r)
Definition: multi_runner.cpp:329
ripple::test::detail::multi_runner_base::inner::checkout_test_index
std::size_t checkout_test_index()
Definition: multi_runner.cpp:167
unordered_set
std::pair
ripple::test::detail::case_results::total
std::size_t total
Definition: multi_runner.h:52
ripple::test::multi_runner_child::print_log_
bool print_log_
Definition: multi_runner.h:264
ripple::test::detail::case_results::name
std::string name
Definition: multi_runner.h:51
ripple::test::detail::suite_results::start
clock_type::time_point start
Definition: multi_runner.h:66
ripple::test::detail::multi_runner_base::region_
boost::interprocess::mapped_region region_
Definition: multi_runner.h:165
ripple::test::multi_runner_parent::running_suites_
std::set< std::string > running_suites_
Definition: multi_runner.h:227
ripple::test::multi_runner_child::continue_keep_alive_
std::atomic< bool > continue_keep_alive_
Definition: multi_runner.h:266
ripple::test::detail::multi_runner_base::inner::results_
detail::results results_
Definition: multi_runner.h:121
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:358
ripple::test::detail::multi_runner_base::inner::m_
boost::interprocess::interprocess_mutex m_
Definition: multi_runner.h:120
ripple::test::multi_runner_child::on_suite_end
virtual void on_suite_end() override
Definition: multi_runner.cpp:584
ripple::test::multi_runner_child::tests
std::size_t tests() const
Definition: multi_runner.cpp:558
ripple::test::detail::multi_runner_base::inner::job_index_
std::atomic< std::size_t > job_index_
Definition: multi_runner.h:111
ripple::test::detail::suite_results
Definition: multi_runner.h:60
ripple::test::detail::results::add
void add(suite_results const &r)
Definition: multi_runner.cpp:65
ripple::test::detail::multi_runner_base::inner::keep_alive_
std::atomic< std::size_t > keep_alive_
Definition: multi_runner.h:118
ripple::test::detail::results
Definition: multi_runner.h:76
ripple::test::multi_runner_parent::suites
std::size_t suites() const
Definition: multi_runner.cpp:491
ripple::test::multi_runner_child::~multi_runner_child
~multi_runner_child()
Definition: multi_runner.cpp:546
ripple::test::detail::case_results::case_results
case_results(std::string name_="")
Definition: multi_runner.h:55
ripple::test::detail::multi_runner_base::inner::test_index_
std::atomic< std::size_t > test_index_
Definition: multi_runner.h:112
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:577
ripple::test::detail::results::max_top
@ max_top
Definition: multi_runner.h:83
ripple::test::detail::multi_runner_base::add_failures
void add_failures(std::size_t failures)
Definition: multi_runner.cpp:384
ripple::test::detail::multi_runner_base::inner_
inner * inner_
Definition: multi_runner.h:162
ripple::test::detail::results::cases
std::size_t cases
Definition: multi_runner.h:86
ripple::test::multi_runner_child::suites
std::size_t suites() const
Definition: multi_runner.cpp:564
thread
ripple::test::multi_runner_parent::continue_message_queue_
std::atomic< bool > continue_message_queue_
Definition: multi_runner.h:224
ripple::test::detail::multi_runner_base::checkout_job_index
std::size_t checkout_job_index()
Definition: multi_runner.cpp:308
std::ostream
STL class.
ripple::test::multi_runner_child::suite_results_
detail::suite_results suite_results_
Definition: multi_runner.h:260
ripple::test::detail::multi_runner_base::any_failed
bool any_failed() const
Definition: multi_runner.cpp:315
chrono
ripple::test::detail::multi_runner_base::inner::checkout_job_index
std::size_t checkout_job_index()
Definition: multi_runner.cpp:160
ripple::test::detail::multi_runner_base::inner::add
void add(results const &r)
Definition: multi_runner.cpp:218
ripple::test::multi_runner_parent::~multi_runner_parent
~multi_runner_parent()
Definition: multi_runner.cpp:462
ripple::test::multi_runner_child::results_
detail::results results_
Definition: multi_runner.h:259
ripple::test::detail::multi_runner_base< true >::MessageType
MessageType
Definition: multi_runner.h:170
ripple::test::detail::results::total
std::size_t total
Definition: multi_runner.h:87
ripple::test::multi_runner_child::on_log
virtual void on_log(std::string const &s) override
Definition: multi_runner.cpp:632
ripple::test::detail::suite_results::cases
std::size_t cases
Definition: multi_runner.h:63
ripple::test::multi_runner_child::add_failures
void add_failures(std::size_t failures)
Definition: multi_runner.cpp:570
ripple::test::multi_runner_child::num_jobs_
std::size_t num_jobs_
Definition: multi_runner.h:262
ripple::test::multi_runner_child::case_results_
detail::case_results case_results_
Definition: multi_runner.h:261
ripple::test::multi_runner_parent::any_failed
bool any_failed() const
Definition: multi_runner.cpp:479
std::uint8_t
ripple::test::multi_runner_parent::multi_runner_parent
multi_runner_parent()
Definition: multi_runner.cpp:396
ripple::test::detail::suite_results::add
void add(case_results const &r)
Definition: multi_runner.cpp:55
atomic
ripple::test::detail::multi_runner_base::inner::suites
std::size_t suites() const
Definition: multi_runner.cpp:196
ripple::test::detail::results::start
clock_type::time_point start
Definition: multi_runner.h:90
ripple::test::detail::results::print
void print(S &s)
Definition: multi_runner.cpp:139
std::advance
T advance(T... args)
ripple::test::multi_runner_child::on_case_end
virtual void on_case_end() override
Definition: multi_runner.cpp:607
ripple::test::multi_runner_parent::message_queue_thread_
std::thread message_queue_thread_
Definition: multi_runner.h:225
ripple::test::detail::multi_runner_base
Definition: multi_runner.h:104
ripple::test::detail::results::failed
std::size_t failed
Definition: multi_runner.h:88
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:613
ripple::test::multi_runner_child::on_fail
virtual void on_fail(std::string const &reason) override
Definition: multi_runner.cpp:619
ripple::test::detail::results::merge
void merge(results const &r)
Definition: multi_runner.cpp:111
ripple::test::detail::results::top
boost::container::static_vector< run_time, max_top > top
Definition: multi_runner.h:89
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:485
ripple::test::detail::multi_runner_base::tests
std::size_t tests() const
Definition: multi_runner.cpp:370
ripple::test::detail::multi_runner_base::message_queue_name_
static constexpr const char * message_queue_name_
Definition: multi_runner.h:158
ripple::test::detail::multi_runner_base::inner::tests
std::size_t tests() const
Definition: multi_runner.cpp:188
ripple::test::multi_runner_child
A class to run a subset of unit tests.
Definition: multi_runner.h:254
ripple::test::detail::multi_runner_base::inner::any_failed_
std::atomic< bool > any_failed_
Definition: multi_runner.h:113
ripple::test::detail::multi_runner_base::~multi_runner_base
~multi_runner_base()
Definition: multi_runner.cpp:289
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:336
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:78
numeric
ripple::test::multi_runner_parent
Manager for children running unit tests.
Definition: multi_runner.h:219
ripple::test::detail::multi_runner_base::inner::any_failed
bool any_failed() const
Definition: multi_runner.cpp:174
ripple::test::multi_runner_child::on_case_begin
virtual void on_case_begin(std::string const &name) override
Definition: multi_runner.cpp:591
ripple::test::multi_runner_child::job_index_
std::size_t job_index_
Definition: multi_runner.h:258
ripple::test::detail::multi_runner_base::message_queue_
std::unique_ptr< boost::interprocess::message_queue > message_queue_
Definition: multi_runner.h:168
std::unique_ptr< boost::interprocess::message_queue >
ripple::test::multi_runner_parent::os_
std::ostream & os_
Definition: multi_runner.h:223
std::set< std::string >
ripple::test::detail::multi_runner_base::multi_runner_base
multi_runner_base()
Definition: multi_runner.cpp:234
ripple::test::detail::multi_runner_base::inner::get_keep_alive_count
std::size_t get_keep_alive_count()
Definition: multi_runner.cpp:211
ripple::test::multi_runner_child::keep_alive_thread_
std::thread keep_alive_thread_
Definition: multi_runner.h:267
ripple::test::detail::case_results::failed
std::size_t failed
Definition: multi_runner.h:53
string
std::chrono::steady_clock::now
T now(T... args)