2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-09-18 11:55:31 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
|
|
|
#include <mutex>
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
#include <boost/noncopyable.hpp>
|
|
|
|
#include <boost/program_options.hpp>
|
|
|
|
|
|
|
|
#include <System/Dispatcher.h>
|
2015-05-27 12:08:46 +00:00
|
|
|
#include <Logging/ConsoleLogger.h>
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "CryptoNoteCore/Currency.h"
|
|
|
|
#include "IWalletLegacy.h"
|
2015-04-06 16:13:07 +00:00
|
|
|
#include "INode.h"
|
2015-05-27 12:08:46 +00:00
|
|
|
#include "TestNode.h"
|
|
|
|
#include "NetworkConfiguration.h"
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
namespace Tests {
|
|
|
|
namespace Common {
|
|
|
|
|
|
|
|
namespace po = boost::program_options;
|
|
|
|
class Semaphore{
|
|
|
|
private:
|
|
|
|
std::mutex mtx;
|
|
|
|
std::condition_variable cv;
|
|
|
|
bool available;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Semaphore() : available(false) { }
|
|
|
|
|
|
|
|
void notify() {
|
|
|
|
std::unique_lock<std::mutex> lck(mtx);
|
|
|
|
available = true;
|
|
|
|
cv.notify_one();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait() {
|
|
|
|
std::unique_lock<std::mutex> lck(mtx);
|
|
|
|
cv.wait(lck, [this](){ return available; });
|
|
|
|
available = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wait_for(const std::chrono::milliseconds& rel_time) {
|
|
|
|
std::unique_lock<std::mutex> lck(mtx);
|
|
|
|
auto result = cv.wait_for(lck, rel_time, [this](){ return available; });
|
|
|
|
available = false;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
const uint16_t P2P_FIRST_PORT = 9000;
|
|
|
|
const uint16_t RPC_FIRST_PORT = 9200;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
class BaseFunctionalTestsConfig {
|
2015-04-06 16:13:07 +00:00
|
|
|
public:
|
2015-07-30 15:22:07 +00:00
|
|
|
BaseFunctionalTestsConfig() {}
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
void init(po::options_description& desc) {
|
|
|
|
desc.add_options()
|
2015-09-18 11:55:31 +00:00
|
|
|
("daemon-dir,d", po::value<std::string>()->default_value("."), "path to daemon")
|
2015-05-27 12:08:46 +00:00
|
|
|
("data-dir,n", po::value<std::string>()->default_value("."), "path to daemon's data directory")
|
|
|
|
("add-daemons,a", po::value<std::vector<std::string>>()->multitoken(), "add daemon to topology");
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool handleCommandLine(const po::variables_map& vm) {
|
|
|
|
if (vm.count("daemon-dir")) {
|
|
|
|
daemonDir = vm["daemon-dir"].as<std::string>();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm.count("data-dir")) {
|
|
|
|
dataDir = vm["data-dir"].as<std::string>();
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
if (vm.count("add-daemons")) {
|
|
|
|
daemons = vm["add-daemons"].as<std::vector<std::string>>();
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
std::string daemonDir;
|
|
|
|
std::string dataDir;
|
2015-05-27 12:08:46 +00:00
|
|
|
std::vector<std::string> daemons;
|
2015-04-06 16:13:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
class BaseFunctionalTests : boost::noncopyable {
|
2015-04-06 16:13:07 +00:00
|
|
|
public:
|
2015-07-30 15:22:07 +00:00
|
|
|
BaseFunctionalTests(const CryptoNote::Currency& currency, System::Dispatcher& d, const BaseFunctionalTestsConfig& config) :
|
2015-05-27 12:08:46 +00:00
|
|
|
m_dispatcher(d),
|
|
|
|
m_currency(currency),
|
|
|
|
m_nextTimestamp(time(nullptr) - 365 * 24 * 60 * 60),
|
|
|
|
m_config(config),
|
|
|
|
m_dataDir(config.dataDir),
|
2015-07-30 15:22:07 +00:00
|
|
|
m_daemonDir(config.daemonDir),
|
|
|
|
m_testnetSize(1) {
|
2015-05-27 12:08:46 +00:00
|
|
|
if (m_dataDir.empty()) {
|
|
|
|
m_dataDir = ".";
|
|
|
|
}
|
|
|
|
if (m_daemonDir.empty()) {
|
|
|
|
m_daemonDir = ".";
|
|
|
|
}
|
2015-04-06 16:13:07 +00:00
|
|
|
};
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
~BaseFunctionalTests();
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
enum Topology {
|
|
|
|
Ring,
|
|
|
|
Line,
|
|
|
|
Star
|
|
|
|
};
|
|
|
|
|
|
|
|
protected:
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
TestNodeConfiguration createNodeConfiguration(size_t i);
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
std::vector< std::unique_ptr<TestNode> > nodeDaemons;
|
|
|
|
System::Dispatcher& m_dispatcher;
|
2015-05-27 12:08:46 +00:00
|
|
|
const CryptoNote::Currency& m_currency;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
void launchTestnet(size_t count, Topology t = Line);
|
|
|
|
void launchTestnetWithInprocNode(size_t count, Topology t = Line);
|
2015-05-27 12:08:46 +00:00
|
|
|
void launchInprocTestnet(size_t count, Topology t = Line);
|
2015-04-06 16:13:07 +00:00
|
|
|
void stopTestnet();
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
void startNode(size_t index);
|
|
|
|
void stopNode(size_t index);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
bool makeWallet(std::unique_ptr<CryptoNote::IWalletLegacy> & wallet, std::unique_ptr<CryptoNote::INode>& node, const std::string& password = "pass");
|
2015-05-27 12:08:46 +00:00
|
|
|
bool mineBlocks(TestNode& node, const CryptoNote::AccountPublicAddress& address, size_t blockCount);
|
2015-07-30 15:22:07 +00:00
|
|
|
bool mineBlock(std::unique_ptr<CryptoNote::IWalletLegacy>& wallet);
|
2015-04-06 16:13:07 +00:00
|
|
|
bool mineBlock();
|
|
|
|
bool startMining(size_t threads);
|
|
|
|
bool stopMining();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
bool getNodeTransactionPool(size_t nodeIndex, CryptoNote::INode& node, std::vector<std::unique_ptr<CryptoNote::ITransactionReader>>& txPool);
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
bool waitDaemonsReady();
|
|
|
|
bool waitDaemonReady(size_t nodeIndex);
|
|
|
|
bool waitForPeerCount(CryptoNote::INode& node, size_t expectedPeerCount);
|
|
|
|
bool waitForPoolSize(size_t nodeIndex, CryptoNote::INode& node, size_t expectedPoolSize,
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>>& txPool);
|
2015-05-27 12:08:46 +00:00
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
bool prepareAndSubmitBlock(TestNode& node, CryptoNote::Block&& blockTemplate);
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
private:
|
|
|
|
#ifdef __linux__
|
|
|
|
std::vector<__pid_t> pids;
|
|
|
|
#endif
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
Logging::ConsoleLogger logger;
|
2015-04-06 16:13:07 +00:00
|
|
|
std::unique_ptr<CryptoNote::INode> mainNode;
|
2015-07-30 15:22:07 +00:00
|
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> workingWallet;
|
2015-05-27 12:08:46 +00:00
|
|
|
uint64_t m_nextTimestamp;
|
|
|
|
Topology m_topology;
|
|
|
|
size_t m_testnetSize;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
BaseFunctionalTestsConfig m_config;
|
2015-04-06 16:13:07 +00:00
|
|
|
std::string m_dataDir;
|
|
|
|
std::string m_daemonDir;
|
2015-05-27 12:08:46 +00:00
|
|
|
uint16_t m_mainDaemonRPCPort;
|
2015-04-06 16:13:07 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|