TestPeer boost::asio Socket and UnitTest framework

This commit is contained in:
Vinnie Falco
2013-08-09 19:39:16 -07:00
parent 98352429c2
commit 88ffd3cdfb
31 changed files with 2487 additions and 271 deletions

View File

@@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_TESTPEERDETAILSTCP_H_INCLUDED
#define BEAST_TESTPEERDETAILSTCP_H_INCLUDED
/** Some predefined Detail classes for TestPeer
*/
struct TcpDetails : public TestPeerDetails
{
protected:
typedef boost::asio::ip::tcp protocol_type;
typedef protocol_type::socket socket_type;
typedef protocol_type::acceptor acceptor_type;
typedef protocol_type::endpoint endpoint_type;
typedef protocol_type::resolver resolver_type;
struct NoArg { }; // dummy
public:
typedef protocol_type arg_type;
typedef socket_type native_socket_type;
typedef acceptor_type native_acceptor_type;
explicit TcpDetails (arg_type protocol)
: m_protocol (protocol)
, m_socket (get_io_service ())
, m_acceptor (get_io_service ())
, m_socket_wrapper (m_socket)
, m_acceptor_wrapper (m_acceptor)
{
}
static String getArgName (arg_type arg)
{
if (arg == protocol_type::v4 ())
return "tcpv4";
else if (arg == protocol_type::v6 ())
return "tcpv6";
return "tcp?";
}
String name ()
{
return getArgName (m_protocol);
}
Socket& get_socket ()
{
return m_socket_wrapper;
}
Socket& get_acceptor ()
{
return m_acceptor_wrapper;
}
socket_type& get_native_socket ()
{
return m_socket;
}
acceptor_type& get_native_acceptor ()
{
return m_acceptor;
}
endpoint_type get_endpoint (TestPeer::Role role)
{
if (m_protocol == protocol_type::v4 ())
{
if (role == TestPeer::Role::server)
return endpoint_type (m_protocol, 1053);
else
return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053);
}
else
{
if (role == TestPeer::Role::server)
return endpoint_type (m_protocol, 1052);
else
return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
}
}
protected:
protocol_type m_protocol;
socket_type m_socket;
acceptor_type m_acceptor;
SocketWrapper <socket_type> m_socket_wrapper;
SocketWrapper <acceptor_type> m_acceptor_wrapper;
};
#endif

View File

