Add BitcoinApplication & RPCConsole tests
Add test coverage for Qt initialization code & basic RPC console functionality.
This commit is contained in:
parent
ca20b65cc0
commit
7e4bd19785
11 changed files with 235 additions and 24 deletions
|
@ -303,6 +303,7 @@ RES_ICONS = \
|
|||
|
||||
BITCOIN_QT_BASE_CPP = \
|
||||
qt/bantablemodel.cpp \
|
||||
qt/bitcoin.cpp \
|
||||
qt/bitcoinaddressvalidator.cpp \
|
||||
qt/bitcoinamountfield.cpp \
|
||||
qt/bitcoingui.cpp \
|
||||
|
@ -383,6 +384,9 @@ qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
|
|||
|
||||
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
|
||||
$(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
|
||||
if TARGET_DARWIN
|
||||
qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM)
|
||||
endif
|
||||
|
||||
nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
|
||||
$(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
|
||||
|
@ -405,10 +409,7 @@ qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDE
|
|||
$(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
|
||||
qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
|
||||
|
||||
qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp
|
||||
if TARGET_DARWIN
|
||||
qt_bitcoin_qt_SOURCES += $(BITCOIN_MM)
|
||||
endif
|
||||
qt_bitcoin_qt_SOURCES = qt/main.cpp
|
||||
if TARGET_WINDOWS
|
||||
qt_bitcoin_qt_SOURCES += $(BITCOIN_RC)
|
||||
endif
|
||||
|
|
|
@ -6,6 +6,7 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt
|
|||
TESTS += qt/test/test_bitcoin-qt
|
||||
|
||||
TEST_QT_MOC_CPP = \
|
||||
qt/test/moc_apptests.cpp \
|
||||
qt/test/moc_compattests.cpp \
|
||||
qt/test/moc_rpcnestedtests.cpp \
|
||||
qt/test/moc_uritests.cpp
|
||||
|
@ -22,6 +23,7 @@ endif # ENABLE_WALLET
|
|||
|
||||
TEST_QT_H = \
|
||||
qt/test/addressbooktests.h \
|
||||
qt/test/apptests.h \
|
||||
qt/test/compattests.h \
|
||||
qt/test/rpcnestedtests.h \
|
||||
qt/test/uritests.h \
|
||||
|
@ -40,6 +42,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
|
|||
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
|
||||
|
||||
qt_test_test_bitcoin_qt_SOURCES = \
|
||||
qt/test/apptests.cpp \
|
||||
qt/test/compattests.cpp \
|
||||
qt/test/rpcnestedtests.cpp \
|
||||
qt/test/test_main.cpp \
|
||||
|
|
|
@ -72,11 +72,6 @@ Q_DECLARE_METATYPE(bool*)
|
|||
Q_DECLARE_METATYPE(CAmount)
|
||||
Q_DECLARE_METATYPE(uint256)
|
||||
|
||||
/** Translate string to current locale using Qt. */
|
||||
const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
|
||||
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
|
||||
};
|
||||
|
||||
static QString GetLangTerritory()
|
||||
{
|
||||
QSettings settings;
|
||||
|
@ -264,6 +259,11 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
|
|||
connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
|
||||
}
|
||||
|
||||
bool BitcoinApplication::baseInitialize()
|
||||
{
|
||||
return m_node.baseInitialize();
|
||||
}
|
||||
|
||||
void BitcoinApplication::startThread()
|
||||
{
|
||||
if(coreThread)
|
||||
|
@ -373,7 +373,7 @@ void BitcoinApplication::initializeResult(bool success)
|
|||
#ifdef ENABLE_BIP70
|
||||
PaymentServer::LoadRootCAs();
|
||||
#endif
|
||||
paymentServer->setOptionsModel(optionsModel);
|
||||
if (paymentServer) paymentServer->setOptionsModel(optionsModel);
|
||||
#endif
|
||||
|
||||
clientModel = new ClientModel(m_node, optionsModel);
|
||||
|
@ -402,16 +402,19 @@ void BitcoinApplication::initializeResult(bool success)
|
|||
window->show();
|
||||
}
|
||||
Q_EMIT splashFinished();
|
||||
Q_EMIT windowShown(window);
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
// Now that initialization/startup is done, process any command-line
|
||||
// bitcoin: URIs or payment requests:
|
||||
connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
|
||||
connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
|
||||
connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
|
||||
window->message(title, message, style);
|
||||
});
|
||||
QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
|
||||
if (paymentServer) {
|
||||
connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
|
||||
connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
|
||||
connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
|
||||
window->message(title, message, style);
|
||||
});
|
||||
QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
|
||||
}
|
||||
#endif
|
||||
pollShutdownTimer->start(200);
|
||||
} else {
|
||||
|
@ -454,7 +457,7 @@ static void SetupUIArgs()
|
|||
}
|
||||
|
||||
#ifndef BITCOIN_QT_TEST
|
||||
int main(int argc, char *argv[])
|
||||
int GuiMain(int argc, char* argv[])
|
||||
{
|
||||
#ifdef WIN32
|
||||
util::WinCmdLineArgs winArgs;
|
||||
|
@ -612,7 +615,7 @@ int main(int argc, char *argv[])
|
|||
// Perform base initialization before spinning up initialization/shutdown thread
|
||||
// This is acceptable because this function only contains steps that are quick to execute,
|
||||
// so the GUI thread won't be held up.
|
||||
if (node->baseInitialize()) {
|
||||
if (app.baseInitialize()) {
|
||||
app.requestInitialize();
|
||||
#if defined(Q_OS_WIN)
|
||||
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
|
||||
|
|
|
@ -71,6 +71,8 @@ public:
|
|||
void createWindow(const NetworkStyle *networkStyle);
|
||||
/// Create splash screen
|
||||
void createSplashScreen(const NetworkStyle *networkStyle);
|
||||
/// Basic initialization, before starting initialization/shutdown thread. Return true on success.
|
||||
bool baseInitialize();
|
||||
|
||||
/// Request core initialization
|
||||
void requestInitialize();
|
||||
|
@ -99,6 +101,7 @@ Q_SIGNALS:
|
|||
void requestedShutdown();
|
||||
void stopThread();
|
||||
void splashFinished();
|
||||
void windowShown(BitcoinGUI* window);
|
||||
|
||||
private:
|
||||
QThread *coreThread;
|
||||
|
@ -119,4 +122,6 @@ private:
|
|||
void startThread();
|
||||
};
|
||||
|
||||
int GuiMain(int argc, char* argv[]);
|
||||
|
||||
#endif // BITCOIN_QT_BITCOIN_H
|
||||
|
|
|
@ -110,6 +110,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
|
|||
* the central widget is the rpc console.
|
||||
*/
|
||||
setCentralWidget(rpcConsole);
|
||||
Q_EMIT consoleShown(rpcConsole);
|
||||
}
|
||||
|
||||
// Accept D&D of URIs
|
||||
|
@ -324,6 +325,7 @@ void BitcoinGUI::createActions()
|
|||
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
|
||||
// initially disable the debug window menu item
|
||||
openRPCConsoleAction->setEnabled(false);
|
||||
openRPCConsoleAction->setObjectName("openRPCConsoleAction");
|
||||
|
||||
usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this);
|
||||
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
|
||||
|
@ -642,9 +644,11 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
|
|||
assert(QSystemTrayIcon::isSystemTrayAvailable());
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
|
||||
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
|
||||
trayIcon->setToolTip(toolTip);
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||
trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
|
||||
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
|
||||
trayIcon->setToolTip(toolTip);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -724,6 +728,7 @@ void BitcoinGUI::aboutClicked()
|
|||
void BitcoinGUI::showDebugWindow()
|
||||
{
|
||||
GUIUtil::bringToFront(rpcConsole);
|
||||
Q_EMIT consoleShown(rpcConsole);
|
||||
}
|
||||
|
||||
void BitcoinGUI::showDebugWindowActivateConsole()
|
||||
|
|
|
@ -187,6 +187,8 @@ private:
|
|||
Q_SIGNALS:
|
||||
/** Signal raised when a URI was entered or dragged to the GUI */
|
||||
void receivedURI(const QString &uri);
|
||||
/** Signal raised when RPC console shown */
|
||||
void consoleShown(RPCConsole* console);
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Set number of connections shown in the UI */
|
||||
|
|
17
src/qt/main.cpp
Normal file
17
src/qt/main.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <qt/bitcoin.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
/** Translate string to current locale using Qt. */
|
||||
extern const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
|
||||
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) { return GuiMain(argc, argv); }
|
117
src/qt/test/apptests.cpp
Normal file
117
src/qt/test/apptests.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <qt/test/apptests.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <init.h>
|
||||
#include <qt/bitcoin.h>
|
||||
#include <qt/bitcoingui.h>
|
||||
#include <qt/networkstyle.h>
|
||||
#include <qt/rpcconsole.h>
|
||||
#include <shutdown.h>
|
||||
#include <validation.h>
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/bitcoin-config.h>
|
||||
#endif
|
||||
#ifdef ENABLE_WALLET
|
||||
#include <wallet/db.h>
|
||||
#endif
|
||||
|
||||
#include <QAction>
|
||||
#include <QEventLoop>
|
||||
#include <QLineEdit>
|
||||
#include <QScopedPointer>
|
||||
#include <QTest>
|
||||
#include <QTextEdit>
|
||||
#include <QtGlobal>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QtTest/QtTestWidgets>
|
||||
#endif
|
||||
#include <QtTest/QtTestGui>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <univalue.h>
|
||||
|
||||
namespace {
|
||||
//! Call getblockchaininfo RPC and check first field of JSON output.
|
||||
void TestRpcCommand(RPCConsole* console)
|
||||
{
|
||||
QEventLoop loop;
|
||||
QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget");
|
||||
QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit);
|
||||
QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit");
|
||||
QTest::keyClicks(lineEdit, "getblockchaininfo");
|
||||
QTest::keyClick(lineEdit, Qt::Key_Return);
|
||||
loop.exec();
|
||||
QString output = messagesWidget->toPlainText();
|
||||
UniValue value;
|
||||
value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString());
|
||||
QCOMPARE(value["chain"].get_str(), std::string("regtest"));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//! Entry point for BitcoinApplication tests.
|
||||
void AppTests::appTests()
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
if (QApplication::platformName() == "minimal") {
|
||||
// Disable for mac on "minimal" platform to avoid crashes inside the Qt
|
||||
// framework when it tries to look up unimplemented cocoa functions,
|
||||
// and fails to handle returned nulls
|
||||
// (https://bugreports.qt.io/browse/QTBUG-49686).
|
||||
QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
|
||||
"with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_app.parameterSetup();
|
||||
m_app.createOptionsModel(true /* reset settings */);
|
||||
QScopedPointer<const NetworkStyle> style(
|
||||
NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
|
||||
m_app.setupPlatformStyle();
|
||||
m_app.createWindow(style.data());
|
||||
connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests);
|
||||
expectCallback("guiTests");
|
||||
m_app.baseInitialize();
|
||||
m_app.requestInitialize();
|
||||
m_app.exec();
|
||||
m_app.requestShutdown();
|
||||
m_app.exec();
|
||||
|
||||
// Reset global state to avoid interfering with later tests.
|
||||
AbortShutdown();
|
||||
UnloadBlockIndex();
|
||||
}
|
||||
|
||||
//! Entry point for BitcoinGUI tests.
|
||||
void AppTests::guiTests(BitcoinGUI* window)
|
||||
{
|
||||
HandleCallback callback{"guiTests", *this};
|
||||
connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests);
|
||||
expectCallback("consoleTests");
|
||||
QAction* action = window->findChild<QAction*>("openRPCConsoleAction");
|
||||
action->activate(QAction::Trigger);
|
||||
}
|
||||
|
||||
//! Entry point for RPCConsole tests.
|
||||
void AppTests::consoleTests(RPCConsole* console)
|
||||
{
|
||||
HandleCallback callback{"consoleTests", *this};
|
||||
TestRpcCommand(console);
|
||||
}
|
||||
|
||||
//! Destructor to shut down after the last expected callback completes.
|
||||
AppTests::HandleCallback::~HandleCallback()
|
||||
{
|
||||
auto& callbacks = m_app_tests.m_callbacks;
|
||||
auto it = callbacks.find(m_callback);
|
||||
assert(it != callbacks.end());
|
||||
callbacks.erase(it);
|
||||
if (callbacks.empty()) {
|
||||
m_app_tests.m_app.quit();
|
||||
}
|
||||
}
|
50
src/qt/test/apptests.h
Normal file
50
src/qt/test/apptests.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_QT_TEST_APPTESTS_H
|
||||
#define BITCOIN_QT_TEST_APPTESTS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class BitcoinApplication;
|
||||
class BitcoinGUI;
|
||||
class RPCConsole;
|
||||
|
||||
class AppTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AppTests(BitcoinApplication& app) : m_app(app) {}
|
||||
|
||||
private Q_SLOTS:
|
||||
void appTests();
|
||||
void guiTests(BitcoinGUI* window);
|
||||
void consoleTests(RPCConsole* console);
|
||||
|
||||
private:
|
||||
//! Add expected callback name to list of pending callbacks.
|
||||
void expectCallback(std::string callback) { m_callbacks.emplace(std::move(callback)); }
|
||||
|
||||
//! RAII helper to remove no-longer-pending callback.
|
||||
struct HandleCallback
|
||||
{
|
||||
std::string m_callback;
|
||||
AppTests& m_app_tests;
|
||||
~HandleCallback();
|
||||
};
|
||||
|
||||
//! Bitcoin application.
|
||||
BitcoinApplication& m_app;
|
||||
|
||||
//! Set of pending callback names. Used to track expected callbacks and shut
|
||||
//! down the app after the last callback has been handled and all tests have
|
||||
//! either run or thrown exceptions. This could be a simple int counter
|
||||
//! instead of a set of names, but the names might be useful for debugging.
|
||||
std::multiset<std::string> m_callbacks;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_QT_TEST_APPTESTS_H
|
|
@ -41,7 +41,7 @@ void RPCNestedTests::rpcNestedTests()
|
|||
|
||||
TestingSetup test;
|
||||
|
||||
SetRPCWarmupFinished();
|
||||
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
|
||||
|
||||
std::string result;
|
||||
std::string result2;
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#endif
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <interfaces/node.h>
|
||||
#include <qt/bitcoin.h>
|
||||
#include <qt/test/apptests.h>
|
||||
#include <qt/test/rpcnestedtests.h>
|
||||
#include <util/system.h>
|
||||
#include <qt/test/uritests.h>
|
||||
|
@ -47,12 +50,13 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
SetupEnvironment();
|
||||
SetupNetworking();
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
noui_connect();
|
||||
ClearDatadirCache();
|
||||
fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
|
||||
fs::create_directories(pathTemp);
|
||||
gArgs.ForceSetArg("-datadir", pathTemp.string());
|
||||
auto node = interfaces::MakeNode();
|
||||
|
||||
bool fInvalid = false;
|
||||
|
||||
|
@ -67,11 +71,15 @@ int main(int argc, char *argv[])
|
|||
|
||||
// Don't remove this, it's needed to access
|
||||
// QApplication:: and QCoreApplication:: in the tests
|
||||
QApplication app(argc, argv);
|
||||
BitcoinApplication app(*node, argc, argv);
|
||||
app.setApplicationName("Bitcoin-Qt-test");
|
||||
|
||||
SSL_library_init();
|
||||
|
||||
AppTests app_tests(app);
|
||||
if (QTest::qExec(&app_tests) != 0) {
|
||||
fInvalid = true;
|
||||
}
|
||||
URITests test1;
|
||||
if (QTest::qExec(&test1) != 0) {
|
||||
fInvalid = true;
|
||||
|
|
Loading…
Reference in a new issue