Skip to content

Commit

Permalink
[DROP]: Refactor test setup to print error messages
Browse files Browse the repository at this point in the history
Just to check CI errors.
  • Loading branch information
furszy committed Nov 6, 2024
1 parent ae49bb3 commit 37eae61
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 98 deletions.
244 changes: 146 additions & 98 deletions src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,94 +100,111 @@ static void ExitFailure(std::string_view str_err)
exit(EXIT_FAILURE);
}

void BasicTestingSetup::inner_setup()
{
std::cout << "Running setup()" << std::endl;

std::vector<const char *> arguments = Cat(
{
"dummy",
"-printtoconsole=0",
"-logsourcelocations",
"-logtimemicros",
"-logthreadnames",
"-loglevel=trace",
"-debug",
"-debugexclude=libevent",
"-debugexclude=leveldb",
},
m_opts.extra_args);
if (G_TEST_COMMAND_LINE_ARGUMENTS) {
arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS());
}

{
SetupServerArgs(*m_node.args);
SetupCommonTestArgs(*m_node.args);
std::string error;
if (!m_node.args->ParseParameters(arguments.size(), arguments.data(), error)) {
m_node.args->ClearArgs();
throw std::runtime_error{error};
}
}

// Use randomly chosen seed for deterministic PRNG, so that (by default) test
// data directories use a random name that doesn't overlap with other tests.
SeedRandomForTest(SeedRand::FIXED_SEED);

const std::string test_name{G_TEST_GET_FULL_NAME ? G_TEST_GET_FULL_NAME() : ""};
if (!m_node.args->IsArgSet("-testdatadir")) {
// By default, the data directory has a random name on each test run
const auto rand_str{g_rng_temp_path.rand256().ToString()};
m_path_root = fs::temp_directory_path() / TEST_DIR_PATH_ELEMENT / test_name / rand_str;
TryCreateDirectories(m_path_root);
} else {
// Custom data directory
m_has_custom_datadir = true;
fs::path root_dir{m_node.args->GetPathArg("-testdatadir")};
if (root_dir.empty()) ExitFailure("-testdatadir argument is empty, please specify a path");

root_dir = fs::absolute(root_dir);
m_path_lock = root_dir / TEST_DIR_PATH_ELEMENT / fs::PathFromString(test_name);
m_path_root = m_path_lock / "datadir";

// Try to obtain the lock; if unsuccessful don't disturb the existing test.
TryCreateDirectories(m_path_lock);
if (util::LockDirectory(m_path_lock, ".lock", /*probe_only=*/false) != util::LockResult::Success) {
ExitFailure("Cannot obtain a lock on test data lock directory " + fs::PathToString(m_path_lock) + '\n' +
"The test executable is probably already running.");
}

// Always start with a fresh data directory; this doesn't delete the .lock file located one level above.
fs::remove_all(m_path_root);
if (!TryCreateDirectories(m_path_root)) ExitFailure("Cannot create test data directory");

// Print the test directory name if custom.
std::cout << "Test directory (will not be deleted): " << m_path_root << std::endl;
}
m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));

SelectParams(m_chain_type);
if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN);
InitLogging(*m_node.args);
AppInitParameterInteraction(*m_node.args);
LogInstance().StartLogging();
m_node.warnings = std::make_unique<node::Warnings>();
m_node.kernel = std::make_unique<kernel::Context>();
m_node.ecc_context = std::make_unique<ECC_Context>();
SetupEnvironment();

m_node.chain = interfaces::MakeChain(m_node);
static bool noui_connected = false;
if (!noui_connected) {
noui_connect();
noui_connected = true;
}
}

void BasicTestingSetup::setup()
{
try {
inner_setup();
} catch (const std::exception& e) {
ExitFailure(strprintf("Error during test context setup. Message: %s", e.what()));
}
}

BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts)
: m_args{}
: m_args{}, m_opts{opts}, m_chain_type{chainType}
{
std::cout << "Running constructor()" << std::endl;
try {
m_node.shutdown_signal = &m_interrupt;
m_node.shutdown_request = [this] { return m_interrupt(); };
m_node.args = &gArgs;
std::vector<const char *> arguments = Cat(
{
"dummy",
"-printtoconsole=0",
"-logsourcelocations",
"-logtimemicros",
"-logthreadnames",
"-loglevel=trace",
"-debug",
"-debugexclude=libevent",
"-debugexclude=leveldb",
},
opts.extra_args);
if (G_TEST_COMMAND_LINE_ARGUMENTS) {
arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS());
}
util::ThreadRename("test");
gArgs.ClearPathCache();
{
SetupServerArgs(*m_node.args);
SetupCommonTestArgs(*m_node.args);
std::string error;
if (!m_node.args->ParseParameters(arguments.size(), arguments.data(), error)) {
m_node.args->ClearArgs();
throw std::runtime_error{error};
}
}

// Use randomly chosen seed for deterministic PRNG, so that (by default) test
// data directories use a random name that doesn't overlap with other tests.
SeedRandomForTest(SeedRand::FIXED_SEED);

const std::string test_name{G_TEST_GET_FULL_NAME ? G_TEST_GET_FULL_NAME() : ""};
if (!m_node.args->IsArgSet("-testdatadir")) {
// By default, the data directory has a random name on each test run
const auto rand_str{g_rng_temp_path.rand256().ToString()};
m_path_root = fs::temp_directory_path() / TEST_DIR_PATH_ELEMENT / test_name / rand_str;
TryCreateDirectories(m_path_root);
} else {
// Custom data directory
m_has_custom_datadir = true;
fs::path root_dir{m_node.args->GetPathArg("-testdatadir")};
if (root_dir.empty()) ExitFailure("-testdatadir argument is empty, please specify a path");

root_dir = fs::absolute(root_dir);
m_path_lock = root_dir / TEST_DIR_PATH_ELEMENT / fs::PathFromString(test_name);
m_path_root = m_path_lock / "datadir";

// Try to obtain the lock; if unsuccessful don't disturb the existing test.
TryCreateDirectories(m_path_lock);
if (util::LockDirectory(m_path_lock, ".lock", /*probe_only=*/false) != util::LockResult::Success) {
ExitFailure("Cannot obtain a lock on test data lock directory " + fs::PathToString(m_path_lock) + '\n' +
"The test executable is probably already running.");
}

// Always start with a fresh data directory; this doesn't delete the .lock file located one level above.
fs::remove_all(m_path_root);
if (!TryCreateDirectories(m_path_root)) ExitFailure("Cannot create test data directory");

// Print the test directory name if custom.
std::cout << "Test directory (will not be deleted): " << m_path_root << std::endl;
}
m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root));
gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));

SelectParams(chainType);
if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN);
InitLogging(*m_node.args);
AppInitParameterInteraction(*m_node.args);
LogInstance().StartLogging();
m_node.warnings = std::make_unique<node::Warnings>();
m_node.kernel = std::make_unique<kernel::Context>();
m_node.ecc_context = std::make_unique<ECC_Context>();
SetupEnvironment();

m_node.chain = interfaces::MakeChain(m_node);
static bool noui_connected = false;
if (!noui_connected) {
noui_connect();
noui_connected = true;
}
} catch (const std::exception& e) {
ExitFailure(strprintf("Error during context setup, message: %s", e.what()));
}
Expand All @@ -209,14 +226,17 @@ BasicTestingSetup::~BasicTestingSetup()
gArgs.ClearArgs();
}

ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
: BasicTestingSetup(chainType, opts)
void ChainTestingSetup::setup()
{
BasicTestingSetup::setup();

std::cout << "Running ChainTestingSetup setup()" << std::endl;

const CChainParams& chainparams = Params();

// We have to run a scheduler thread to prevent ActivateBestChain
// from blocking due to queue overrun.
if (opts.setup_validation_interface) {
if (m_opts.setup_validation_interface) {
m_node.scheduler = std::make_unique<CScheduler>();
m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); });
m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(*m_node.scheduler));
Expand All @@ -231,6 +251,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)

m_node.notifications = std::make_unique<KernelNotifications>(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings));

auto opts = m_opts;
m_make_chainman = [this, &chainparams, opts] {
Assert(!m_node.chainman);
ChainstateManager::Options chainman_opts{
Expand All @@ -241,7 +262,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
.signals = m_node.validation_signals.get(),
.worker_threads_num = 2,
};
if (opts.min_validation_cache) {
if (m_opts.min_validation_cache) {
chainman_opts.script_execution_cache_bytes = 0;
chainman_opts.signature_cache_bytes = 0;
}
Expand All @@ -261,6 +282,11 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
m_make_chainman();
}

ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
: BasicTestingSetup(chainType, opts)
{
}

ChainTestingSetup::~ChainTestingSetup()
{
if (m_node.scheduler) m_node.scheduler->stop();
Expand Down Expand Up @@ -302,24 +328,22 @@ void ChainTestingSetup::LoadVerifyActivateChainstate()
}
}

