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>
<ClInclude Include="..\..\src\ripple\test\jtx\utility.h"> <ClInclude Include="..\..\src\ripple\test\jtx\utility.h">
</ClInclude> </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"> <ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.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"> <Filter Include="ripple\test\jtx\impl">
<UniqueIdentifier>{27D70888-7145-691C-0E0A-E511EB3A80A2}</UniqueIdentifier> <UniqueIdentifier>{27D70888-7145-691C-0E0A-E511EB3A80A2}</UniqueIdentifier>
</Filter> </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"> <Filter Include="ripple\unity">
<UniqueIdentifier>{5DB3CD0B-B361-B301-9562-697CA8A52B68}</UniqueIdentifier> <UniqueIdentifier>{5DB3CD0B-B361-B301-9562-697CA8A52B68}</UniqueIdentifier>
</Filter> </Filter>
@@ -4437,6 +4443,15 @@
<ClInclude Include="..\..\src\ripple\test\jtx\utility.h"> <ClInclude Include="..\..\src\ripple\test\jtx\utility.h">
<Filter>ripple\test\jtx</Filter> <Filter>ripple\test\jtx</Filter>
</ClInclude> </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"> <ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
<Filter>ripple\unity</Filter> <Filter>ripple\unity</Filter>
</ClCompile> </ClCompile>

View File

