New TestOverlay generic peer to peer network tests

This commit is contained in:
Vinnie Falco
2013-09-05 01:42:26 -07:00
parent 5a06121a85
commit e26a3a1d84
14 changed files with 1233 additions and 0 deletions

View File

@@ -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" />

View File

@@ -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">

View File

@@ -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"

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}