TestingSetup::TestingSetup(
const ChainType chainType,
TestOpts opts)
: ChainTestingSetup(chainType, opts)
void TestingSetup::setup()
{
m_coins_db_in_memory = opts.coins_db_in_memory;
m_block_tree_db_in_memory = opts.block_tree_db_in_memory;
ChainTestingSetup::setup();
std::cout << "Running TestingSetup setup()" << std::endl;

// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC);

LoadVerifyActivateChainstate();

if (!opts.setup_net) return;
if (!m_opts.setup_net) return;

m_node.netgroupman = std::make_unique<NetGroupManager>(/*asmap=*/std::vector<bool>());
m_node.addrman = std::make_unique<AddrMan>(*m_node.netgroupman,
/*deterministic=*/false,
/*deterministic=*/false,
m_node.args->GetIntArg("-checkaddrman", 0));
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); // Deterministic randomness for tests.
Expand All @@ -338,14 +362,22 @@ TestingSetup::TestingSetup(
}
}

TestChain100Setup::TestChain100Setup(
const ChainType chain_type,
TestingSetup::TestingSetup(
const ChainType chainType,
TestOpts opts)
: TestingSetup{ChainType::REGTEST, opts}
: ChainTestingSetup(chainType, opts)
{
m_coins_db_in_memory = opts.coins_db_in_memory;
m_block_tree_db_in_memory = opts.block_tree_db_in_memory;
}

void TestChain100Setup::inner_setup()
{
TestingSetup::setup();

SetMockTime(1598887952);
constexpr std::array<unsigned char, 32> vchKey = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
coinbaseKey.Set(vchKey.begin(), vchKey.end(), true);

// Generate a 100-block chain:
Expand All @@ -354,11 +386,27 @@ TestChain100Setup::TestChain100Setup(
{
LOCK(::cs_main);
assert(
m_node.chainman->ActiveChain().Tip()->GetBlockHash().ToString() ==
"571d80a9967ae599cec0448b0b0ba1cfb606f584d8069bd7166b86854ba7a191");
m_node.chainman->ActiveChain().Tip()->GetBlockHash().ToString() ==
"571d80a9967ae599cec0448b0b0ba1cfb606f584d8069bd7166b86854ba7a191");
}
}

void TestChain100Setup::setup()
{
try {
inner_setup();
} catch (const std::exception& e) {
ExitFailure(strprintf("Error during test context setup. Message: %s", e.what()));
}
}

TestChain100Setup::TestChain100Setup(
const ChainType chain_type,
TestOpts opts)
: TestingSetup{ChainType::REGTEST, opts}
{
}

void TestChain100Setup::mineBlocks(int num_blocks)
{
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
Expand Down
12 changes: 12 additions & 0 deletions src/test/util/setup_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ struct BasicTestingSetup {
explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {});
~BasicTestingSetup();

// Test setup function
void setup();
void inner_setup();

fs::path m_path_root;
fs::path m_path_lock;
bool m_has_custom_datadir{false};
Expand All @@ -96,6 +100,8 @@ struct BasicTestingSetup {
* @see https://github.com/bitcoin/bitcoin/issues/25055 for additional context.
*/
ArgsManager m_args;
TestOpts m_opts;
ChainType m_chain_type;
};

/** Testing setup that performs all steps up until right before
Expand All @@ -111,6 +117,8 @@ struct ChainTestingSetup : public BasicTestingSetup {
explicit ChainTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {});
~ChainTestingSetup();

void setup();

// Supplies a chainstate, if one is needed
void LoadVerifyActivateChainstate();
};
Expand All @@ -121,6 +129,7 @@ struct TestingSetup : public ChainTestingSetup {
explicit TestingSetup(
const ChainType chainType = ChainType::MAIN,
TestOpts = {});
void setup();
};

/** Identical to TestingSetup, but chain set to regtest */
Expand All @@ -141,6 +150,9 @@ struct TestChain100Setup : public TestingSetup {
const ChainType chain_type = ChainType::REGTEST,
TestOpts = {});

void setup();
void inner_setup();

/**
* Create a new block with just given transactions, coinbase paying to
* scriptPubKey, and try to add it to the current chain.
Expand Down

0 comments on commit 37eae61

Please sign in to comment.