Isolate Application object in Env:

This change causes each instance of Env to construct its own
isolated Application object for testing. Also included is
part of a framework to create multiple Application objects
in the same unit test and connect them together.
This commit is contained in:
Vinnie Falco
2015-09-17 10:18:01 -07:00
parent 19903674af
commit 9315d98aa9
20 changed files with 630 additions and 368 deletions

View File

@@ -3760,6 +3760,16 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\utility.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\test\mao\impl\Net.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\test\mao\impl\Net_test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\test\mao\Net.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>

View File

@@ -421,6 +421,12 @@
<Filter Include="ripple\test\jtx\impl">
<UniqueIdentifier>{27D70888-7145-691C-0E0A-E511EB3A80A2}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\test\mao">
<UniqueIdentifier>{94B5035A-6D4A-E4FC-DB50-E7E804DC9F13}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\test\mao\impl">
<UniqueIdentifier>{23DE6C05-81D2-7471-D9BB-3AA1D49DE429}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\unity">
<UniqueIdentifier>{5DB3CD0B-B361-B301-9562-697CA8A52B68}</UniqueIdentifier>
</Filter>
@@ -4437,6 +4443,15 @@
<ClInclude Include="..\..\src\ripple\test\jtx\utility.h">
<Filter>ripple\test\jtx</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\test\mao\impl\Net.cpp">
<Filter>ripple\test\mao\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\test\mao\impl\Net_test.cpp">
<Filter>ripple\test\mao\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\test\mao\Net.h">
<Filter>ripple\test\mao</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
<Filter>ripple\unity</Filter>
</ClCompile>

View File

