Run unit tests in parallel

This commit is contained in:
seelabs
2017-09-01 09:50:22 -04:00
parent 6ff5d3734f
commit 07e3f81b76
16 changed files with 1045 additions and 265 deletions

View File

@@ -18,6 +18,7 @@
//==============================================================================
#include <BeastConfig.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/digest.h>
#include <ripple/app/main/Application.h>
@@ -39,21 +40,30 @@
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/beast/core/Time.h>
#include <ripple/beast/utility/Debug.h>
#include <beast/unit_test/dstream.hpp>
#include <beast/unit_test/global_suites.hpp>
#include <beast/unit_test/match.hpp>
#include <beast/unit_test/reporter.hpp>
#include <test/quiet_reporter.h>
#include <test/unit_test/multi_runner.h>
#include <google/protobuf/stubs/common.h>
#include <boost/program_options.hpp>
#include <boost/version.hpp>
#include <cstdlib>
#include <iostream>
#include <utility>
#include <stdexcept>
#if defined(BEAST_LINUX) || defined(BEAST_MAC) || defined(BEAST_BSD)
#include <sys/resource.h>
#if BOOST_VERSION >= 106400
#define HAS_BOOST_PROCESS 1
#endif
#if HAS_BOOST_PROCESS
#include <boost/process.hpp>
#endif
namespace po = boost::program_options;
@@ -172,23 +182,70 @@ static int runUnitTests(
std::string const& pattern,
std::string const& argument,
bool quiet,
bool log)
bool log,
bool child,
std::size_t num_jobs,
int argc,
char** argv)
{
using namespace beast::unit_test;
using namespace ripple::test;
beast::unit_test::dstream dout{std::cout};
std::unique_ptr<runner> r;
if(quiet)
r = std::make_unique<quiet_reporter>(dout, log);
#if HAS_BOOST_PROCESS
if (!child && num_jobs == 1)
#endif
{
multi_runner_parent parent_runner;
multi_runner_child child_runner{num_jobs, quiet, log};
auto const any_failed = child_runner.run_multi(match_auto(pattern));
if (any_failed)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
#if HAS_BOOST_PROCESS
if (!child)
{
multi_runner_parent parent_runner;
std::vector<boost::process::child> children;
std::string const exe_name = argv[0];
std::vector<std::string> args;
{
args.reserve(argc);
for (int i = 1; i < argc; ++i)
args.emplace_back(argv[i]);
args.emplace_back("--unittest-child");
}
for (std::size_t i = 0; i < num_jobs; ++i)
children.emplace_back(
boost::process::exe = exe_name, boost::process::args = args);
int bad_child_exits = 0;
for(auto& c : children)
{
c.wait();
if (c.exit_code())
++bad_child_exits;
}
if (parent_runner.any_failed() || bad_child_exits)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
else
r = std::make_unique<reporter>(dout);
r->arg(argument);
bool const anyFailed = r->run_each_if(
global_suites(), match_auto(pattern));
if(anyFailed)
return EXIT_FAILURE;
return EXIT_SUCCESS;
{
// child
multi_runner_child runner{num_jobs, quiet, log};
auto const anyFailed = runner.run_multi(match_auto(pattern));
if (anyFailed)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
#endif
}
//------------------------------------------------------------------------------
@@ -227,6 +284,10 @@ int run (int argc, char** argv)
("unittest,u", po::value <std::string> ()->implicit_value (""), "Perform unit tests.")
("unittest-arg", po::value <std::string> ()->implicit_value (""), "Supplies argument to unit tests.")
("unittest-log", po::value <std::string> ()->implicit_value (""), "Force unit test log output, even in quiet mode.")
#if HAS_BOOST_PROCESS
("unittest-jobs", po::value <std::size_t> (), "Number of unittest jobs to run.")
("unittest-child", "For internal use only. Run the process as a unit test child process.")
#endif
("parameters", po::value< vector<string> > (), "Specify comma separated parameters.")
("quiet,q", "Reduce diagnotics.")
("quorum", po::value <std::size_t> (), "Override the minimum validation quorum.")
@@ -288,10 +349,35 @@ int run (int argc, char** argv)
if (vm.count("unittest-arg"))
argument = vm["unittest-arg"].as<std::string>();
std::size_t numJobs = 1;
bool unittestChild = false;
#if HAS_BOOST_PROCESS
if (vm.count("unittest-jobs"))
numJobs = std::max(numJobs, vm["unittest-jobs"].as<std::size_t>());
unittestChild = bool (vm.count("unittest-child"));
#endif
return runUnitTests(
vm["unittest"].as<std::string>(), argument,
bool (vm.count ("quiet")),
bool (vm.count ("unittest-log")));
bool (vm.count ("unittest-log")),
unittestChild,
numJobs,
argc,
argv);
}
else
{
#if HAS_BOOST_PROCESS
if (vm.count("unittest-jobs"))
{
// unittest jobs only makes sense with `unittest`
std::cerr << "rippled: '--unittest-jobs' specified without '--unittest'.\n";
std::cerr << "To run the unit tests the '--unittest' option must be present.\n";
return 1;
}
#endif
}
auto config = std::make_unique<Config>();