@@ -79,33 +79,6 @@ namespace ripple {
// 204/256 about 80% // 204/256 about 80%
static int const MAJORITY_FRACTION (204); 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 { namespace detail {
@@ -239,7 +212,7 @@ public:
// VFALCO TODO Move the function definitions into the class declaration // VFALCO TODO Move the function definitions into the class declaration
class ApplicationImp class ApplicationImp
: public ApplicationImpBase : public Application
, public beast::RootStoppable , public beast::RootStoppable
, public beast::DeadlineTimer::Listener , public beast::DeadlineTimer::Listener
, public BasicApp , 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 CollectorManager& getCollectorManager () override
{ {
return *m_collectorManager; return *m_collectorManager;
@@ -555,18 +547,6 @@ public:
return *m_networkOPs; return *m_networkOPs;
} }
Config const&
config() const override
{
return *config_;
}
Logs&
logs() override
{
return *logs_;
}
boost::asio::io_service& getIOService () override boost::asio::io_service& getIOService () override
{ {
return get_io_service(); return get_io_service();
@@ -702,12 +682,6 @@ public:
return *m_overlay; return *m_overlay;
} }
// VFALCO TODO Move these to the .cpp
bool running () override
{
return mTxnDB != nullptr;
}
DatabaseCon& getTxnDB () override DatabaseCon& getTxnDB () override
{ {
assert (mTxnDB.get() != nullptr); assert (mTxnDB.get() != nullptr);
@@ -724,12 +698,6 @@ public:
return *mWalletDB; return *mWalletDB;
} }
bool isShutdown () override
{
// from Stoppable mixin
return isStopped();
}
bool serverOkay (std::string& reason) override; bool serverOkay (std::string& reason) override;
beast::Journal journal (std::string const& name) 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. // VFALCO NOTE: 0 means use heuristics to determine the thread count.
m_jobQueue->setThreadCount (0, config_->RUN_STANDALONE); m_jobQueue->setThreadCount (0, config_->RUN_STANDALONE);
@@ -951,75 +1052,11 @@ public:
m_networkOPs->setStandAlone (); m_networkOPs->setStandAlone ();
} }
} }
//-------------------------------------------------------------------------- void
// ApplicationImp::run()
// 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
{
// VFALCO NOTE I put this here in the hopes that when unit tests run (which // 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 // tragically require an Application object to exist or else they
// crash), the run() function will not get called and we will // crash), the run() function will not get called and we will
@@ -1047,84 +1084,27 @@ public:
stop (m_journal); stop (m_journal);
m_journal.info << "Done."; m_journal.info << "Done.";
StopSustain(); StopSustain();
} }
void exitWithCode(int code) void
{ ApplicationImp::signalStop()
StopSustain(); {
// VFALCO This breaks invariants: automatic objects
// will not have destructors called.
std::exit(code);
}
void signalStop () override
{
// Unblock the main thread (which is sitting in run()). // Unblock the main thread (which is sitting in run()).
// //
m_stop.signal(); m_stop.signal();
} }
void onDeadlineTimer (beast::DeadlineTimer& timer) override bool
{ ApplicationImp::isShutdown()
if (timer == m_entropyTimer) {
{ // from Stoppable mixin
add_entropy (nullptr, 0); return isStopped();
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);
};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void ApplicationImp::startGenesisLedger () void
ApplicationImp::startGenesisLedger()
{ {
std::shared_ptr<Ledger> const genesis = std::shared_ptr<Ledger> const genesis =
std::make_shared<Ledger>( std::make_shared<Ledger>(
@@ -1485,14 +1465,17 @@ bool ApplicationImp::serverOkay (std::string& reason)
return true; return true;
} }
beast::Journal ApplicationImp::journal (std::string const& name) beast::Journal
ApplicationImp::journal (std::string const& name)
{ {
return logs_->journal (name); return logs_->journal (name);
} }
//VFALCO TODO clean this up since it is just a file holding a single member function definition //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; std::vector<std::string> schema;
schema.reserve(32); schema.reserve(32);
@@ -1653,6 +1636,8 @@ Application::Application ()
{ {
} }
//------------------------------------------------------------------------------
std::unique_ptr<Application> std::unique_ptr<Application>
make_Application ( make_Application (
std::unique_ptr<Config const> config, std::unique_ptr<Config const> config,
@@ -1662,9 +1647,14 @@ make_Application (
std::move(config), std::move(logs)); 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 (); Application ();
virtual ~Application () = default; 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 Logs& logs() = 0;
virtual Config const& config() const = 0;
virtual boost::asio::io_service& getIOService () = 0; virtual boost::asio::io_service& getIOService () = 0;
virtual CollectorManager& getCollectorManager () = 0; virtual CollectorManager& getCollectorManager () = 0;
virtual Family& family() = 0; virtual Family& family() = 0;
@@ -138,12 +148,6 @@ public:
// NOTE This will be replaced by class Validators // NOTE This will be replaced by class Validators
// //
virtual DatabaseCon& getWalletDB () = 0; 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> std::unique_ptr <Application>
@@ -151,8 +155,9 @@ make_Application(
std::unique_ptr<Config const> config, std::unique_ptr<Config const> config,
std::unique_ptr<Logs> logs); std::unique_ptr<Logs> logs);
// DEPRECATED extern
extern Application& getApp (); 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) static int runShutdownTests (std::unique_ptr<Config> config)
{ {
// Shutdown tests can not be part of the normal unit tests in 'runUnitTests' // 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; return EXIT_SUCCESS;
} }
static int runUnitTests ( static int runUnitTests(
std::unique_ptr<Config> config,
std::string const& pattern, std::string const& pattern,
std::string const& argument) 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; using namespace beast::unit_test;
beast::debug_ostream stream; beast::debug_ostream stream;
reporter r (stream); reporter r (stream);
@@ -363,9 +344,7 @@ int run (int argc, char** argv)
argument = vm["unittest-arg"].as<std::string>(); argument = vm["unittest-arg"].as<std::string>();
return runUnitTests( return runUnitTests(
std::make_unique<Config> (), vm["unittest"].as<std::string>(), argument);
vm["unittest"].as<std::string>(),
argument);
} }
auto config = std::make_unique<Config>(); auto config = std::make_unique<Config>();

View File

@@ -142,7 +142,7 @@ public:
env.require (owners (alice, 4)); env.require (owners (alice, 4));
// This should work. // 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); std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(bogie, demon), fee(3 * baseFee)); env(noop(alice), msig(bogie, demon), fee(3 * baseFee));
env.close(); env.close();
@@ -232,7 +232,7 @@ public:
// alice multisigns a transaction. Should succeed. // alice multisigns a transaction. Should succeed.
std::uint32_t aliceSeq = env.seq (alice); 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(noop(alice), msig(bogie), fee(2 * baseFee));
env.close(); env.close();
expect (env.seq(alice) == aliceSeq + 1); expect (env.seq(alice) == aliceSeq + 1);
@@ -265,7 +265,7 @@ public:
env.require (owners (alice, 10)); env.require (owners (alice, 10));
// This should work. // 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); std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(bogie), fee(2 * baseFee)); env(noop(alice), msig(bogie), fee(2 * baseFee));
env.close(); env.close();
@@ -348,7 +348,7 @@ public:
env.require (owners (alice, 4)); env.require (owners (alice, 4));
// Attempt a multisigned transaction that meets the quorum. // 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); aliceSeq = env.seq (alice);
env(noop(alice), msig(cheri), fee(2 * baseFee)); env(noop(alice), msig(cheri), fee(2 * baseFee));
env.close(); env.close();
@@ -401,7 +401,7 @@ public:
env.close(); env.close();
// Attempt a multisigned transaction that meets the quorum. // 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); std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(msig::Reg{cheri, cher}), fee(2 * baseFee)); env(noop(alice), msig(msig::Reg{cheri, cher}), fee(2 * baseFee));
env.close(); env.close();
@@ -468,7 +468,7 @@ public:
env.require (owners (alice, 6)); env.require (owners (alice, 6));
// Each type of signer should succeed individually. // 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); std::uint32_t aliceSeq = env.seq (alice);
env(noop(alice), msig(becky), fee(2 * baseFee)); env(noop(alice), msig(becky), fee(2 * baseFee));
env.close(); env.close();
@@ -592,7 +592,7 @@ public:
env(regkey (alice, disabled), sig(alie)); env(regkey (alice, disabled), sig(alie));
// L0; A lone signer list cannot be removed. // 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), env(signers(alice, jtx::none), msig(bogie),
fee(2 * baseFee), ter(tecNO_ALTERNATIVE_KEY)); fee(2 * baseFee), ter(tecNO_ALTERNATIVE_KEY));
@@ -645,7 +645,7 @@ public:
env.require (owners (alice, 4)); env.require (owners (alice, 4));
// Multisign a ttPAYMENT. // 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); std::uint32_t aliceSeq = env.seq (alice);
env(pay(alice, env.master, XRP(1)), env(pay(alice, env.master, XRP(1)),
msig(becky, bogie), fee(3 * baseFee)); 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 // be reproduced against an open ledger. Make a local
// closed ledger and work with it directly. // closed ledger and work with it directly.
auto closed = std::make_shared<Ledger>( 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; auto expectedDrops = SYSTEM_CURRENCY_START;
expect(closed->info().drops == expectedDrops); expect(closed->info().drops == expectedDrops);
@@ -67,7 +67,7 @@ struct Regression_test : public beast::unit_test::suite
auto const result = ripple::apply(env.app(), auto const result = ripple::apply(env.app(),
accum, *jt.stx, tapENABLE_TESTING, accum, *jt.stx, tapENABLE_TESTING,
directSigVerify, env.config, directSigVerify, env.app().config(),
env.journal); env.journal);
expect(result.first == tesSUCCESS); expect(result.first == tesSUCCESS);
expect(result.second); expect(result.second);
@@ -95,7 +95,7 @@ struct Regression_test : public beast::unit_test::suite
auto const result = ripple::apply(env.app(), auto const result = ripple::apply(env.app(),
accum, *jt.stx, tapENABLE_TESTING, accum, *jt.stx, tapENABLE_TESTING,
directSigVerify, env.config, directSigVerify, env.app().config(),
env.journal); env.journal);
expect(result.first == tecINSUFF_FEE); expect(result.first == tecINSUFF_FEE);
expect(result.second); expect(result.second);

View File

@@ -175,6 +175,9 @@ public:
If the section does not exist, an empty section is returned. If the section does not exist, an empty section is returned.
*/ */
/** @{ */ /** @{ */
Section&
section (std::string const& name);
Section const& Section const&
section (std::string const& name) const; section (std::string const& name) const;
@@ -183,6 +186,12 @@ public:
{ {
return section(name); return section(name);
} }
Section&
operator[] (std::string const& name)
{
return section(name);
}
/** @} */ /** @} */
/** Overwrite a key/value pair with a command line argument /** 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(); return map_.find(name) != map_.end();
} }
Section&
BasicConfig::section (std::string const& name)
{
return map_[name];
}
Section const& Section const&
BasicConfig::section (std::string const& name) const BasicConfig::section (std::string const& name) const
{ {

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,17 +50,41 @@ namespace test {
namespace jtx { 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 // VFALCO Could wrap the log in a Journal here
Env::Env (beast::unit_test::suite& test_) Env::Env (beast::unit_test::suite& test_)
: test(test_) : test (test_)
, config() , master ("master", generateKeyPair(
, master("master", generateKeyPair(
KeyType::secp256k1, KeyType::secp256k1,
generateSeed("masterpassphrase"))) generateSeed("masterpassphrase")))
, bundle_ (makeConfig())
, closed_ (std::make_shared<Ledger>( , closed_ (std::make_shared<Ledger>(
create_genesis, config, app().family())) create_genesis, app().config(), app().family()))
, cachedSLEs_ (std::chrono::seconds(5), stopwatch_) , cachedSLEs_ (std::chrono::seconds(5), stopwatch_)
, openLedger (closed_, config, cachedSLEs_, journal) , openLedger (closed_, app().config(), cachedSLEs_, journal)
{ {
memoize(master); memoize(master);
initializePathfinding(); initializePathfinding();
@@ -98,7 +122,7 @@ Env::close(NetClock::time_point const& closeTime)
OpenView accum(&*next); OpenView accum(&*next);
OpenLedger::apply(app(), accum, *closed_, OpenLedger::apply(app(), accum, *closed_,
txs, retries, applyFlags(), *router, txs, retries, applyFlags(), *router,
config, journal); app().config(), journal);
accum.apply(*next); accum.apply(*next);
} }
// To ensure that the close time is exact and not rounded, we don't // 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( std::tie(ter_, didApply) = ripple::apply(
app(), view, *stx, applyFlags(), app(), view, *stx, applyFlags(),
directSigVerify, config, directSigVerify, app().config(),
beast::Journal{}); beast::Journal{});
return didApply; return didApply;
}); });

View File

@@ -360,7 +360,7 @@ public:
{ { "bob", 1 }, { "carol", 2 } })); { { "bob", 1 }, { "carol", 2 } }));
env(noop("alice")); 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("bob"), fee(2 * baseFee));
env(noop("alice"), msig("carol"), fee(2 * baseFee)); env(noop("alice"), msig("carol"), fee(2 * baseFee));
env(noop("alice"), msig("bob", "carol"), fee(3 * 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/balance.cpp>
#include <ripple/test/jtx/impl/delivermin.cpp> #include <ripple/test/jtx/impl/delivermin.cpp>
#include <ripple/test/jtx/impl/Env.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/fee.cpp>
#include <ripple/test/jtx/impl/flags.cpp> #include <ripple/test/jtx/impl/flags.cpp>
#include <ripple/test/jtx/impl/jtx_json.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/txflags.cpp>
#include <ripple/test/jtx/impl/utility.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>