@@ -79,33 +79,6 @@ namespace ripple {
// 204/256 about 80%
static int const MAJORITY_FRACTION (204);
// This hack lets the s_instance variable remain set during
// the call to ~Application
class ApplicationImpBase : public Application
{
public:
ApplicationImpBase ()
{
assert (s_instance == nullptr);
s_instance = this;
}
~ApplicationImpBase ()
{
s_instance = nullptr;
}
static Application* s_instance;
static Application& getInstance ()
{
bassert (s_instance != nullptr);
return *s_instance;
}
};
Application* ApplicationImpBase::s_instance;
//------------------------------------------------------------------------------
namespace detail {
@@ -239,7 +212,7 @@ public:
// VFALCO TODO Move the function definitions into the class declaration
class ApplicationImp
: public ApplicationImpBase
: public Application
, public beast::RootStoppable
, public beast::DeadlineTimer::Listener
, public BasicApp
@@ -523,6 +496,25 @@ public:
//--------------------------------------------------------------------------
void setup() override;
void run() override;
bool isShutdown() override;
void signalStop() override;
//--------------------------------------------------------------------------
Logs&
logs() override
{
return *logs_;
}
Config const&
config() const override
{
return *config_;
}
CollectorManager& getCollectorManager () override
{
return *m_collectorManager;
@@ -555,18 +547,6 @@ public:
return *m_networkOPs;
}
Config const&
config() const override
{
return *config_;
}
Logs&
logs() override
{
return *logs_;
}
boost::asio::io_service& getIOService () override
{
return get_io_service();
@@ -702,12 +682,6 @@ public:
return *m_overlay;
}
// VFALCO TODO Move these to the .cpp
bool running () override
{
return mTxnDB != nullptr;
}
DatabaseCon& getTxnDB () override
{
assert (mTxnDB.get() != nullptr);
@@ -724,12 +698,6 @@ public:
return *mWalletDB;
}
bool isShutdown () override
{
// from Stoppable mixin
return isStopped();
}
bool serverOkay (std::string& reason) override;
beast::Journal journal (std::string const& name) override;
@@ -774,12 +742,145 @@ public:
}
}
// VFALCO TODO Break this function up into many small initialization segments.
// Or better yet refactor these initializations into RAII classes
// which are members of the Application object.
//--------------------------------------------------------------------------
//
void setup () override
// Stoppable
//
void onPrepare() override
{
}
void onStart () override
{
m_journal.info << "Application starting. Build is " << gitCommitID();
m_sweepTimer.setExpiration (10);
m_entropyTimer.setRecurringExpiration (300);
m_io_latency_sampler.start();
m_resolver->start ();
}
// Called to indicate shutdown.
void onStop () override
{
m_journal.debug << "Application stopping";
m_io_latency_sampler.cancel_async ();
// VFALCO Enormous hack, we have to force the probe to cancel
// before we stop the io_service queue or else it never
// unblocks in its destructor. The fix is to make all
// io_objects gracefully handle exit so that we can
// naturally return from io_service::run() instead of
// forcing a call to io_service::stop()
m_io_latency_sampler.cancel ();
m_resolver->stop_async ();
// NIKB This is a hack - we need to wait for the resolver to
// stop. before we stop the io_server_queue or weird
// things will happen.
m_resolver->stop ();
m_sweepTimer.cancel ();
m_entropyTimer.cancel ();
mValidations->flush ();
m_overlay->saveValidatorKeyManifests (getWalletDB ());
stopped ();
}
//------------------------------------------------------------------------------
//
// PropertyStream
//
void onWrite (beast::PropertyStream::Map& stream) override
{
}
//------------------------------------------------------------------------------
void exitWithCode(int code)
{
StopSustain();
// VFALCO This breaks invariants: automatic objects
// will not have destructors called.
std::exit(code);
}
void onDeadlineTimer (beast::DeadlineTimer& timer) override
{
if (timer == m_entropyTimer)
{
add_entropy (nullptr, 0);
return;
}
if (timer == m_sweepTimer)
{
// VFALCO TODO Move all this into doSweep
boost::filesystem::space_info space =
boost::filesystem::space (config_->legacy ("database_path"));
// VFALCO TODO Give this magic constant a name and move it into a well documented header
//
if (space.available < (512 * 1024 * 1024))
{
m_journal.fatal << "Remaining free disk space is less than 512MB";
signalStop ();
}
m_jobQueue->addJob(jtSWEEP, "sweep", [this] (Job&) { doSweep(); });
}
}
void doSweep ()
{
// VFALCO NOTE Does the order of calls matter?
// VFALCO TODO fix the dependency inversion using an observer,
// have listeners register for "onSweep ()" notification.
family().fullbelow().sweep ();
getMasterTransaction().sweep();
getNodeStore().sweep();
getLedgerMaster().sweep();
getTempNodeCache().sweep();
getValidations().sweep();
getInboundLedgers().sweep();
m_acceptedLedgerCache.sweep();
family().treecache().sweep();
cachedSLEs_.expire();
// VFALCO NOTE does the call to sweep() happen on another thread?
m_sweepTimer.setExpiration (config_->getSize (siSweepInterval));
}
private:
void addTxnSeqField();
void updateTables ();
void startGenesisLedger ();
Ledger::pointer getLastFullLedger();
bool loadOldLedger (
std::string const& ledgerID, bool replay, bool isFilename);
};
//------------------------------------------------------------------------------
// VFALCO TODO Break this function up into many small initialization segments.
// Or better yet refactor these initializations into RAII classes
// which are members of the Application object.
//
void ApplicationImp::setup()
{
// VFALCO NOTE: 0 means use heuristics to determine the thread count.
m_jobQueue->setThreadCount (0, config_->RUN_STANDALONE);
@@ -951,75 +1052,11 @@ public:
m_networkOPs->setStandAlone ();
}
}
}
//--------------------------------------------------------------------------
//
// Stoppable
//
void onPrepare() override
{
}
void onStart () override
{
m_journal.info << "Application starting. Build is " << gitCommitID();
m_sweepTimer.setExpiration (10);
m_entropyTimer.setRecurringExpiration (300);
m_io_latency_sampler.start();
m_resolver->start ();
}
// Called to indicate shutdown.
void onStop () override
{
m_journal.debug << "Application stopping";
m_io_latency_sampler.cancel_async ();
// VFALCO Enormous hack, we have to force the probe to cancel
// before we stop the io_service queue or else it never
// unblocks in its destructor. The fix is to make all
// io_objects gracefully handle exit so that we can
// naturally return from io_service::run() instead of
// forcing a call to io_service::stop()
m_io_latency_sampler.cancel ();
m_resolver->stop_async ();
// NIKB This is a hack - we need to wait for the resolver to
// stop. before we stop the io_server_queue or weird
// things will happen.
m_resolver->stop ();
m_sweepTimer.cancel ();
m_entropyTimer.cancel ();
mValidations->flush ();
m_overlay->saveValidatorKeyManifests (getWalletDB ());
stopped ();
}
//------------------------------------------------------------------------------
//
// PropertyStream
//
void onWrite (beast::PropertyStream::Map& stream) override
{
}
//------------------------------------------------------------------------------
void run () override
{
void
ApplicationImp::run()
{
// VFALCO NOTE I put this here in the hopes that when unit tests run (which
// tragically require an Application object to exist or else they
// crash), the run() function will not get called and we will
@@ -1047,84 +1084,27 @@ public:
stop (m_journal);
m_journal.info << "Done.";
StopSustain();
}
}
void exitWithCode(int code)
{
StopSustain();
// VFALCO This breaks invariants: automatic objects
// will not have destructors called.
std::exit(code);
}
void signalStop () override
{
void
ApplicationImp::signalStop()
{
// Unblock the main thread (which is sitting in run()).
//
m_stop.signal();
}
}
void onDeadlineTimer (beast::DeadlineTimer& timer) override
{
if (timer == m_entropyTimer)
{
add_entropy (nullptr, 0);
return;
}
if (timer == m_sweepTimer)
{
// VFALCO TODO Move all this into doSweep
boost::filesystem::space_info space =
boost::filesystem::space (config_->legacy ("database_path"));
// VFALCO TODO Give this magic constant a name and move it into a well documented header
//
if (space.available < (512 * 1024 * 1024))
{
m_journal.fatal << "Remaining free disk space is less than 512MB";
signalStop ();
}
m_jobQueue->addJob(jtSWEEP, "sweep", [this] (Job&) { doSweep(); });
}
}
void doSweep ()
{
// VFALCO NOTE Does the order of calls matter?
// VFALCO TODO fix the dependency inversion using an observer,
// have listeners register for "onSweep ()" notification.
family().fullbelow().sweep ();
getMasterTransaction().sweep();
getNodeStore().sweep();
getLedgerMaster().sweep();
getTempNodeCache().sweep();
getValidations().sweep();
getInboundLedgers().sweep();
m_acceptedLedgerCache.sweep();
family().treecache().sweep();
cachedSLEs_.expire();
// VFALCO NOTE does the call to sweep() happen on another thread?
m_sweepTimer.setExpiration (config_->getSize (siSweepInterval));
}
private:
void addTxnSeqField();
void updateTables ();
void startGenesisLedger ();
Ledger::pointer getLastFullLedger();
bool loadOldLedger (
std::string const& ledgerID, bool replay, bool isFilename);
};
bool
ApplicationImp::isShutdown()
{
// from Stoppable mixin
return isStopped();
}
//------------------------------------------------------------------------------
void ApplicationImp::startGenesisLedger ()
void
ApplicationImp::startGenesisLedger()
{
std::shared_ptr<Ledger> const genesis =
std::make_shared<Ledger>(
@@ -1485,14 +1465,17 @@ bool ApplicationImp::serverOkay (std::string& reason)
return true;
}
beast::Journal ApplicationImp::journal (std::string const& name)
beast::Journal
ApplicationImp::journal (std::string const& name)
{
return logs_->journal (name);
}
//VFALCO TODO clean this up since it is just a file holding a single member function definition
static std::vector<std::string> getSchema (DatabaseCon& dbc, std::string const& dbName)
static
std::vector<std::string>
getSchema (DatabaseCon& dbc, std::string const& dbName)
{
std::vector<std::string> schema;
schema.reserve(32);
@@ -1653,6 +1636,8 @@ Application::Application ()
{
}
//------------------------------------------------------------------------------
std::unique_ptr<Application>
make_Application (
std::unique_ptr<Config const> config,
@@ -1662,9 +1647,14 @@ make_Application (
std::move(config), std::move(logs));
}
Application& getApp ()
void
setupConfigForUnitTests (Config& config)
{
return ApplicationImpBase::getInstance ();
config.overwrite (ConfigSection::nodeDatabase (), "type", "memory");
config.overwrite (ConfigSection::nodeDatabase (), "path", "main");
config.deprecatedClearSection (ConfigSection::importNodeDatabase ());
config.legacy("database_path", "DummyForUnitTests");
}
}

View File

@@ -90,8 +90,18 @@ public:
Application ();
virtual ~Application () = default;
virtual Config const& config() const = 0;
virtual void setup() = 0;
virtual void run() = 0;
virtual bool isShutdown () = 0;
virtual void signalStop () = 0;
//
// ---
//
virtual Logs& logs() = 0;
virtual Config const& config() const = 0;
virtual boost::asio::io_service& getIOService () = 0;
virtual CollectorManager& getCollectorManager () = 0;
virtual Family& family() = 0;
@@ -138,12 +148,6 @@ public:
// NOTE This will be replaced by class Validators
//
virtual DatabaseCon& getWalletDB () = 0;
virtual bool isShutdown () = 0;
virtual bool running () = 0;
virtual void setup () = 0;
virtual void run () = 0;
virtual void signalStop () = 0;
};
std::unique_ptr <Application>
@@ -151,8 +155,9 @@ make_Application(
std::unique_ptr<Config const> config,
std::unique_ptr<Logs> logs);
// DEPRECATED
extern Application& getApp ();
extern
void
setupConfigForUnitTests (Config& config);
}

