mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-16 02:27:43 +02:00
test: Use NodeClockContext in more tests
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <test/util/time.h>
|
||||
#include <util/time.h>
|
||||
|
||||
static void BenchTimeDeprecated(benchmark::Bench& bench)
|
||||
@@ -15,11 +15,10 @@ static void BenchTimeDeprecated(benchmark::Bench& bench)
|
||||
|
||||
static void BenchTimeMock(benchmark::Bench& bench)
|
||||
{
|
||||
SetMockTime(111);
|
||||
NodeClockContext clock_ctx{111s};
|
||||
bench.run([&] {
|
||||
(void)GetTime<std::chrono::seconds>();
|
||||
});
|
||||
SetMockTime(0);
|
||||
}
|
||||
|
||||
static void BenchTimeMillis(benchmark::Bench& bench)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <sync.h>
|
||||
#include <test/util/mining.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <uint256.h>
|
||||
#include <util/time.h>
|
||||
#include <validation.h>
|
||||
@@ -32,7 +33,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
|
||||
|
||||
// Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
|
||||
// The reason is 'generatetoaddress', which creates a chain with deterministic timestamps in the past.
|
||||
SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
|
||||
NodeClockContext clock_ctx{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()};
|
||||
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <script/script.h>
|
||||
#include <sync.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <uint256.h>
|
||||
#include <util/result.h>
|
||||
#include <util/time.h>
|
||||
@@ -117,7 +118,7 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
|
||||
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
// Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
|
||||
SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
|
||||
NodeClockContext clock_ctx{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()};
|
||||
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
@@ -172,7 +173,7 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType
|
||||
{
|
||||
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
// Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
|
||||
SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
|
||||
NodeClockContext clock_ctx{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()};
|
||||
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <random.h>
|
||||
#include <test/data/asmap.raw.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <util/asmap.h>
|
||||
#include <util/string.h>
|
||||
|
||||
@@ -1030,7 +1031,8 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
|
||||
BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.36:0");
|
||||
|
||||
// Eviction is also successful if too much time has passed since last try
|
||||
SetMockTime(GetTime() + 4 * 60 *60);
|
||||
NodeClockContext clock_ctx{};
|
||||
clock_ctx += 4h;
|
||||
addrman->ResolveCollisions();
|
||||
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
|
||||
//Now 19 is in tried again, and 36 back to new
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
#include <streams.h>
|
||||
#include <test/util/logging.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <util/readwritefile.h>
|
||||
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(banman_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(file)
|
||||
{
|
||||
SetMockTime(777s);
|
||||
NodeClockContext clock_ctx{777s};
|
||||
const fs::path banlist_path{m_args.GetDataDirBase() / "banlist_test"};
|
||||
{
|
||||
const std::string entries_write{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
@@ -30,6 +31,7 @@ BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup)
|
||||
m_node.validation_signals->RegisterSharedValidationInterface(sub);
|
||||
auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
|
||||
BlockValidationState state_dummy{};
|
||||
NodeClockContext clock_ctx{};
|
||||
|
||||
// The first periodic flush sets m_next_write and does not flush
|
||||
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
||||
@@ -37,12 +39,12 @@ BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup)
|
||||
BOOST_CHECK(!sub->m_did_flush);
|
||||
|
||||
// The periodic flush interval is between 50 and 70 minutes (inclusive)
|
||||
SetMockTime(GetTime<std::chrono::minutes>() + DATABASE_WRITE_INTERVAL_MIN - 1min);
|
||||
clock_ctx += DATABASE_WRITE_INTERVAL_MIN - 1min;
|
||||
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
||||
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
BOOST_CHECK(!sub->m_did_flush);
|
||||
|
||||
SetMockTime(GetTime<std::chrono::minutes>() + DATABASE_WRITE_INTERVAL_MAX);
|
||||
clock_ctx += DATABASE_WRITE_INTERVAL_MAX;
|
||||
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
||||
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
||||
BOOST_CHECK(sub->m_did_flush);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <test/util/net.h>
|
||||
#include <test/util/random.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <util/string.h>
|
||||
#include <util/time.h>
|
||||
#include <validation.h>
|
||||
@@ -90,17 +91,17 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
}
|
||||
connman.FlushSendBuffer(dummyNode1);
|
||||
|
||||
int64_t nStartTime = GetTime();
|
||||
// Wait 21 minutes
|
||||
SetMockTime(nStartTime+21*60);
|
||||
NodeClockContext clock_ctx{};
|
||||
clock_ctx += 21min;
|
||||
|
||||
BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
|
||||
{
|
||||
LOCK(dummyNode1.cs_vSend);
|
||||
const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
|
||||
BOOST_CHECK(!to_send.empty());
|
||||
}
|
||||
// Wait 3 more minutes
|
||||
SetMockTime(nStartTime+24*60);
|
||||
|
||||
clock_ctx += 3min;
|
||||
BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in disconnect
|
||||
BOOST_CHECK(dummyNode1.fDisconnect == true);
|
||||
|
||||
@@ -151,9 +152,9 @@ BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
|
||||
CConnman::Options options;
|
||||
options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
|
||||
|
||||
const auto time_init{GetTime<std::chrono::seconds>()};
|
||||
SetMockTime(time_init);
|
||||
const auto time_later{time_init + 3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
|
||||
const auto time_init{Now<NodeSeconds>()};
|
||||
NodeClockContext clock_ctx{time_init};
|
||||
const auto delta{3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
|
||||
connman->Init(options);
|
||||
std::vector<CNode *> vNodes;
|
||||
|
||||
@@ -169,7 +170,7 @@ BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
|
||||
BOOST_CHECK(node->fDisconnect == false);
|
||||
}
|
||||
|
||||
SetMockTime(time_later);
|
||||
clock_ctx += delta;
|
||||
|
||||
// Now tip should definitely be stale, and we should look for an extra
|
||||
// outbound peer
|
||||
@@ -184,9 +185,9 @@ BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
|
||||
// If we add one more peer, something should get marked for eviction
|
||||
// on the next check (since we're mocking the time to be in the future, the
|
||||
// required time connected check should be satisfied).
|
||||
SetMockTime(time_init);
|
||||
clock_ctx.set(time_init);
|
||||
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
|
||||
SetMockTime(time_later);
|
||||
clock_ctx += delta;
|
||||
|
||||
peerLogic->CheckForStaleTipAndEvictPeers();
|
||||
for (int i = 0; i < max_outbound_full_relay; ++i) {
|
||||
@@ -212,9 +213,9 @@ BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
|
||||
|
||||
// Add an onion peer, that will be protected because it is the only one for
|
||||
// its network, so another peer gets disconnected instead.
|
||||
SetMockTime(time_init);
|
||||
clock_ctx.set(time_init);
|
||||
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
|
||||
SetMockTime(time_later);
|
||||
clock_ctx += delta;
|
||||
peerLogic->CheckForStaleTipAndEvictPeers();
|
||||
|
||||
for (int i = 0; i < max_outbound_full_relay - 2; ++i) {
|
||||
@@ -225,9 +226,9 @@ BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
|
||||
BOOST_CHECK(vNodes[max_outbound_full_relay]->fDisconnect == false);
|
||||
|
||||
// Add a second onion peer which won't be protected
|
||||
SetMockTime(time_init);
|
||||
clock_ctx.set(time_init);
|
||||
AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
|
||||
SetMockTime(time_later);
|
||||
clock_ctx += delta;
|
||||
peerLogic->CheckForStaleTipAndEvictPeers();
|
||||
|
||||
BOOST_CHECK(vNodes.back()->fDisconnect == true);
|
||||
@@ -246,7 +247,7 @@ BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)
|
||||
auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
|
||||
|
||||
constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
|
||||
constexpr int64_t MINIMUM_CONNECT_TIME{30};
|
||||
constexpr auto MINIMUM_CONNECT_TIME{30s};
|
||||
CConnman::Options options;
|
||||
options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
|
||||
|
||||
@@ -273,7 +274,8 @@ BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)
|
||||
}
|
||||
BOOST_CHECK(vNodes.back()->fDisconnect == false);
|
||||
|
||||
SetMockTime(GetTime() + MINIMUM_CONNECT_TIME + 1);
|
||||
NodeClockContext clock_ctx{};
|
||||
clock_ctx += MINIMUM_CONNECT_TIME;
|
||||
peerLogic->CheckForStaleTipAndEvictPeers();
|
||||
for (int i = 0; i < max_outbound_block_relay; ++i) {
|
||||
BOOST_CHECK(vNodes[i]->fDisconnect == false);
|
||||
@@ -411,8 +413,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
|
||||
|
||||
banman->ClearBanned();
|
||||
int64_t nStartTime = GetTime();
|
||||
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||
const NodeClockContext clock_ctx{}; // keep mocktime constant
|
||||
|
||||
CAddress addr(ip(0xa0b0c001), NODE_NONE);
|
||||
NodeId id{0};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <common/system.h>
|
||||
#include <policy/policy.h>
|
||||
#include <test/util/time.h>
|
||||
#include <test/util/txmempool.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/time.h>
|
||||
@@ -251,28 +252,29 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
TryAddToMempool(pool, entry.Fee(900LL).FromTx(tx7));
|
||||
|
||||
std::vector<CTransactionRef> vtx;
|
||||
SetMockTime(42);
|
||||
SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
|
||||
NodeClockContext clock_ctx{42s};
|
||||
constexpr std::chrono::seconds HALFLIFE{CTxMemPool::ROLLING_FEE_HALFLIFE};
|
||||
clock_ctx += HALFLIFE;
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE);
|
||||
// ... we should keep the same min fee until we get a block
|
||||
pool.removeForBlock(vtx, 1);
|
||||
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
|
||||
clock_ctx += HALFLIFE;
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/2.0));
|
||||
// ... then feerate should drop 1/2 each halflife
|
||||
|
||||
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
|
||||
clock_ctx += HALFLIFE / 2;
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/4.0));
|
||||
// ... with a 1/2 halflife when mempool is < 1/2 its target size
|
||||
|
||||
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
|
||||
clock_ctx += HALFLIFE / 4;
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/8.0));
|
||||
// ... with a 1/4 halflife when mempool is < 1/4 its target size
|
||||
|
||||
SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
|
||||
clock_ctx += 5 * HALFLIFE;
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), DEFAULT_INCREMENTAL_RELAY_FEE);
|
||||
// ... but feerate should never drop below DEFAULT_INCREMENTAL_RELAY_FEE
|
||||
|
||||
SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
|
||||
clock_ctx += HALFLIFE;
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
|
||||
// ... unless it has gone all the way to 0 (after getting past DEFAULT_INCREMENTAL_RELAY_FEE/2)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <test/util/common.h>
|
||||
#include <test/util/random.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <test/util/transaction_utils.h>
|
||||
|
||||
#include <array>
|
||||
@@ -431,9 +432,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||
FillableSigningProvider keystore;
|
||||
BOOST_CHECK(keystore.AddKey(key));
|
||||
|
||||
// Freeze time for length of test
|
||||
auto now{GetTime<std::chrono::seconds>()};
|
||||
SetMockTime(now);
|
||||
NodeClockContext clock_ctx{};
|
||||
|
||||
std::vector<CTransactionRef> orphans_added;
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
#include <common/system.h>
|
||||
#include <interfaces/mining.h>
|
||||
#include <node/miner.h>
|
||||
#include <test/util/common.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <util/time.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using interfaces::BlockTemplate;
|
||||
@@ -39,14 +40,14 @@ BOOST_AUTO_TEST_CASE(MiningInterface)
|
||||
std::unique_ptr<BlockTemplate> block_template;
|
||||
|
||||
// Set node time a few minutes past the testnet4 genesis block
|
||||
const int64_t genesis_time{WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Tip()->GetBlockTime())};
|
||||
SetMockTime(genesis_time + 3 * 60);
|
||||
const auto template_time{3min + WITH_LOCK(cs_main, return m_node.chainman->ActiveChain().Tip()->Time())};
|
||||
NodeClockContext clock_ctx{template_time};
|
||||
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
||||
// The template should use the mocked system time
|
||||
BOOST_REQUIRE_EQUAL(block_template->getBlockHeader().nTime, genesis_time + 3 * 60);
|
||||
BOOST_REQUIRE_EQUAL(block_template->getBlockHeader().Time(), template_time);
|
||||
|
||||
const BlockWaitOptions wait_options{.timeout = MillisecondsDouble{0}, .fee_threshold = 1};
|
||||
|
||||
@@ -55,20 +56,14 @@ BOOST_AUTO_TEST_CASE(MiningInterface)
|
||||
BOOST_REQUIRE(should_be_nullptr == nullptr);
|
||||
|
||||
// This remains the case when exactly 20 minutes have gone by
|
||||
{
|
||||
LOCK(cs_main);
|
||||
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60);
|
||||
}
|
||||
clock_ctx += 17min;
|
||||
should_be_nullptr = block_template->waitNext(wait_options);
|
||||
BOOST_REQUIRE(should_be_nullptr == nullptr);
|
||||
|
||||
// One second later the difficulty drops and it returns a new template
|
||||
// Note that we can't test the actual difficulty change, because the
|
||||
// difficulty is already at 1.
|
||||
{
|
||||
LOCK(cs_main);
|
||||
SetMockTime(m_node.chainman->ActiveChain().Tip()->GetBlockTime() + 20 * 60 + 1);
|
||||
}
|
||||
clock_ctx += 1s;
|
||||
block_template = block_template->waitNext(wait_options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <test/util/common.h>
|
||||
#include <test/util/random.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/time.h>
|
||||
#include <uint256.h>
|
||||
#include <util/bitdeque.h>
|
||||
#include <util/byte_units.h>
|
||||
@@ -585,7 +586,7 @@ BOOST_AUTO_TEST_CASE(strprintf_numbers)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_mocktime)
|
||||
{
|
||||
SetMockTime(111s);
|
||||
NodeClockContext clock_ctx{111s};
|
||||
// Check that mock time does not change after a sleep
|
||||
for (const auto& num_sleep : {0ms, 1ms}) {
|
||||
UninterruptibleSleep(num_sleep);
|
||||
@@ -598,7 +599,6 @@ BOOST_AUTO_TEST_CASE(util_mocktime)
|
||||
BOOST_CHECK_EQUAL(111000, TicksSinceEpoch<std::chrono::milliseconds>(NodeClock::now()));
|
||||
BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count());
|
||||
}
|
||||
SetMockTime(0s);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_ticksseconds)
|
||||
|
||||
Reference in New Issue
Block a user