mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
adds pong timer support and new full stack automated integration testing for it
This commit is contained in:
@@ -198,7 +198,7 @@ Export('polyfill_libs')
|
||||
|
||||
if not env['PLATFORM'].startswith('win'):
|
||||
# Unit tests, add test folders with SConscript files to to_test list.
|
||||
to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection'] #,'http','processors','connection'
|
||||
to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection','transport'] #,'http','processors','connection'
|
||||
|
||||
for t in to_test:
|
||||
new_tests = SConscript('#/test/'+t+'/SConscript',variant_dir = testdir + t, duplicate = 0)
|
||||
|
||||
24
test/transport/SConscript
Normal file
24
test/transport/SConscript
Normal file
@@ -0,0 +1,24 @@
|
||||
## transport integration tests
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','regex','random'],env) + [platform_libs] + [tls_libs]
|
||||
|
||||
objs = env.Object('boost_integration.o', ["integration.cpp"], LIBS = BOOST_LIBS)
|
||||
prgs = env.Program('test_boost_integration', ["boost_integration.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
objs += env_cpp11.Object('stl_integration.o', ["integration.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_stl_integration', ["stl_integration.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
Return('prgs')
|
||||
131
test/transport/integration.cpp
Normal file
131
test/transport/integration.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the WebSocket++ Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE transport_integration
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <websocketpp/common/thread.hpp>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
void run_server(server * s, int port) {
|
||||
try {
|
||||
s->clear_access_channels(websocketpp::log::alevel::all);
|
||||
s->clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
s->init_asio();
|
||||
|
||||
s->listen(port);
|
||||
s->start_accept();
|
||||
s->run();
|
||||
} catch (std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (boost::system::error_code & ec) {
|
||||
std::cout << ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void run_client(client & c, std::string uri) {
|
||||
c.clear_access_channels(websocketpp::log::alevel::all);
|
||||
c.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
c.init_asio();
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = c.get_connection(uri,ec);
|
||||
BOOST_CHECK( !ec );
|
||||
c.connect(con);
|
||||
|
||||
c.run();
|
||||
}
|
||||
|
||||
bool on_ping(websocketpp::connection_hdl, std::string payload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void cancel_on_open(server * s, websocketpp::connection_hdl hdl) {
|
||||
s->cancel();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) {
|
||||
typename T::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
con->ping(payload);
|
||||
}
|
||||
|
||||
void fail_on_pong(websocketpp::connection_hdl hdl, std::string payload) {
|
||||
BOOST_FAIL( "expected no pong" );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void req_pong_timeout(T * c, std::string expected_payload,
|
||||
websocketpp::connection_hdl hdl, std::string payload)
|
||||
{
|
||||
typename T::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
BOOST_CHECK_EQUAL( payload, expected_payload );
|
||||
con->close(websocketpp::close::status::normal,"");
|
||||
}
|
||||
|
||||
// Wait for the specified time period then fail the test
|
||||
void run_test_timer(long value) {
|
||||
/*boost::asio::io_service ios;
|
||||
boost::asio::deadline_timer t(ios,boost::posix_time::milliseconds(value));
|
||||
boost::system::error_code ec;
|
||||
t.wait(ec);*/
|
||||
sleep(value);
|
||||
BOOST_FAIL( "Test timed out" );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( pong_timeout ) {
|
||||
server s;
|
||||
client c;
|
||||
|
||||
s.set_ping_handler(on_ping);
|
||||
s.set_open_handler(bind(&cancel_on_open,&s,::_1));
|
||||
|
||||
c.set_pong_handler(bind(&fail_on_pong,::_1,::_2));
|
||||
c.set_open_handler(bind(&ping_on_open<client>,&c,"foo",::_1));
|
||||
c.set_pong_timeout_handler(bind(&req_pong_timeout<client>,&c,"foo",::_1,::_2));
|
||||
|
||||
websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005));
|
||||
websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6));
|
||||
sthread.detach();
|
||||
tthread.detach();
|
||||
|
||||
run_client(c, "http://localhost:9005");
|
||||
}
|
||||
|
||||
@@ -163,7 +163,10 @@ public:
|
||||
|
||||
// Message handler (needs to know message type)
|
||||
typedef lib::function<void(connection_hdl,message_ptr)> message_handler;
|
||||
|
||||
|
||||
/// Type of a pointer to a transport timer handle
|
||||
typedef typename transport_con_type::timer_ptr timer_ptr;
|
||||
|
||||
// Misc Convenience Types
|
||||
typedef session::internal_state::value istate_type;
|
||||
|
||||
@@ -263,11 +266,18 @@ public:
|
||||
* If the transport component being used supports timers, the pong timeout
|
||||
* handler is called whenever a pong control frame is not received with the
|
||||
* configured timeout period after the application sends a ping.
|
||||
*
|
||||
*
|
||||
* The config setting `timeout_pong` controls the length of the timeout
|
||||
* period. It is specified in milliseconds.
|
||||
*
|
||||
* This can be used to probe the health of the remote endpoint's WebSocket
|
||||
* implimentation. This does not guarantee that the remote application
|
||||
* itself is still healthy but can be a useful diagnostic.
|
||||
*
|
||||
* Note: receipt of this callback doesn't mean the pong will never come.
|
||||
* This functionality will not suppress delivery of the pong in question
|
||||
* should it arrive after the timeout.
|
||||
*
|
||||
* @param h The new pong_timeout_handler
|
||||
*/
|
||||
void set_pong_timeout_handler(pong_timeout_handler h) {
|
||||
@@ -428,7 +438,13 @@ public:
|
||||
* @param payload Payload to be used for the ping
|
||||
*/
|
||||
void ping(const std::string& payload);
|
||||
|
||||
|
||||
/// exception free variant of ping
|
||||
void ping(const std::string & payload, lib::error_code & ec);
|
||||
|
||||
/// Utility method that gets called back when the ping timer expires
|
||||
void handle_pong_timeout(std::string payload, const lib::error_code & ec);
|
||||
|
||||
/// Send a pong
|
||||
/**
|
||||
* Initiates a pong with the given payload.
|
||||
@@ -1027,6 +1043,7 @@ private:
|
||||
size_t m_buf_cursor;
|
||||
termination_handler m_termination_handler;
|
||||
con_msg_manager_ptr m_msg_manager;
|
||||
timer_ptr m_ping_timer;
|
||||
|
||||
// TODO: this is not memory efficient. this value is not used after the
|
||||
// handshake.
|
||||
|
||||
@@ -139,21 +139,45 @@ lib::error_code connection<config>::send(typename config::message_type::ptr msg)
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::ping(const std::string& payload) {
|
||||
void connection<config>::ping(const std::string& payload, lib::error_code& ec) {
|
||||
m_alog.write(log::alevel::devel,"connection ping");
|
||||
|
||||
if (m_state != session::state::open) {
|
||||
throw error::make_error_code(error::invalid_state);
|
||||
ec = error::make_error_code(error::invalid_state);
|
||||
return;
|
||||
}
|
||||
|
||||
message_ptr msg = m_msg_manager->get_message();
|
||||
if (!msg) {
|
||||
throw error::make_error_code(error::no_outgoing_buffers);
|
||||
ec = error::make_error_code(error::no_outgoing_buffers);
|
||||
return;
|
||||
}
|
||||
|
||||
lib::error_code ec = m_processor->prepare_ping(payload,msg);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
ec = m_processor->prepare_ping(payload,msg);
|
||||
if (ec) {return;}
|
||||
|
||||
// set ping timer if we are listening for one
|
||||
if (m_pong_timeout_handler) {
|
||||
// Cancel any existing timers
|
||||
if (m_ping_timer) {
|
||||
m_ping_timer->cancel();
|
||||
}
|
||||
|
||||
m_ping_timer = transport_con_type::set_timer(
|
||||
config::timeout_pong,
|
||||
lib::bind(
|
||||
&type::handle_pong_timeout,
|
||||
type::shared_from_this(),
|
||||
payload,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
if (!m_ping_timer) {
|
||||
// Our transport doesn't support timers
|
||||
m_elog.write(log::elevel::warn,"Warning: a pong_timeout_handler is \
|
||||
set but the transport in use does not support timeouts.");
|
||||
}
|
||||
}
|
||||
|
||||
bool needs_writing = false;
|
||||
@@ -169,6 +193,36 @@ void connection<config>::ping(const std::string& payload) {
|
||||
type::shared_from_this()
|
||||
));
|
||||
}
|
||||
|
||||
ec = lib::error_code();
|
||||
}
|
||||
|
||||
template<typename config>
|
||||
void connection<config>::ping(const std::string& payload) {
|
||||
lib::error_code ec;
|
||||
ping(payload,ec);
|
||||
if (ec) {
|
||||
throw ec;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename config>
|
||||
void connection<config>::handle_pong_timeout(std::string payload, const lib::error_code &
|
||||
ec)
|
||||
{
|
||||
if (ec) {
|
||||
if (ec == transport::error::operation_aborted) {
|
||||
// ignore, this is expected
|
||||
return;
|
||||
}
|
||||
|
||||
m_elog.write(log::elevel::devel,"pong_timeout error: "+ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pong_timeout_handler) {
|
||||
m_pong_timeout_handler(m_connection_hdl,payload);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
@@ -187,9 +241,7 @@ void connection<config>::pong(const std::string& payload, lib::error_code& ec) {
|
||||
}
|
||||
|
||||
ec = m_processor->prepare_pong(payload,msg);
|
||||
if (ec) {
|
||||
return;
|
||||
}
|
||||
if (ec) {return;}
|
||||
|
||||
bool needs_writing = false;
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user