View File

@@ -162,17 +162,6 @@ void printHelp (const po::options_description& desc)
//------------------------------------------------------------------------------
static
void
setupConfigForUnitTests (Config& config)
{
config.overwrite (ConfigSection::nodeDatabase (), "type", "memory");
config.overwrite (ConfigSection::nodeDatabase (), "path", "main");
config.deprecatedClearSection (ConfigSection::importNodeDatabase ());
config.legacy("database_path", "DummyForUnitTests");
}
static int runShutdownTests (std::unique_ptr<Config> config)
{
// Shutdown tests can not be part of the normal unit tests in 'runUnitTests'
@@ -204,18 +193,10 @@ static int runShutdownTests (std::unique_ptr<Config> config)
return EXIT_SUCCESS;
}
static int runUnitTests (
std::unique_ptr<Config> config,
static int runUnitTests(
std::string const& pattern,
std::string const& argument)
{
// Config needs to be set up before creating Application
setupConfigForUnitTests (*config);
auto app = make_Application (
std::move(config),
std::make_unique<Logs>());
using namespace beast::unit_test;
beast::debug_ostream stream;
reporter r (stream);
@@ -363,9 +344,7 @@ int run (int argc, char** argv)
argument = vm["unittest-arg"].as<std::string>();
return runUnitTests(
std::make_unique<Config> (),
vm["unittest"].as<std::string>(),
argument);
vm["unittest"].as<std::string>(), argument);
}
auto config = std::make_unique<Config>();

