test: parse the command line arguments in unit tests

Retrieve the command line arguments from boost and pass them to
`BasicTestingSetup` so that we gain extra flexibility of passing any
config options on the test command line, e.g.:

```
test_bitcoin -- -printtoconsole=1 -checkaddrman=5
```
This commit is contained in:
Vasil Dimov 2021-10-08 18:11:40 +02:00
parent c561f2f06e
commit 92a0f7e58d
No known key found for this signature in database
GPG key ID: 54DF06F64B55CBBF
7 changed files with 56 additions and 12 deletions

View file

@ -19,6 +19,8 @@ using namespace std::chrono_literals;
const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
namespace { namespace {
void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl) void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl)

View file

@ -22,6 +22,7 @@
#include <QApplication> #include <QApplication>
#include <QObject> #include <QObject>
#include <QTest> #include <QTest>
#include <functional>
#if defined(QT_STATICPLUGIN) #if defined(QT_STATICPLUGIN)
#include <QtPlugin> #include <QtPlugin>
@ -43,6 +44,8 @@ using node::NodeContext;
const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
// This is all you need to run all the tests // This is all you need to run all the tests
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {

View file

@ -33,19 +33,31 @@ the `src/qt/test/test_main.cpp` file.
### Running individual tests ### Running individual tests
`test_bitcoin` has some built-in command-line arguments; for `test_bitcoin` accepts the command line arguments from the boost framework.
example, to run just the `getarg_tests` verbosely: For example, to run just the `getarg_tests` suite of tests:
test_bitcoin --log_level=all --run_test=getarg_tests -- DEBUG_LOG_OUT ```bash
test_bitcoin --log_level=all --run_test=getarg_tests
```
`log_level` controls the verbosity of the test framework, which logs when a `log_level` controls the verbosity of the test framework, which logs when a
test case is entered, for example. The `DEBUG_LOG_OUT` after the two dashes test case is entered, for example. `test_bitcoin` also accepts the command
redirects the debug log, which would normally go to a file in the test datadir line arguments accepted by `bitcoind`. Use `--` to separate both types of
arguments:
```bash
test_bitcoin --log_level=all --run_test=getarg_tests -- -printtoconsole=1
```
The `-printtoconsole=1` after the two dashes redirects the debug log, which
would normally go to a file in the test datadir
(`BasicTestingSetup::m_path_root`), to the standard terminal output. (`BasicTestingSetup::m_path_root`), to the standard terminal output.
... or to run just the doubledash test: ... or to run just the doubledash test:
```bash
test_bitcoin --run_test=getarg_tests/doubledash test_bitcoin --run_test=getarg_tests/doubledash
```
Run `test_bitcoin --help` for the full list. Run `test_bitcoin --help` for the full list.

View file

@ -12,6 +12,7 @@
#include <cstdint> #include <cstdint>
#include <exception> #include <exception>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unistd.h> #include <unistd.h>
@ -19,6 +20,8 @@
const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets() std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
{ {
static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets; static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;

View file

@ -11,6 +11,7 @@
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <functional>
#include <iostream> #include <iostream>
/** Redirect debug log to unit_test.log files */ /** Redirect debug log to unit_test.log files */
@ -24,3 +25,17 @@ const std::function<void(const std::string&)> G_TEST_LOG_FUN = [](const std::str
if (!should_log) return; if (!should_log) return;
std::cout << s; std::cout << s;
}; };
/**
* Retrieve the command line arguments from boost.
* Allows usage like:
* `test_bitcoin --run_test="net_tests/cnode_listen_port" -- -checkaddrman=1 -printtoconsole=1`
* which would return `["-checkaddrman=1", "-printtoconsole=1"]`.
*/
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() {
std::vector<const char*> args;
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) {
args.push_back(boost::unit_test::framework::master_test_suite().argv[i]);
}
return args;
};

View file

@ -42,6 +42,7 @@
#include <walletinitinterface.h> #include <walletinitinterface.h>
#include <functional> #include <functional>
#include <stdexcept>
using node::BlockAssembler; using node::BlockAssembler;
using node::CalculateCacheSizes; using node::CalculateCacheSizes;
@ -88,7 +89,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
m_args{} m_args{}
{ {
m_node.args = &gArgs; m_node.args = &gArgs;
const std::vector<const char*> arguments = Cat( std::vector<const char*> arguments = Cat(
{ {
"dummy", "dummy",
"-printtoconsole=0", "-printtoconsole=0",
@ -100,6 +101,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
"-debugexclude=leveldb", "-debugexclude=leveldb",
}, },
extra_args); extra_args);
if (G_TEST_COMMAND_LINE_ARGUMENTS) {
arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS());
}
util::ThreadRename("test"); util::ThreadRename("test");
fs::create_directories(m_path_root); fs::create_directories(m_path_root);
m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root)); m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
@ -108,9 +112,10 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
{ {
SetupServerArgs(*m_node.args); SetupServerArgs(*m_node.args);
std::string error; std::string error;
const bool success{m_node.args->ParseParameters(arguments.size(), arguments.data(), error)}; if (!m_node.args->ParseParameters(arguments.size(), arguments.data(), error)) {
assert(success); m_node.args->ClearArgs();
assert(error.empty()); throw std::runtime_error{error};
}
} }
SelectParams(chainName); SelectParams(chainName);
SeedInsecureRand(); SeedInsecureRand();

View file

@ -19,12 +19,16 @@
#include <util/string.h> #include <util/string.h>
#include <util/vector.h> #include <util/vector.h>
#include <functional>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
/** This is connected to the logger. Can be used to redirect logs to any other log */ /** This is connected to the logger. Can be used to redirect logs to any other log */
extern const std::function<void(const std::string&)> G_TEST_LOG_FUN; extern const std::function<void(const std::string&)> G_TEST_LOG_FUN;
/** Retrieve the command line arguments. */
extern const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS;
// Enable BOOST_CHECK_EQUAL for enum class types // Enable BOOST_CHECK_EQUAL for enum class types
namespace std { namespace std {
template <typename T> template <typename T>