mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
New TestOverlay generic peer to peer network tests
This commit is contained in:
@@ -778,6 +778,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\ripple_core\ripple_core.cpp" />
|
||||
<ClCompile Include="..\..\modules\ripple_core\test\TestOverlay.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\ripple_core\validator\ValidatorSourceStrings.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -1501,6 +1507,16 @@
|
||||
<ClInclude Include="..\..\modules\ripple_core\node\NodeStore.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\node\NullBackendFactory.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\ripple_core.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\ConnectionType.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\InitPolicy.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\MessageType.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\NetworkType.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\PeerLogicBase.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\ConfigType.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\PeerType.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\Results.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\SimplePayload.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\StateBase.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorSourceStrings.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorSourceTrustedUri.h" />
|
||||
<ClInclude Include="..\..\modules\ripple_core\validator\Validator.h" />
|
||||
|
||||
@@ -151,6 +151,9 @@
|
||||
<Filter Include="[1] Ripple\ripple_app\node">
|
||||
<UniqueIdentifier>{1d9bc26d-d76e-4fd4-a737-b968e31e614b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="[1] Ripple\ripple_core\test">
|
||||
<UniqueIdentifier>{129c51dc-e885-4023-999b-e133d800fb80}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\Subtrees\beast\modules\beast_core\beast_core.cpp">
|
||||
@@ -864,6 +867,9 @@
|
||||
<ClCompile Include="..\..\modules\ripple_core\validator\Validators.cpp">
|
||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\ripple_core\test\TestOverlay.cpp">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\ripple_app\ripple_app.h">
|
||||
@@ -1685,6 +1691,36 @@
|
||||
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorsImp.h">
|
||||
<Filter>[1] Ripple\ripple_core\validator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\Results.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\SimplePayload.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\MessageType.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\ConnectionType.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\PeerType.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\NetworkType.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\StateBase.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\PeerLogicBase.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\InitPolicy.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\ripple_core\test\ConfigType.h">
|
||||
<Filter>[1] Ripple\ripple_core\test</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\modules\ripple_data\protocol\ripple.proto">
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
// For NodeStore backends
|
||||
#include "beast/modules/beast_db/beast_db.h"
|
||||
@@ -46,6 +47,18 @@ namespace ripple
|
||||
#include "node/NodeStore.cpp"
|
||||
#include "node/NodeObject.cpp"
|
||||
|
||||
# include "test/Results.h"
|
||||
# include "test/SimplePayload.h"
|
||||
# include "test/MessageType.h"
|
||||
# include "test/ConnectionType.h"
|
||||
# include "test/PeerType.h"
|
||||
# include "test/NetworkType.h"
|
||||
# include "test/StateBase.h"
|
||||
# include "test/PeerLogicBase.h"
|
||||
# include "test/InitPolicy.h"
|
||||
# include "test/ConfigType.h"
|
||||
#include "test/TestOverlay.cpp"
|
||||
|
||||
# include "validator/Validator.h"
|
||||
#include "validator/Validator.cpp"
|
||||
# include "validator/ValidatorSourceStrings.h"
|
||||
|
||||
44
modules/ripple_core/test/ConfigType.h
Normal file
44
modules/ripple_core/test/ConfigType.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_CONFIGTYPE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_CONFIGTYPE_H_INCLUDED
|
||||
|
||||
/** A simulated peer to peer network for unit tests. */
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** Combines Params with standard Config requirements for test objects. */
|
||||
template <
|
||||
class Params,
|
||||
template <class> class StateType = StateBase,
|
||||
template <class> class PeerLogicType = PeerLogicBase
|
||||
>
|
||||
class ConfigType
|
||||
{
|
||||
public:
|
||||
// These defaults can be overridden in
|
||||
// Params simply by adding declarations to it.
|
||||
|
||||
static int64 const randomSeedValue = 42;
|
||||
|
||||
typedef std::size_t SizeType;
|
||||
|
||||
typedef SimplePayload Payload;
|
||||
|
||||
typedef StateType <Params> State;
|
||||
typedef MessageType <Params> Message;
|
||||
typedef NetworkType <Params> Network;
|
||||
|
||||
typedef PeerType <Params> Peer;
|
||||
typedef PeerLogicType <Params> PeerLogic;
|
||||
|
||||
typedef NoInitPolicy InitPolicy;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
173
modules/ripple_core/test/ConnectionType.h
Normal file
173
modules/ripple_core/test/ConnectionType.h
Normal file
@@ -0,0 +1,173 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_CONNECTIONTYPE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_CONNECTIONTYPE_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** A connection between two nodes. */
|
||||
template <class Config>
|
||||
class ConnectionType : public Config
|
||||
{
|
||||
public:
|
||||
using typename Config::Peer;
|
||||
using typename Config::Message;
|
||||
|
||||
typedef std::vector <Message> Messages;
|
||||
typedef typename Config::State::UniqueID UniqueID;
|
||||
typedef boost::unordered_set <UniqueID> MessageTable;
|
||||
|
||||
/** Create the 'no connection' object. */
|
||||
ConnectionType ()
|
||||
: m_peer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionType (Peer& peer, bool inbound)
|
||||
: m_peer (&peer)
|
||||
, m_inbound (inbound)
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionType (ConnectionType const& other)
|
||||
: m_peer (other.m_peer)
|
||||
, m_inbound (other.m_inbound)
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionType& operator= (ConnectionType const& other)
|
||||
{
|
||||
m_peer = other.m_peer;
|
||||
m_inbound = other.m_inbound;
|
||||
}
|
||||
|
||||
/** Returns `true` if there is no connection. */
|
||||
bool empty () const
|
||||
{
|
||||
return m_peer == nullptr;
|
||||
}
|
||||
|
||||
/** Returns `true` if this is an inbound connection.
|
||||
If there is no connection, the return value is undefined.
|
||||
*/
|
||||
bool inbound () const
|
||||
{
|
||||
return m_inbound;
|
||||
}
|
||||
|
||||
/** Returns the peer on the other end.
|
||||
If there is no connection, the return value is undefined.
|
||||
*/
|
||||
/** @{ */
|
||||
Peer& peer ()
|
||||
{
|
||||
return *m_peer;
|
||||
}
|
||||
|
||||
Peer const& peer () const
|
||||
{
|
||||
return *m_peer;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Returns a container with the current step's incoming messages. */
|
||||
/** @{ */
|
||||
Messages& messages ()
|
||||
{
|
||||
return m_messages;
|
||||
}
|
||||
|
||||
Messages const& messages () const
|
||||
{
|
||||
return m_messages;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Returns a container with the next step's incoming messages.
|
||||
During each step, peers process the current step's message
|
||||
list, but post new messages to the pending messages list.
|
||||
This way, new messages will always process in the next step
|
||||
and not the current one.
|
||||
*/
|
||||
/** @{ */
|
||||
Messages& pending ()
|
||||
{
|
||||
return m_pending;
|
||||
}
|
||||
|
||||
Messages const& pending () const
|
||||
{
|
||||
return m_pending;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** A UnaryPredicate that always returns true. */
|
||||
class Any
|
||||
{
|
||||
public:
|
||||
bool operator() (ConnectionType const&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** A UnaryPredicate that returns `true` if the peer matches. */
|
||||
class IsPeer
|
||||
{
|
||||
public:
|
||||
explicit IsPeer (Peer const& peer)
|
||||
: m_peer (&peer)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator() (ConnectionType const& connection) const
|
||||
{
|
||||
return &connection.peer () == m_peer;
|
||||
}
|
||||
|
||||
private:
|
||||
Peer const* m_peer;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** A UnaryPredicate that returns `true` if the peer does not match. */
|
||||
class IsNotPeer
|
||||
{
|
||||
public:
|
||||
explicit IsNotPeer (Peer const& peer)
|
||||
: m_peer (&peer)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator() (ConnectionType const& connection) const
|
||||
{
|
||||
return &connection.peer () != m_peer;
|
||||
}
|
||||
|
||||
private:
|
||||
Peer const* m_peer;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
Peer* m_peer;
|
||||
bool m_inbound;
|
||||
Messages m_messages;
|
||||
Messages m_pending;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
72
modules/ripple_core/test/InitPolicy.h
Normal file
72
modules/ripple_core/test/InitPolicy.h
Normal file
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_INITPOLICY_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_INITPOLICY_H_INCLUDED
|
||||
|
||||
/** A simulated peer to peer network for unit tests. */
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// InitPolicy
|
||||
//
|
||||
// This is called during construction to form the network.
|
||||
//
|
||||
|
||||
/** InitPolicy which does nothing. */
|
||||
class NoInitPolicy
|
||||
{
|
||||
public:
|
||||
template <class Network>
|
||||
void operator() (Network& network)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Init policy for a pre-built connected network. */
|
||||
template <int NumberOfPeers,
|
||||
int OutgoingConnectionsPerPeer>
|
||||
class PremadeInitPolicy
|
||||
{
|
||||
public:
|
||||
static int const numberOfPeers = NumberOfPeers;
|
||||
static int const outgoingConnectionsPerPeer = OutgoingConnectionsPerPeer;
|
||||
|
||||
template <class Network>
|
||||
void operator() (Network& network)
|
||||
{
|
||||
typedef typename Network::Peer Peer;
|
||||
typedef typename Network::Peers Peers;
|
||||
typedef typename Network::Config Config;
|
||||
typedef typename Config::SizeType SizeType;
|
||||
|
||||
for (SizeType i = 0; i < numberOfPeers; ++i)
|
||||
network.createPeer ();
|
||||
|
||||
Peers& peers (network.peers ());
|
||||
for (SizeType i = 0; i < numberOfPeers; ++i)
|
||||
{
|
||||
Peer& peer (*peers [i]);
|
||||
for (SizeType j = 0; j < outgoingConnectionsPerPeer; ++j)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
SizeType k (network.state ().random ().nextInt (numberOfPeers));
|
||||
if (peer.connect_to (*peers [k]))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
62
modules/ripple_core/test/MessageType.h
Normal file
62
modules/ripple_core/test/MessageType.h
Normal file
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_MESSAGETYPE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_MESSAGETYPE_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** A message sent between peers. */
|
||||
template <class Config>
|
||||
class MessageType : public Config
|
||||
{
|
||||
public:
|
||||
typedef typename Config::State::UniqueID UniqueID;
|
||||
using typename Config::Payload;
|
||||
|
||||
MessageType ()
|
||||
: m_id (0)
|
||||
{
|
||||
}
|
||||
|
||||
MessageType (UniqueID id, Payload payload)
|
||||
: m_id (id)
|
||||
, m_payload (payload)
|
||||
{
|
||||
}
|
||||
|
||||
MessageType (MessageType const& other)
|
||||
: m_id (other.m_id)
|
||||
, m_payload (other.m_payload)
|
||||
{
|
||||
}
|
||||
|
||||
MessageType& operator= (MessageType const& other)
|
||||
{
|
||||
m_id = other.m_id;
|
||||
m_payload = other.m_payload;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UniqueID id () const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
Payload payload () const
|
||||
{
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
private:
|
||||
UniqueID m_id;
|
||||
Payload m_payload;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
130
modules/ripple_core/test/NetworkType.h
Normal file
130
modules/ripple_core/test/NetworkType.h
Normal file
@@ -0,0 +1,130 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_NETWORKTYPE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_NETWORKTYPE_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
template <class ConfigParam>
|
||||
class NetworkType : public ConfigParam
|
||||
{
|
||||
public:
|
||||
typedef ConfigParam Config;
|
||||
|
||||
using typename Config::SizeType;
|
||||
using typename Config::State;
|
||||
using typename Config::Peer;
|
||||
|
||||
typedef std::vector <ScopedPointer <Peer> > Peers;
|
||||
|
||||
NetworkType ()
|
||||
: m_steps (0)
|
||||
{
|
||||
typename Config::InitPolicy () (*this);
|
||||
}
|
||||
|
||||
/** Return the number of steps taken in the simulation. */
|
||||
SizeType steps () const
|
||||
{
|
||||
return m_steps;
|
||||
}
|
||||
|
||||
/** Return the size of the network measured in peers. */
|
||||
SizeType size () const
|
||||
{
|
||||
return m_peers.size ();
|
||||
}
|
||||
|
||||
/** Retrieve the state information associated with the Config. */
|
||||
State& state ()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
/** Create new Peer. */
|
||||
Peer& createPeer ()
|
||||
{
|
||||
Peer* peer (new Peer (*this));
|
||||
m_peers.push_back (peer);
|
||||
return *peer;
|
||||
}
|
||||
|
||||
/** Retrieve the container holding the set of peers. */
|
||||
Peers& peers ()
|
||||
{
|
||||
return m_peers;
|
||||
}
|
||||
|
||||
/** Run the network for 1 iteration. */
|
||||
Results step ()
|
||||
{
|
||||
Results results;
|
||||
for (typename Peers::iterator iter = m_peers.begin ();
|
||||
iter!= m_peers.end (); ++iter)
|
||||
(*iter)->pre_step ();
|
||||
for (typename Peers::iterator iter = m_peers.begin ();
|
||||
iter!= m_peers.end (); ++iter)
|
||||
(*iter)->step ();
|
||||
++results.steps;
|
||||
++m_steps;
|
||||
for (typename Peers::iterator iter = m_peers.begin ();
|
||||
iter!= m_peers.end (); ++iter)
|
||||
{
|
||||
Peer& peer (**iter);
|
||||
peer.post_step ();
|
||||
results = results + peer.results();
|
||||
peer.results() = Results();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/** Run the network until a condition is met.
|
||||
Requirements:
|
||||
p (*this) is well-formed and returns bool.
|
||||
*/
|
||||
template <class Predicate>
|
||||
Results step_until (Predicate p)
|
||||
{
|
||||
Results results;
|
||||
while (! p (*this))
|
||||
results += step ();
|
||||
return results;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** A UnaryPredicate that returns true after # steps have passed. */
|
||||
class Steps
|
||||
{
|
||||
public:
|
||||
explicit Steps (SizeType steps)
|
||||
: m_steps (steps)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator() (NetworkType const&)
|
||||
{
|
||||
if (m_steps == 0)
|
||||
return true;
|
||||
--m_steps;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
SizeType m_steps;
|
||||
};
|
||||
|
||||
private:
|
||||
State m_state;
|
||||
SizeType m_steps;
|
||||
Peers m_peers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
69
modules/ripple_core/test/PeerLogicBase.h
Normal file
69
modules/ripple_core/test/PeerLogicBase.h
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_PEERLOGICBASE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_PEERLOGICBASE_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** Base class for all PeerLogic implementations.
|
||||
This provides stubs for all necessary functions, although
|
||||
they don't actually do anything.
|
||||
*/
|
||||
template <class Config>
|
||||
class PeerLogicBase : public Config
|
||||
{
|
||||
public:
|
||||
typedef typename Config::Peer Peer;
|
||||
typedef typename Peer::Connection Connection;
|
||||
typedef typename Connection::Message Message;
|
||||
|
||||
explicit PeerLogicBase (Peer& peer)
|
||||
: m_peer (peer)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return the Peer associated with this logic. */
|
||||
/** @{ */
|
||||
Peer& peer ()
|
||||
{
|
||||
return m_peer;
|
||||
}
|
||||
|
||||
Peer const& peer () const
|
||||
{
|
||||
return m_peer;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
// Called to process a message
|
||||
void receive (Connection const& c, Message const& m)
|
||||
{
|
||||
}
|
||||
|
||||
// Called before taking a step
|
||||
void pre_step ()
|
||||
{
|
||||
}
|
||||
|
||||
// Called during a step
|
||||
void step ()
|
||||
{
|
||||
}
|
||||
|
||||
// Called after a step is taken
|
||||
void post_step ()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Peer& m_peer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
283
modules/ripple_core/test/PeerType.h
Normal file
283
modules/ripple_core/test/PeerType.h
Normal file
@@ -0,0 +1,283 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_PEERTYPE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_PEERTYPE_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** A peer in the overlay network. */
|
||||
template <class Config>
|
||||
class PeerType
|
||||
: public Config
|
||||
, public Uncopyable
|
||||
{
|
||||
public:
|
||||
using typename Config::Peer;
|
||||
using typename Config::Payload;
|
||||
using typename Config::PeerLogic;
|
||||
using typename Config::Message;
|
||||
using typename Config::Network;
|
||||
typedef typename Config::State::UniqueID UniqueID;
|
||||
typedef ConnectionType <Config> Connection;
|
||||
typedef std::vector <Connection> Connections;
|
||||
typedef boost::unordered_set <UniqueID> MessageTable;
|
||||
|
||||
explicit PeerType (Network& network)
|
||||
: m_network (network)
|
||||
, m_id (network.state().nextPeerID())
|
||||
, m_logic (*this)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return the pending Results data associated with this peer. */
|
||||
/** @{ */
|
||||
Results& results ()
|
||||
{
|
||||
return m_results;
|
||||
}
|
||||
|
||||
Results const& results () const
|
||||
{
|
||||
return m_results;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Return the unique ID associated with this peer. */
|
||||
UniqueID id () const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/** Return the network this peer belongs to. */
|
||||
/** @{ */
|
||||
Network& network ()
|
||||
{
|
||||
return m_network;
|
||||
}
|
||||
|
||||
Network const& network () const
|
||||
{
|
||||
return m_network;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Return the container holding active connections. */
|
||||
/** @{ */
|
||||
Connections& connections ()
|
||||
{
|
||||
return m_connections;
|
||||
}
|
||||
|
||||
Connections const& connections () const
|
||||
{
|
||||
return m_connections;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Return the container holding the message ids seen by this peer. */
|
||||
/** @{ */
|
||||
MessageTable& msg_table ()
|
||||
{
|
||||
return m_msg_table;
|
||||
}
|
||||
|
||||
MessageTable const& msg_table () const
|
||||
{
|
||||
return m_msg_table;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Establish an outgoing connection to peer.
|
||||
@return `true` if the peer is not us and not connected already.
|
||||
*/
|
||||
bool connect_to (Peer& peer)
|
||||
{
|
||||
if (&peer == this)
|
||||
return false;
|
||||
typename Connections::iterator const iter (std::find_if (
|
||||
connections().begin(), connections().end (),
|
||||
typename Connection::IsPeer (peer)));
|
||||
if (iter != connections().end())
|
||||
return false;
|
||||
check_postcondition (std::find_if (peer.connections().begin(),
|
||||
peer.connections().end(),
|
||||
typename Connection::IsPeer (*this))
|
||||
== peer.connections().end ());
|
||||
connections().push_back (Connection (peer, false));
|
||||
peer.connections().push_back (Connection (*this, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Disconnect from a peer.
|
||||
@return `true` if the peer was found and disconnected.
|
||||
*/
|
||||
bool disconnect (Peer& peer)
|
||||
{
|
||||
if (&peer == this)
|
||||
return false;
|
||||
typename Connections::iterator const iter1 (std::find_if (
|
||||
connections().begin(), connections().end (),
|
||||
typename Connection::IsPeer (peer)));
|
||||
if (iter1 == connections().end())
|
||||
return false;
|
||||
typename Connections::iterator const iter2 (std::find_if (
|
||||
peer.connections().begin(), peer.connections().end (),
|
||||
typename Connection::IsPeer (*this)));
|
||||
check_postcondition (iter2 != peer.connections().end());
|
||||
connections().erase (iter1);
|
||||
peer.connections().erase (iter2);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Send a new message to a specific connection.
|
||||
A new message with an unused id is created with the given payload.
|
||||
*/
|
||||
void send (Peer& peer, Payload const& payload)
|
||||
{
|
||||
Message const m (network().state().nextMessageID(), payload);
|
||||
check_postcondition (msg_table().insert (m.id()).second);
|
||||
check_postcondition (send_to (peer,
|
||||
Message (network().state().nextMessageID(),
|
||||
payload)));
|
||||
}
|
||||
|
||||
/** Send a message to a specific connection.
|
||||
The message already has an id and associated payload.
|
||||
*/
|
||||
bool send (Peer& peer, Message const& m)
|
||||
{
|
||||
return send_to (peer, m);
|
||||
}
|
||||
|
||||
/** Send a new message to all connections.
|
||||
A new message with an unused id is created with the given payload.
|
||||
*/
|
||||
void send_all (Payload const& payload)
|
||||
{
|
||||
Message const m (network().state().nextMessageID(), payload);
|
||||
check_postcondition (msg_table().insert (m.id()).second);
|
||||
check_postcondition (send_all_if (m,
|
||||
typename Connection::Any ()));
|
||||
};
|
||||
|
||||
/** Send a message to all connections.
|
||||
The message already has an id and associated payload.
|
||||
*/
|
||||
bool send_all (Message const& m)
|
||||
{
|
||||
return send_all_if (m,
|
||||
typename Connection::Any ());
|
||||
};
|
||||
|
||||
/** Create a new message and send it to each connection that passes the predicate.
|
||||
Predicate is a UnaryPredicate that takes a Connection parameter.
|
||||
A new message with an unused id is created with the given payload.
|
||||
*/
|
||||
template <class Predicate>
|
||||
void send_all_if (Payload const& payload, Predicate p)
|
||||
{
|
||||
Message const m (network().state().nextMessageID(), payload);
|
||||
check_postcondition (msg_table().insert (m.id()).second);
|
||||
check_postcondition (send_all_if (m, p));
|
||||
}
|
||||
|
||||
/** Send an existing message to all connections that pass the predicate.
|
||||
@return `true` if at least one message was sent.
|
||||
*/
|
||||
template <class Predicate>
|
||||
bool send_all_if (Message const& m, Predicate p)
|
||||
{
|
||||
bool sent = false;
|
||||
for (typename Connections::iterator iter (connections().begin());
|
||||
iter != connections().end(); ++iter)
|
||||
if (p (*iter))
|
||||
sent = send_to (iter->peer(), m) || sent;
|
||||
return sent;
|
||||
}
|
||||
|
||||
private:
|
||||
// Low level send function, everything goes through this.
|
||||
// Returns true if the message was sent.
|
||||
//
|
||||
bool send_to (Peer& peer, Message const& m)
|
||||
{
|
||||
// already seen it?
|
||||
if (peer.msg_table().count(m.id()) != 0)
|
||||
{
|
||||
++results().dropped;
|
||||
return false;
|
||||
}
|
||||
typename Connections::iterator const iter (std::find_if (
|
||||
peer.connections().begin(), peer.connections().end (),
|
||||
typename Connection::IsPeer (*this)));
|
||||
check_postcondition (iter != peer.connections().end());
|
||||
check_postcondition (peer.msg_table().insert(m.id()).second);
|
||||
iter->pending().push_back (m);
|
||||
++results().sent;
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Called once on each Peer object before every iteration. */
|
||||
void pre_step ()
|
||||
{
|
||||
m_logic.pre_step ();
|
||||
}
|
||||
|
||||
/** Called once on each Peer object during every iteration. */
|
||||
void step ()
|
||||
{
|
||||
// Call logic with current messages
|
||||
for (typename Connections::iterator iter (connections().begin());
|
||||
iter != connections().end(); ++iter)
|
||||
{
|
||||
Connection& c (*iter);
|
||||
for (typename Connection::Messages::iterator iter (
|
||||
c.messages().begin()); iter != c.messages().end(); ++iter)
|
||||
{
|
||||
Message const& m (*iter);
|
||||
check_precondition (msg_table().count (m.id()) == 1);
|
||||
m_logic.receive (c, m);
|
||||
++results().received;
|
||||
}
|
||||
}
|
||||
|
||||
m_logic.step ();
|
||||
}
|
||||
|
||||
/** Called once on each Peer object after every iteration. */
|
||||
void post_step ()
|
||||
{
|
||||
// Move pending messages to current messages
|
||||
for (typename Connections::iterator iter (connections().begin());
|
||||
iter != connections().end(); ++iter)
|
||||
{
|
||||
Connection& c (*iter);
|
||||
c.messages().clear ();
|
||||
c.messages().swap (c.pending());
|
||||
}
|
||||
|
||||
m_logic.post_step ();
|
||||
}
|
||||
|
||||
private:
|
||||
Results m_results;
|
||||
Network& m_network;
|
||||
UniqueID const m_id;
|
||||
Connections m_connections;
|
||||
MessageTable m_msg_table;
|
||||
PeerLogic m_logic; // must come last
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
78
modules/ripple_core/test/Results.h
Normal file
78
modules/ripple_core/test/Results.h
Normal file
@@ -0,0 +1,78 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_RESULTS_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_RESULTS_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** Accumulates statistics on one or more simulation steps. */
|
||||
struct Results
|
||||
{
|
||||
Results ()
|
||||
: steps (0)
|
||||
, sent (0)
|
||||
, received (0)
|
||||
, dropped (0)
|
||||
{
|
||||
}
|
||||
|
||||
Results (Results const& other)
|
||||
: steps (other.steps)
|
||||
, sent (other.sent)
|
||||
, received (other.received)
|
||||
, dropped (other.dropped)
|
||||
{
|
||||
}
|
||||
|
||||
Results& operator= (Results const& other)
|
||||
{
|
||||
steps = other.steps;
|
||||
sent = other.sent;
|
||||
received = other.received;
|
||||
dropped = other.dropped;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String toString () const
|
||||
{
|
||||
String s;
|
||||
s = "steps(" + String::fromNumber (steps) + ")"
|
||||
+ ", sent(" + String::fromNumber (sent) + ")"
|
||||
+ ", received(" + String::fromNumber (received) + ")"
|
||||
+ ", dropped(" + String::fromNumber (dropped) + ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
Results& operator+= (Results const& other)
|
||||
{
|
||||
steps += other.steps;
|
||||
sent += other.sent;
|
||||
received += other.received;
|
||||
dropped += other.dropped;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Results operator+ (Results const& other)
|
||||
{
|
||||
Results results;
|
||||
results.steps = steps + other.steps;
|
||||
results.sent = sent + other.sent;
|
||||
results.received = received + other.received;
|
||||
results.dropped = dropped + other.dropped;
|
||||
return results;
|
||||
}
|
||||
|
||||
int steps;
|
||||
int sent;
|
||||
int received;
|
||||
int dropped;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
71
modules/ripple_core/test/SimplePayload.h
Normal file
71
modules/ripple_core/test/SimplePayload.h
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_SIMPLEPAYLOAD_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_SIMPLEPAYLOAD_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/** A simple message payload. */
|
||||
class SimplePayload
|
||||
{
|
||||
public:
|
||||
SimplePayload ()
|
||||
{
|
||||
}
|
||||
|
||||
SimplePayload (int what, String data = String::empty, int hops = 0)
|
||||
: m_hops (hops)
|
||||
, m_what (what)
|
||||
, m_data (data)
|
||||
{
|
||||
}
|
||||
|
||||
SimplePayload (SimplePayload const& other)
|
||||
: m_hops (other.m_hops)
|
||||
, m_what (other.m_what)
|
||||
, m_data (other.m_data)
|
||||
{
|
||||
}
|
||||
|
||||
SimplePayload& operator= (SimplePayload const& other)
|
||||
{
|
||||
m_hops = other.m_hops;
|
||||
m_what = other.m_what;
|
||||
m_data = other.m_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SimplePayload withHop () const
|
||||
{
|
||||
return SimplePayload (m_what, m_data, m_hops + 1);
|
||||
}
|
||||
|
||||
int hops () const
|
||||
{
|
||||
return m_hops;
|
||||
}
|
||||
|
||||
int what () const
|
||||
{
|
||||
return m_what;
|
||||
}
|
||||
|
||||
String data () const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_hops;
|
||||
int m_what;
|
||||
String m_data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
53
modules/ripple_core/test/StateBase.h
Normal file
53
modules/ripple_core/test/StateBase.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_TEST_STATEBASE_H_INCLUDED
|
||||
#define RIPPLE_CORE_TEST_STATEBASE_H_INCLUDED
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
/* Base class for state information used by test objects. */
|
||||
template <class Params>
|
||||
class StateBase
|
||||
{
|
||||
public:
|
||||
// Identifies messages and peers.
|
||||
// Always starts at 1 and increases incrementally.
|
||||
//
|
||||
typedef uint64 UniqueID;
|
||||
|
||||
StateBase ()
|
||||
: m_random (Params::randomSeedValue)
|
||||
, m_peerID (0)
|
||||
, m_messageID (0)
|
||||
{
|
||||
}
|
||||
|
||||
Random& random ()
|
||||
{
|
||||
return m_random;
|
||||
}
|
||||
|
||||
UniqueID nextPeerID ()
|
||||
{
|
||||
return ++m_peerID;
|
||||
}
|
||||
|
||||
UniqueID nextMessageID ()
|
||||
{
|
||||
return ++m_messageID;
|
||||
}
|
||||
|
||||
private:
|
||||
Random m_random;
|
||||
UniqueID m_peerID;
|
||||
UniqueID m_messageID;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
133
modules/ripple_core/test/TestOverlay.cpp
Normal file
133
modules/ripple_core/test/TestOverlay.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace TestOverlay
|
||||
{
|
||||
|
||||
class Tests : public UnitTest
|
||||
{
|
||||
public:
|
||||
template <class Config>
|
||||
class SeenState : public StateBase <Config>
|
||||
{
|
||||
public:
|
||||
SeenState ()
|
||||
: m_seen (0)
|
||||
{
|
||||
}
|
||||
|
||||
void increment ()
|
||||
{
|
||||
++m_seen;
|
||||
}
|
||||
|
||||
int seen () const
|
||||
{
|
||||
return m_seen;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_seen;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Config>
|
||||
class PeerLogic : public PeerLogicBase <Config>
|
||||
{
|
||||
public:
|
||||
typedef PeerLogicBase <Config> Base;
|
||||
typedef typename Config::Payload Payload;
|
||||
typedef typename Base::Connection Connection;
|
||||
typedef typename Base::Peer Peer;
|
||||
typedef typename Base::Message Message;
|
||||
typedef typename Config::SizeType SizeType;
|
||||
|
||||
explicit PeerLogic (Peer& peer)
|
||||
: PeerLogicBase <Config> (peer)
|
||||
{
|
||||
}
|
||||
|
||||
~PeerLogic ()
|
||||
{
|
||||
}
|
||||
|
||||
void step ()
|
||||
{
|
||||
if (this->peer().id () == 1)
|
||||
{
|
||||
if (this->peer().network().steps() == 0)
|
||||
{
|
||||
this->peer().network().state().increment();
|
||||
this->peer().send_all (Payload (1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void receive (Connection const& c, Message const& m)
|
||||
{
|
||||
if (this->peer().id () != 1)
|
||||
{
|
||||
this->peer().network().state().increment();
|
||||
this->peer().send_all_if (Message (m.id(),
|
||||
m.payload().withHop ()),
|
||||
typename Connection::IsNotPeer (c.peer()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
struct Params : ConfigType <
|
||||
Params,
|
||||
SeenState,
|
||||
PeerLogic
|
||||
>
|
||||
{
|
||||
typedef PremadeInitPolicy <250, 3> InitPolicy;
|
||||
};
|
||||
|
||||
typedef Params::Network Network;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void testCreation ()
|
||||
{
|
||||
beginTestCase ("create");
|
||||
|
||||
Network network;
|
||||
|
||||
Results result;
|
||||
for (int i = 0; result.received < 249 && i < 100; ++i)
|
||||
{
|
||||
String s =
|
||||
String ("step #") + String::fromNumber (
|
||||
network.steps()) + " ";
|
||||
result += network.step ();
|
||||
s << result.toString ();
|
||||
logMessage (s);
|
||||
}
|
||||
|
||||
int const seen (network.state().seen());
|
||||
|
||||
String s = "Seen = " + String::fromNumber (seen);
|
||||
logMessage (s);
|
||||
pass ();
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
testCreation ();
|
||||
}
|
||||
|
||||
Tests () : UnitTest ("TestOverlay", "ripple", runManual)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static Tests tests;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user