View File

@@ -142,7 +142,7 @@ public:
env.require (owners (alice, 4));
// This should work.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(bogie, demon), fee(3 * baseFee));
env.close();
@@ -232,7 +232,7 @@ public:
// alice multisigns a transaction. Should succeed.
std::uint32_t aliceSeq = env.seq (alice);
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
env(noop(alice), msig(bogie), fee(2 * baseFee));
env.close();
expect (env.seq(alice) == aliceSeq + 1);
@@ -265,7 +265,7 @@ public:
env.require (owners (alice, 10));
// This should work.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(bogie), fee(2 * baseFee));
env.close();
@@ -348,7 +348,7 @@ public:
env.require (owners (alice, 4));
// Attempt a multisigned transaction that meets the quorum.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
aliceSeq = env.seq (alice);
env(noop(alice), msig(cheri), fee(2 * baseFee));
env.close();
@@ -401,7 +401,7 @@ public:
env.close();
// Attempt a multisigned transaction that meets the quorum.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(msig::Reg{cheri, cher}), fee(2 * baseFee));
env.close();
@@ -468,7 +468,7 @@ public:
env.require (owners (alice, 6));
// Each type of signer should succeed individually.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(becky), fee(2 * baseFee));
env.close();
@@ -592,7 +592,7 @@ public:
env(regkey (alice, disabled), sig(alie));
// L0; A lone signer list cannot be removed.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
env(signers(alice, jtx::none), msig(bogie),
fee(2 * baseFee), ter(tecNO_ALTERNATIVE_KEY));
@@ -645,7 +645,7 @@ public:
env.require (owners (alice, 4));
// Multisign a ttPAYMENT.
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
std::uint32_t aliceSeq = env.seq (alice);
env(pay(alice, env.master, XRP(1)),
msig(becky, bogie), fee(3 * baseFee));

