From 91e303595be2cc2361a5e32000e23a3b744e2fc1 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 10 Mar 2017 15:47:41 -0500 Subject: [PATCH 1/6] Make test_bitcoin.cpp compatible with Qt Test framework Move Boost.Test main function and global overrides to a new test_bitcoin_main.cpp file. --- src/Makefile.test.include | 1 + src/test/test_bitcoin.cpp | 28 ++++++---------------------- src/test/test_bitcoin_main.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 22 deletions(-) create mode 100644 src/test/test_bitcoin_main.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 55a587cf8..c3069e33b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -126,6 +126,7 @@ BITCOIN_TESTS =\ test/streams_tests.cpp \ test/test_bitcoin.cpp \ test/test_bitcoin.h \ + test/test_bitcoin_main.cpp \ test/test_random.h \ test/testutil.cpp \ test/testutil.h \ diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 2297644c0..abaec45cd 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -2,8 +2,6 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#define BOOST_TEST_MODULE Bitcoin Test Suite - #include "test_bitcoin.h" #include "chainparams.h" @@ -27,10 +25,8 @@ #include #include -#include #include -std::unique_ptr g_connman; FastRandomContext insecure_rand_ctx(true); extern bool fPrintToConsole; @@ -69,11 +65,14 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); - BOOST_REQUIRE(InitBlockIndex(chainparams)); + if (!InitBlockIndex(chainparams)) { + throw std::runtime_error("InitBlockIndex failed."); + } { CValidationState state; - bool ok = ActivateBestChain(state, chainparams); - BOOST_REQUIRE(ok); + if (!ActivateBestChain(state, chainparams)) { + throw std::runtime_error("ActivateBestChain failed."); + } } nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) @@ -150,18 +149,3 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) { return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight, spendsCoinbase, sigOpCost, lp); } - -void Shutdown(void* parg) -{ - exit(EXIT_SUCCESS); -} - -void StartShutdown() -{ - exit(EXIT_SUCCESS); -} - -bool ShutdownRequested() -{ - return false; -} diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp new file mode 100644 index 000000000..34beef553 --- /dev/null +++ b/src/test/test_bitcoin_main.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2011-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#define BOOST_TEST_MODULE Bitcoin Test Suite + +#include "net.h" + +#include + +std::unique_ptr g_connman; + +void Shutdown(void* parg) +{ + exit(EXIT_SUCCESS); +} + +void StartShutdown() +{ + exit(EXIT_SUCCESS); +} + +bool ShutdownRequested() +{ + return false; +} From cc9503cec9c66acfb38d56b094ada8382d15434f Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 10 Mar 2017 15:52:29 -0500 Subject: [PATCH 2/6] Make qt test compatible with TestChain100Setup framework Reset global state after rpc tests, and remove unnecessary ECC initialization to prevent assert error if it is initialized twice. --- src/qt/test/rpcnestedtests.cpp | 4 ++++ src/qt/test/test_main.cpp | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index bd496f149..a7b82117d 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -148,9 +148,13 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , #endif + UnloadBlockIndex(); delete pcoinsTip; + pcoinsTip = nullptr; delete pcoinsdbview; + pcoinsdbview = nullptr; delete pblocktree; + pblocktree = nullptr; boost::filesystem::remove_all(boost::filesystem::path(path)); } diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index d44d71131..fd07ecb7a 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -7,7 +7,6 @@ #endif #include "chainparams.h" -#include "key.h" #include "rpcnestedtests.h" #include "util.h" #include "uritests.h" @@ -36,7 +35,6 @@ extern void noui_connect(); // This is all you need to run all the tests int main(int argc, char *argv[]) { - ECC_Start(); SetupEnvironment(); SetupNetworking(); SelectParams(CBaseChainParams::MAIN); @@ -66,6 +64,5 @@ int main(int argc, char *argv[]) if (QTest::qExec(&test4) != 0) fInvalid = true; - ECC_Stop(); return fInvalid; } From b61b34c89dbe3946e21147dcfe620a4a6ff536ed Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 15 Mar 2017 13:02:02 -0400 Subject: [PATCH 3/6] Add braces to if statements in Qt test_main --- src/qt/test/test_main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index fd07ecb7a..fc085f7e9 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -50,19 +50,23 @@ int main(int argc, char *argv[]) SSL_library_init(); URITests test1; - if (QTest::qExec(&test1) != 0) + if (QTest::qExec(&test1) != 0) { fInvalid = true; + } #ifdef ENABLE_WALLET PaymentServerTests test2; - if (QTest::qExec(&test2) != 0) + if (QTest::qExec(&test2) != 0) { fInvalid = true; + } #endif RPCNestedTests test3; - if (QTest::qExec(&test3) != 0) + if (QTest::qExec(&test3) != 0) { fInvalid = true; + } CompatTests test4; - if (QTest::qExec(&test4) != 0) + if (QTest::qExec(&test4) != 0) { fInvalid = true; + } return fInvalid; } From 2754ef1c4a8cd7415f9ac2d3660ce6e4545b2754 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 10 Mar 2017 15:58:53 -0500 Subject: [PATCH 4/6] Add simple qt wallet test sending a transaction --- src/Makefile.qttest.include | 22 ++++++-- src/qt/test/test_main.cpp | 13 +++-- src/qt/test/wallettests.cpp | 104 ++++++++++++++++++++++++++++++++++++ src/qt/test/wallettests.h | 15 ++++++ 4 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/qt/test/wallettests.cpp create mode 100644 src/qt/test/wallettests.h diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 039f8ac54..948e13a9e 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -11,7 +11,9 @@ TEST_QT_MOC_CPP = \ qt/test/moc_uritests.cpp if ENABLE_WALLET -TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp +TEST_QT_MOC_CPP += \ + qt/test/moc_paymentservertests.cpp \ + qt/test/moc_wallettests.cpp endif TEST_QT_H = \ @@ -19,7 +21,16 @@ TEST_QT_H = \ qt/test/rpcnestedtests.h \ qt/test/uritests.h \ qt/test/paymentrequestdata.h \ - qt/test/paymentservertests.h + qt/test/paymentservertests.h \ + qt/test/wallettests.h + +TEST_BITCOIN_CPP = \ + test/test_bitcoin.cpp \ + test/testutil.cpp + +TEST_BITCOIN_H = \ + test/test_bitcoin.h \ + test/testutil.h qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) @@ -29,10 +40,13 @@ qt_test_test_bitcoin_qt_SOURCES = \ qt/test/rpcnestedtests.cpp \ qt/test/test_main.cpp \ qt/test/uritests.cpp \ - $(TEST_QT_H) + $(TEST_QT_H) \ + $(TEST_BITCOIN_CPP) \ + $(TEST_BITCOIN_H) if ENABLE_WALLET qt_test_test_bitcoin_qt_SOURCES += \ - qt/test/paymentservertests.cpp + qt/test/paymentservertests.cpp \ + qt/test/wallettests.cpp endif nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index fc085f7e9..8a475405e 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -14,9 +14,10 @@ #ifdef ENABLE_WALLET #include "paymentservertests.h" +#include "wallettests.h" #endif -#include +#include #include #include @@ -43,8 +44,8 @@ int main(int argc, char *argv[]) bool fInvalid = false; // Don't remove this, it's needed to access - // QCoreApplication:: in the tests - QCoreApplication app(argc, argv); + // QApplication:: and QCoreApplication:: in the tests + QApplication app(argc, argv); app.setApplicationName("Bitcoin-Qt-test"); SSL_library_init(); @@ -67,6 +68,12 @@ int main(int argc, char *argv[]) if (QTest::qExec(&test4) != 0) { fInvalid = true; } +#ifdef ENABLE_WALLET + WalletTests test5; + if (QTest::qExec(&test5) != 0) { + fInvalid = true; + } +#endif return fInvalid; } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp new file mode 100644 index 000000000..2bb7f01fd --- /dev/null +++ b/src/qt/test/wallettests.cpp @@ -0,0 +1,104 @@ +#include "wallettests.h" + +#include "qt/bitcoinamountfield.h" +#include "qt/optionsmodel.h" +#include "qt/platformstyle.h" +#include "qt/qvalidatedlineedit.h" +#include "qt/sendcoinsdialog.h" +#include "qt/sendcoinsentry.h" +#include "qt/transactiontablemodel.h" +#include "qt/walletmodel.h" +#include "test/test_bitcoin.h" +#include "validation.h" +#include "wallet/wallet.h" + +#include +#include +#include +#include + +namespace +{ +//! Press "Yes" button in modal send confirmation dialog. +void ConfirmSend() +{ + QTimer::singleShot(0, Qt::PreciseTimer, []() { + for (QWidget* widget : QApplication::topLevelWidgets()) { + if (widget->inherits("SendConfirmationDialog")) { + SendConfirmationDialog* dialog = qobject_cast(widget); + QAbstractButton* button = dialog->button(QMessageBox::Yes); + button->setEnabled(true); + button->click(); + } + } + }); +} + +//! Send coins to address and return txid. +uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount) +{ + QVBoxLayout* entries = sendCoinsDialog.findChild("entries"); + SendCoinsEntry* entry = qobject_cast(entries->itemAt(0)->widget()); + entry->findChild("payTo")->setText(QString::fromStdString(address.ToString())); + entry->findChild("payAmount")->setValue(amount); + uint256 txid; + boost::signals2::scoped_connection c = wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) { + if (status == CT_NEW) txid = hash; + }); + ConfirmSend(); + QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked"); + return txid; +} + +//! Find index of txid in transaction list. +QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid) +{ + QString hash = QString::fromStdString(txid.ToString()); + int rows = model.rowCount({}); + for (int row = 0; row < rows; ++row) { + QModelIndex index = model.index(row, 0, {}); + if (model.data(index, TransactionTableModel::TxHashRole) == hash) { + return index; + } + } + return {}; +} +} + +//! Simple qt wallet tests. +void WalletTests::walletTests() +{ + // Set up wallet and chain with 101 blocks (1 mature block for spending). + TestChain100Setup test; + test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); + bitdb.MakeMock(); + CWallet wallet("wallet_test.dat"); + bool firstRun; + wallet.LoadWallet(firstRun); + { + LOCK(wallet.cs_wallet); + wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive"); + wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); + } + wallet.ScanForWalletTransactions(chainActive.Genesis(), true); + wallet.SetBroadcastTransactions(true); + + // Create widgets for sending coins and listing transactions. + std::unique_ptr platformStyle(PlatformStyle::instantiate("other")); + SendCoinsDialog sendCoinsDialog(platformStyle.get()); + OptionsModel optionsModel; + WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel); + sendCoinsDialog.setModel(&walletModel); + + // Send two transactions, and verify they are added to transaction list. + TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); + QCOMPARE(transactionTableModel->rowCount({}), 101); + uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN); + uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN); + QCOMPARE(transactionTableModel->rowCount({}), 103); + QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); + QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); + + bitdb.Flush(true); + bitdb.Reset(); +} diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h new file mode 100644 index 000000000..342f7916c --- /dev/null +++ b/src/qt/test/wallettests.h @@ -0,0 +1,15 @@ +#ifndef BITCOIN_QT_TEST_WALLETTESTS_H +#define BITCOIN_QT_TEST_WALLETTESTS_H + +#include +#include + +class WalletTests : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void walletTests(); +}; + +#endif // BITCOIN_QT_TEST_WALLETTESTS_H From 9e6817ed1146a340543de96b36d9eaee5d5ced7d Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Tue, 14 Mar 2017 20:45:00 -0400 Subject: [PATCH 5/6] Add new test_bitcoin-qt static library dependencies Avoids following error when qt is statically linked into the test binary, as on travis: This application failed to start because it could not find or load the Qt platform plugin "xcb" in "". --- src/qt/test/test_main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 8a475405e..d8bcfedb7 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -23,12 +23,22 @@ #include -#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000 +#if defined(QT_STATICPLUGIN) #include +#if QT_VERSION < 0x050000 Q_IMPORT_PLUGIN(qcncodecs) Q_IMPORT_PLUGIN(qjpcodecs) Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) +#else +#if defined(QT_QPA_PLATFORM_XCB) +Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_WINDOWS) +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_COCOA) +Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); +#endif +#endif #endif extern void noui_connect(); From 9576b015a107b98fc950c574ed01d993b388d7c9 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Tue, 14 Mar 2017 20:46:41 -0400 Subject: [PATCH 6/6] Enable xvfb in travis to allow running test_bitcoin-qt Avoids following error: QXcbConnection: Could not connect to display --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ce6cdc2db..f2f1d0f35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: # bitcoind - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" # No wallet - - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + - HOST=x86_64-unknown-linux-gnu PACKAGES="python3 xvfb" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" # Cross-Mac - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" @@ -50,6 +50,8 @@ before_script: - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS + # Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI + - if [ "$RUN_TESTS" = "true" -a "${DEP_OPTS#*NO_QT=1}" = "$DEP_OPTS" ]; then export DISPLAY=:99.0; /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi script: - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then git fetch --unshallow; fi