Skip to content

Commit 1674008

Browse files
thepastaclawclaude
andcommitted
test: cover CoinJoin client lifecycle handling
Add functional coverage for CoinJoin session startup, participant restart, wallet unload/reload, and live stop/reset cleanup. Add a focused manager unit test that verifies removeWallet cannot erase a client while doForClient is using it, and isolate peers synchronously before testing the live session. Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent edf98c5 commit 1674008

3 files changed

Lines changed: 411 additions & 0 deletions

File tree

‎src/wallet/test/coinjoin_tests.cpp‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
#include <boost/test/unit_test.hpp>
3434

35+
#include <chrono>
36+
#include <future>
37+
#include <thread>
38+
3539
namespace wallet {
3640
BOOST_FIXTURE_TEST_SUITE(coinjoin_tests, BasicTestingSetup)
3741

@@ -394,6 +398,38 @@ BOOST_FIXTURE_TEST_CASE(coinjoin_pending_observation_reload_tests, CTransactionB
394398
SetMockTime(0);
395399
}
396400

401+
BOOST_FIXTURE_TEST_CASE(coinjoin_wallet_manager_remove_during_client_access_tests, CTransactionBuilderTestSetup)
402+
{
403+
std::promise<void> client_entered;
404+
auto client_entered_future{client_entered.get_future()};
405+
std::promise<void> release_client;
406+
auto release_client_future{release_client.get_future()};
407+
bool client_found{false};
408+
409+
std::thread client_thread([&] {
410+
client_found = m_node.cj_walletman->doForClient(wallet->GetName(), [&](CCoinJoinClientManager&) {
411+
client_entered.set_value();
412+
release_client_future.wait();
413+
});
414+
});
415+
416+
client_entered_future.wait();
417+
auto remove_future{std::async(std::launch::async, [&] { m_node.cj_walletman->removeWallet(wallet->GetName()); })};
418+
419+
// doForClient holds the manager-map lock while the callback uses the
420+
// client, so removal must wait until the callback has released it.
421+
BOOST_CHECK_EQUAL(remove_future.wait_for(std::chrono::milliseconds{100}), std::future_status::timeout);
422+
423+
release_client.set_value();
424+
client_thread.join();
425+
BOOST_CHECK(client_found);
426+
BOOST_CHECK_EQUAL(remove_future.wait_for(std::chrono::seconds{1}), std::future_status::ready);
427+
remove_future.get();
428+
429+
// Restore the fixture's manager for its teardown.
430+
m_node.cj_walletman->addWallet(wallet);
431+
}
432+
397433
BOOST_FIXTURE_TEST_CASE(coinjoin_pending_observation_unreadable_tests, CTransactionBuilderTestSetup)
398434
{
399435
// 0.100001 DASH, a valid CoinJoin denomination

‎test/functional/test_runner.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
# Longest test should go first, to favor running tests in parallel
102102
'feature_llmq_data_recovery.py',
103103
# vv Tests less than 5m vv
104+
'wallet_coinjoin_mixing.py',
104105
'feature_fee_estimation.py',
105106
'feature_block.py', # NOTE: needs dash_hash to pass
106107
# vv Tests less than 2m vv

0 commit comments

Comments
 (0)