View File

@@ -49,7 +49,7 @@ struct Regression_test : public beast::unit_test::suite
// be reproduced against an open ledger. Make a local
// closed ledger and work with it directly.
auto closed = std::make_shared<Ledger>(
create_genesis, env.config, env.app().family());
create_genesis, env.app().config(), env.app().family());
auto expectedDrops = SYSTEM_CURRENCY_START;
expect(closed->info().drops == expectedDrops);
@@ -67,7 +67,7 @@ struct Regression_test : public beast::unit_test::suite
auto const result = ripple::apply(env.app(),
accum, *jt.stx, tapENABLE_TESTING,
directSigVerify, env.config,
directSigVerify, env.app().config(),
env.journal);
expect(result.first == tesSUCCESS);
expect(result.second);
@@ -95,7 +95,7 @@ struct Regression_test : public beast::unit_test::suite
auto const result = ripple::apply(env.app(),
accum, *jt.stx, tapENABLE_TESTING,
directSigVerify, env.config,
directSigVerify, env.app().config(),
env.journal);
expect(result.first == tecINSUFF_FEE);
expect(result.second);

View File

@@ -175,6 +175,9 @@ public:
If the section does not exist, an empty section is returned.
*/
/** @{ */
Section&
section (std::string const& name);
Section const&
section (std::string const& name) const;
@@ -183,6 +186,12 @@ public:
{
return section(name);
}
Section&
operator[] (std::string const& name)
{
return section(name);
}
/** @} */
/** Overwrite a key/value pair with a command line argument

View File

@@ -96,6 +96,12 @@ BasicConfig::exists (std::string const& name) const
return map_.find(name) != map_.end();
}
Section&
BasicConfig::section (std::string const& name)
{
return map_[name];
}
Section const&
BasicConfig::section (std::string const& name) const
{

View File

@@ -162,9 +162,7 @@ public:
beast::File getModuleDatabasePath () const;
bool doImport = false;
bool QUIET = false;
bool ELB_SUPPORT = false;
std::string VALIDATORS_SITE; // Where to find validators.txt on the Internet.

View File

@@ -47,13 +47,8 @@ public:
Account (Account const&) = default;
Account& operator= (Account const&) = default;
#ifdef _MSC_VER
Account (Account&&);
Account& operator= (Account&&);
#else
Account (Account&&) = default;
Account& operator= (Account&&) = default;
#endif
/** Create an account from a key pair. */
Account (std::string name,

View File

@@ -29,6 +29,7 @@
#include <ripple/app/ledger/Ledger.h>
#include <ripple/app/ledger/OpenLedger.h>
#include <ripple/basics/chrono.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/json/json_value.h>
#include <ripple/json/to_string.h>
@@ -126,13 +127,21 @@ public:
beast::Journal const journal;
/** Configuration used. */
Config const config;
/** The master account. */
Account const master;
private:
struct AppBundle
{
Application* app;
std::unique_ptr<Logs> logs;
std::unique_ptr<Application> owned;
AppBundle (std::unique_ptr<Config const> config);
AppBundle (Application* app_);
};
AppBundle bundle_;
std::shared_ptr<Ledger const> closed_;
CachedSLEs cachedSLEs_;
LogSquelcher logSquelcher_;
@@ -150,7 +159,7 @@ public:
Application&
app()
{
return getApp();
return *bundle_.app;
}
/** Returns the open ledger.

View File

@@ -26,28 +26,6 @@ namespace ripple {
namespace test {
namespace jtx {
#ifdef _MSC_VER
Account::Account (Account&& other)
: name_(std::move(other.name_))
, pk_(std::move(other.pk_))
, sk_(std::move(other.sk_))
, id_(std::move(other.id_))
, human_(std::move(other.human_))
{
}
Account&
Account::operator= (Account&& rhs)
{
name_ = std::move(rhs.name_);
pk_ = std::move(rhs.pk_);
sk_ = std::move(rhs.sk_);
id_ = std::move(rhs.id_);
human_ = std::move(rhs.human_);
return *this;
}
#endif
Account::Account(std::string name,
std::pair<PublicKey, SecretKey> const& keys)
: name_(std::move(name))
@@ -58,16 +36,15 @@ Account::Account(std::string name,
{
}
Account::Account (std::string name,
KeyType type)
#ifndef _MSC_VER
: Account(name,
#else
// Fails on Clang and possibly gcc
: Account(std::move(name),
#endif
generateKeyPair(type, generateSeed(name)))
Account::Account (std::string name, KeyType type)
: name_(std::move(name))
{
auto const keys = generateKeyPair(
type, generateSeed(name_));
pk_ = keys.first;
sk_ = keys.second;
id_ = calcAccountID(pk_);
human_ = toBase58(id_);
}
IOU

View File

@@ -50,17 +50,41 @@ namespace test {
namespace jtx {
Env::AppBundle::AppBundle(Application* app_)
: app (app_)
{
}
Env::AppBundle::AppBundle(std::unique_ptr<Config const> config)
{
auto logs = std::make_unique<Logs>();
owned = make_Application(
std::move(config), std::move(logs));
app = owned.get();
}
//------------------------------------------------------------------------------
static
std::unique_ptr<Config const>
makeConfig()
{
auto p = std::make_unique<Config>();
setupConfigForUnitTests(*p);
return std::unique_ptr<Config const>(p.release());
}
// VFALCO Could wrap the log in a Journal here
Env::Env (beast::unit_test::suite& test_)
: test(test_)
, config()
, master("master", generateKeyPair(
: test (test_)
, master ("master", generateKeyPair(
KeyType::secp256k1,
generateSeed("masterpassphrase")))
, bundle_ (makeConfig())
, closed_ (std::make_shared<Ledger>(
create_genesis, config, app().family()))
create_genesis, app().config(), app().family()))
, cachedSLEs_ (std::chrono::seconds(5), stopwatch_)
, openLedger (closed_, config, cachedSLEs_, journal)
, openLedger (closed_, app().config(), cachedSLEs_, journal)
{
memoize(master);
initializePathfinding();
@@ -98,7 +122,7 @@ Env::close(NetClock::time_point const& closeTime)
OpenView accum(&*next);
OpenLedger::apply(app(), accum, *closed_,
txs, retries, applyFlags(), *router,
config, journal);
app().config(), journal);
accum.apply(*next);
}
// To ensure that the close time is exact and not rounded, we don't
@@ -254,7 +278,7 @@ Env::submit (JTx const& jt)
{
std::tie(ter_, didApply) = ripple::apply(
app(), view, *stx, applyFlags(),
directSigVerify, config,
directSigVerify, app().config(),
beast::Journal{});
return didApply;
});

View File

@@ -360,7 +360,7 @@ public:
{ { "bob", 1 }, { "carol", 2 } }));
env(noop("alice"));
auto const baseFee = env.config.FEE_DEFAULT;
auto const baseFee = env.app().config().FEE_DEFAULT;
env(noop("alice"), msig("bob"), fee(2 * baseFee));
env(noop("alice"), msig("carol"), fee(2 * baseFee));
env(noop("alice"), msig("bob", "carol"), fee(3 * baseFee));

27
src/ripple/test/mao.h Normal file
View File

@@ -0,0 +1,27 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TEST_MAO_H_INCLUDED
#define RIPPLE_TEST_MAO_H_INCLUDED
// Convenience header that includes everything
#include <ripple/test/mao/Net.h>
#endif

39
src/ripple/test/mao/Net.h Normal file
View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TEST_MAO_H_INCLUDED
#define RIPPLE_TEST_MAO_H_INCLUDED
#include <ripple/app/main/Application.h>
namespace ripple {
namespace test {
namespace mao {
class Net
{
private:
public:
};
} // mao
} // test
} // ripple
#endif

View File

@@ -0,0 +1,31 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/test/mao/Net.h>
namespace ripple {
namespace test {
namespace mao {
} // mao
} // test
} // ripple

View File

@@ -0,0 +1,145 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/basics/Log.h>
#include <ripple/test/mao/Net.h>
#include <ripple/net/HTTPClient.h>
#include <ripple/net/RPCCall.h>
#include <beast/unit_test/suite.h>
#include <memory>
#include <mutex>
#include <thread>
#include <utility>
namespace ripple {
namespace test {
namespace mao {
struct TestApp
{
TestApp()
{
auto config = std::make_unique<Config>();
setupConfigForUnitTests(*config);
config->RUN_STANDALONE = true;
(*config)["server"].append("port_peer");
(*config)["port_peer"].set("ip", "127.0.0.1");
(*config)["port_peer"].set("port", "8080");
(*config)["port_peer"].set("protocol", "peer");
(*config)["server"].append("port_admin");
(*config)["port_admin"].set("ip", "127.0.0.1");
(*config)["port_admin"].set("port", "8081");
(*config)["port_admin"].set("protocol", "http");
(*config)["port_admin"].set("admin", "127.0.0.1");
// Hack so we dont have to call Config::setup
HTTPClient::initializeSSLContext(*config);
auto logs = std::make_unique<Logs>();
instance = make_Application(
std::move(config), std::move(logs));
instance->setup();
thread_ = std::thread(
[&]() { instance->run(); });
}
~TestApp()
{
if (thread_.joinable())
{
instance->signalStop();
thread_.join();
}
}
void
join()
{
thread_.join();
}
Application*
operator->()
{
return instance.get();
}
template <class T, class... Args>
void
rpc (T const& t, Args const&... args)
{
std::vector<std::string> v;
collect(v, t, args...);
RPCCall::fromCommandLine(
instance->config(), v,
instance->logs());
}
private:
inline
void
collect (std::vector<std::string>& v)
{
}
template <class T, class... Args>
void
collect (std::vector<std::string>& v,
T const& t, Args const&... args)
{
v.emplace_back(t);
collect(v, args...);
}
std::unique_ptr<Application> instance;
std::thread thread_;
std::mutex mutex_;
};
class Net_test : public beast::unit_test::suite
{
public:
void
testStartStop()
{
TestApp app;
pass();
}
void
testRPC()
{
TestApp app;
app.rpc("stop");
app.join();
pass();
}
void
run() override
{
testStartStop();
testRPC();
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(Net,mao,ripple)
} // mao
} // test
} // ripple

View File

@@ -24,6 +24,7 @@
#include <ripple/test/jtx/impl/balance.cpp>
#include <ripple/test/jtx/impl/delivermin.cpp>
#include <ripple/test/jtx/impl/Env.cpp>
#include <ripple/test/jtx/impl/Env_test.cpp>
#include <ripple/test/jtx/impl/fee.cpp>
#include <ripple/test/jtx/impl/flags.cpp>
#include <ripple/test/jtx/impl/jtx_json.cpp>
@@ -44,4 +45,6 @@
#include <ripple/test/jtx/impl/txflags.cpp>
#include <ripple/test/jtx/impl/utility.cpp>
#include <ripple/test/jtx/impl/Env_test.cpp>
#include <ripple/test/mao/impl/Net.cpp>
#include <ripple/test/mao/impl/Net_test.cpp>