@@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
TestPeerLogicAsyncClient::TestPeerLogicAsyncClient (Socket& socket)
: TestPeerLogic (socket)
{
}
TestPeerBasics::Role TestPeerLogicAsyncClient::get_role () const noexcept
{
return Role::client;
}
TestPeerBasics::Model TestPeerLogicAsyncClient::get_model () const noexcept
{
return Model::async;
}
void TestPeerLogicAsyncClient::on_connect_async (error_code const& ec)
{
if (failure (error (ec)))
return;
if (socket ().requires_handshake ())
{
socket ().async_handshake (Socket::client,
boost::bind (&TestPeerLogicAsyncClient::on_handshake, this,
boost::asio::placeholders::error));
}
else
{
on_handshake (ec);
}
}
void TestPeerLogicAsyncClient::on_handshake (error_code const& ec)
{
if (failure (error (ec)))
return;
boost::asio::async_write (socket (), boost::asio::buffer ("hello", 5),
boost::bind (&TestPeerLogicAsyncClient::on_write, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_write (error_code const& ec, std::size_t bytes_transferred)
{
if (failure (error (ec)))
return;
if (unexpected (bytes_transferred == 5, error ()))
return;
boost::asio::async_read_until (socket (), m_buf, std::string ("goodbye"),
boost::bind (&TestPeerLogicAsyncClient::on_read, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_read (error_code const& ec, std::size_t bytes_transferred)
{
if (failure (error (ec)))
return;
if (unexpected (bytes_transferred == 7, error ()))
return;
// should check the data here?
m_buf.consume (bytes_transferred);
boost::asio::async_read (socket (), m_buf.prepare (1),
boost::bind (&TestPeerLogicAsyncClient::on_read_final, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_read_final (error_code const& ec, std::size_t)
{
if (ec == boost::asio::error::eof)
{
if (failure (socket ().shutdown (Socket::shutdown_both, error ())))
return;
if (failure (socket ().close (error ())))
return;
}
else
{
// If we don't get eof, then there should be some other
// error in there. We don't expect the server to send more bytes!
//
unexpected (success (error (ec)), error ());
}
}

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
#define BEAST_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
class TestPeerLogicAsyncClient : public TestPeerLogic
{
public:
explicit TestPeerLogicAsyncClient (Socket& socket);
Role get_role () const noexcept;
Model get_model () const noexcept;
void on_connect_async (error_code const& ec);
void on_handshake (error_code const& ec);
void on_write (error_code const& ec, std::size_t bytes_transferred);
void on_read (error_code const& ec, std::size_t bytes_transferred);
void on_read_final (error_code const& ec, std::size_t);
private:
boost::asio::streambuf m_buf;
};
#endif

View File

@@ -0,0 +1,104 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
TestPeerLogicAsyncServer::TestPeerLogicAsyncServer (Socket& socket)
: TestPeerLogic (socket)
{
}
TestPeerBasics::Role TestPeerLogicAsyncServer::get_role () const noexcept
{
return Role::server;
}
TestPeerBasics::Model TestPeerLogicAsyncServer::get_model () const noexcept
{
return Model::async;
}
void TestPeerLogicAsyncServer::on_connect_async (error_code const& ec)
{
if (failure (error (ec)))
return;
if (socket ().requires_handshake ())
{
socket ().async_handshake (Socket::server,
boost::bind (&TestPeerLogicAsyncServer::on_handshake, this,
boost::asio::placeholders::error));
}
else
{
on_handshake (ec);
}
}
void TestPeerLogicAsyncServer::on_handshake (error_code const& ec)
{
if (failure (error (ec)))
return;
boost::asio::async_read_until (socket (), m_buf, std::string ("hello"),
boost::bind (&TestPeerLogicAsyncServer::on_read, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncServer::on_read (error_code const& ec, std::size_t bytes_transferred)
{
if (failure (error (ec)))
return;
if (unexpected (bytes_transferred == 5, error ()))
return;
boost::asio::async_write (socket (), boost::asio::buffer ("goodbye", 7),
boost::bind (&TestPeerLogicAsyncServer::on_write, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncServer::on_write (error_code const& ec, std::size_t bytes_transferred)
{
if (failure (error (ec)))
return;
if (unexpected (bytes_transferred == 7, error ()))
return;
if (socket ().requires_handshake ())
{
socket ().async_shutdown (boost::bind (&TestPeerLogicAsyncServer::on_shutdown, this,
boost::asio::placeholders::error));
}
else
{
// we need another instance of ec so we can call on_shutdown()
error_code ec;
on_shutdown (socket ().shutdown (Socket::shutdown_both, ec));
}
}
void TestPeerLogicAsyncServer::on_shutdown (error_code const& ec)
{
if (failure (error (ec), true))
return;
if (failure (socket ().close (error ())))
return;
}

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_TESTPEERLOGICASYNCSERVER_H_INCLUDED
#define BEAST_TESTPEERLOGICASYNCSERVER_H_INCLUDED
class TestPeerLogicAsyncServer : public TestPeerLogic
{
public:
explicit TestPeerLogicAsyncServer (Socket& socket);
Role get_role () const noexcept;
Model get_model () const noexcept;
void on_connect_async (error_code const& ec);
void on_handshake (error_code const& ec);
void on_read (error_code const& ec, std::size_t bytes_transferred);
void on_write (error_code const& ec, std::size_t bytes_transferred);
void on_shutdown (error_code const& ec);
private:
boost::asio::streambuf m_buf;
};
#endif

View File

@@ -0,0 +1,97 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
TestPeerLogicSyncClient::TestPeerLogicSyncClient (Socket& socket)
: TestPeerLogic (socket)
{
}
TestPeerBasics::Role TestPeerLogicSyncClient::get_role () const noexcept
{
return Role::client;
}
TestPeerBasics::Model TestPeerLogicSyncClient::get_model () const noexcept
{
return Model::sync;
}
void TestPeerLogicSyncClient::on_connect ()
{
if (socket ().requires_handshake ())
{
if (failure (socket ().handshake (get_role (), error ())))
return;
}
{
std::size_t const amount = boost::asio::write (
socket (), boost::asio::buffer ("hello", 5), error ());
if (failure (error ()))
return;
if (unexpected (amount == 5, error ()))
return;
}
{
char data [7];
size_t const amount = boost::asio::read (
socket (), boost::asio::buffer (data, 7), error ());
if (failure (error ()))
return;
if (unexpected (amount == 7, error ()))
return;
if (unexpected (memcmp (&data, "goodbye", 7) == 0, error ()))
return;
}
// Wait for 1 byte which should never come. Instead,
// the server should close its end and we will get eof
{
char data [1];
boost::asio::read (socket (), boost::asio::buffer (data, 1), error ());
if (error () == boost::asio::error::eof)
{
error () = error_code ();
}
else if (unexpected (failure (error ()), error ()))
{
return;
}
}
if (socket ().requires_handshake ())
{
if (failure (socket ().shutdown (error ()), true))
return;
}
if (failure (socket ().shutdown (Socket::shutdown_both, error ())))
return;
if (failure (socket ().close (error ())))
return;
}

View File

@@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
#define BEAST_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
class TestPeerLogicSyncClient : public TestPeerLogic
{
public:
explicit TestPeerLogicSyncClient (Socket& socket);
Role get_role () const noexcept;
Model get_model () const noexcept;
void on_connect ();
};
#endif

View File

@@ -0,0 +1,80 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
TestPeerLogicSyncServer::TestPeerLogicSyncServer (Socket& socket)
: TestPeerLogic (socket)
{
}
TestPeerBasics::Role TestPeerLogicSyncServer::get_role () const noexcept
{
return Role::server;
}
TestPeerBasics::Model TestPeerLogicSyncServer::get_model () const noexcept
{
return Model::sync;
}
void TestPeerLogicSyncServer::on_connect ()
{
if (socket ().requires_handshake ())
{
if (failure (socket ().handshake (get_role (), error ())))
return;
}
{
boost::asio::streambuf buf (5);
std::size_t const amount = boost::asio::read_until (
socket (), buf, "hello", error ());
if (failure (error ()))
return;
if (unexpected (amount == 5, error ()))
return;
if (unexpected (buf.size () == 5, error ()))
return;
}
{
std::size_t const amount = boost::asio::write (
socket (), boost::asio::buffer ("goodbye", 7), error ());
if (failure (error ()))
return;
if (unexpected (amount == 7, error ()))
return;
}
if (socket ().requires_handshake ())
{
if (failure (socket ().shutdown (error ()), true))
return;
}
if (failure (socket ().shutdown (Socket::shutdown_both, error ())))
return;
if (failure (socket ().close (error ())))
return;
}

View File

@@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_TESTPEERLOGICSYNCSERVER_H_INCLUDED
#define BEAST_TESTPEERLOGICSYNCSERVER_H_INCLUDED
class TestPeerLogicSyncServer : public TestPeerLogic
{
public:
explicit TestPeerLogicSyncServer (Socket& socket);
Role get_role () const noexcept;
Model get_model () const noexcept;
void on_connect ();
};
#endif

View File

@@ -0,0 +1,119 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_TESTPEERTESTTYPE_H_INCLUDED
#define RIPPLE_TESTPEERTESTTYPE_H_INCLUDED
/** Performs a test of two peers defined by template parameters.
*/
class TestPeerTestType : public TestPeerTest
{
public:
/** Test two peers and return the results.
*/
template <typename Details, typename ServerLogic, typename ClientLogic, class Arg>
static Results run (Arg const& arg, int timeoutSeconds = defaultTimeoutSeconds)
{
Results results;
results.name = Details::getArgName (arg);
try
{
TestPeerType <ServerLogic, Details> server (arg);
results.name << " / " << server.name ();
try
{
TestPeerType <ClientLogic, Details> client (arg);
results.name << " / " << client.name ();
try
{
server.start ();
try
{
client.start ();
boost::system::error_code const ec =
client.join (timeoutSeconds);
results.client = Result (ec, client.name ());
try
{
boost::system::error_code const ec =
server.join (timeoutSeconds);
results.server = Result (ec, server.name ());
}
catch (...)
{
results.server = Result (make_error (
errc::exceptioned), server.name ());
}
}
catch (...)
{
results.client = Result (make_error (
errc::exceptioned), client.name ());
}
}
catch (...)
{
results.server = Result (make_error (
errc::exceptioned), server.name ());
}
}
catch (...)
{
results.client = Result (make_error (
errc::exceptioned), "client");
}
}
catch (...)
{
results.server = Result (make_error (
errc::exceptioned), "server");
}
return results;
}
//--------------------------------------------------------------------------
/** Reports tests of Details against all known logic combinations to a UnitTest.
*/
template <typename Details, class Arg>
static void test (UnitTest& test, Arg const& arg,
int timeoutSeconds = defaultTimeoutSeconds,
bool beginTestCase = true)
{
run <Details, TestPeerLogicSyncServer, TestPeerLogicSyncClient> (arg, timeoutSeconds).report (test, beginTestCase);
run <Details, TestPeerLogicSyncServer, TestPeerLogicAsyncClient> (arg, timeoutSeconds).report (test, beginTestCase);
run <Details, TestPeerLogicAsyncServer, TestPeerLogicSyncClient> (arg, timeoutSeconds).report (test, beginTestCase);
run <Details, TestPeerLogicAsyncServer, TestPeerLogicAsyncClient> (arg, timeoutSeconds).report (test, beginTestCase);
}
};
#endif

View File

@@ -0,0 +1,176 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 BEAST_TESTPEERTYPE_H_INCLUDED
#define BEAST_TESTPEERTYPE_H_INCLUDED
template <typename Logic, typename DetailsType>
class TestPeerType
: public DetailsType
, public Logic
, public TestPeer
, public Thread
{
public:
typedef typename DetailsType::arg_type arg_type;
typedef TestPeerType <Logic, DetailsType> ThisType;
TestPeerType (arg_type const& arg)
: DetailsType (arg)
, Logic (get_socket ())
, Thread (name ())
{
}
~TestPeerType ()
{
}
String name () const
{
return get_model ().name () + "_" + get_role ().name ();
}
void start ()
{
startThread ();
}
boost::system::error_code join (int timeoutSeconds)
{
if (! wait (timeoutSeconds * 1000))
{
stopThread (0);
return error (make_error (errc::timeout));
}
return error ();
}
//--------------------------------------------------------------------------
void run ()
{
if (get_model () == Model::async)
{
if (get_role () == Role::server)
{
run_async_server ();
}
else if (get_role () == Role::client)
{
run_async_client ();
}
else
{
error () = make_error (errc::unexpected);
}
}
else if (get_model () == Model::sync)
{
if (get_role () == Role::server)
{
run_sync_server ();
}
else if (get_role () == Role::client)
{
run_sync_client ();
}
else
{
error () = make_error (errc::unexpected);
}
}
else
{
error () = make_error (errc::unexpected);
}
get_io_service ().run ();
notify ();
}
//--------------------------------------------------------------------------
void run_sync_server ()
{
do_listen ();
if (failure (error ()))
return;
if (failure (get_acceptor ().accept (get_socket (), error ())))
return;
this->on_connect ();
if (failure (error ()))
return ;
}
void run_async_server ()
{
do_listen ();
if (failure (error ()))
return;
get_acceptor ().async_accept (get_socket (), boost::bind (
&Logic::on_connect_async, this, boost::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void run_sync_client ()
{
if (failure (get_native_socket ().connect (get_endpoint (get_role ()), error ())))
return;
this->on_connect ();
if (failure (error ()))
return;
}
void run_async_client ()
{
get_native_socket ().async_connect (get_endpoint (get_role ()),
boost::bind (&Logic::on_connect_async, this, boost::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void do_listen ()
{
if (failure (get_native_acceptor ().open (get_endpoint (get_role ()).protocol (), error ())))
return;
if (failure (get_native_acceptor ().set_option (socket_type::reuse_address (true), error ())))
return;
if (failure (get_native_acceptor ().bind (get_endpoint (get_role ()), error ())))
return;
if (failure (get_native_acceptor ().listen (socket_type::max_connections, error ())))
return;
}
};
#endif