stranded_socket tests and tidy

This commit is contained in:
Vinnie Falco
2019-02-07 20:11:21 -08:00
parent f15bbf10b4
commit b8aa6be7fd
15 changed files with 1641 additions and 555 deletions

View File

@ -2,6 +2,7 @@ Version 212:
* dynamic_buffer_ref tests and tidy
* flat_stream tests and tidy
* stranded_socket tests and tidy
--------------------------------------------------------------------------------

View File

@ -113,30 +113,4 @@ synchronous stream may check its argument:
[snippet_core_3]
[heading Stream Interfaces]
To facilitiate stream algorithms, these types provide enhanced functionality
above what is offered by networking:
[table Stream Interfaces
[[Name][Description]]
[[
[link beast.ref.boost__beast__basic_timeout_stream `basic_timeout_stream`]
[link beast.ref.boost__beast__timeout_stream `timeout_stream`]
][
Objects of this type are designed to act as a replacement for the
traditional networking socket. They
]]
[[
[link beast.ref.boost__beast__flat_stream `flat_stream`]
][
This stream wrapper improves performance by working around a limitation
of networking's `ssl::stream` to improve performance.
]]
]
[endsect]

View File

@ -110,7 +110,7 @@ facilities for authoring and working with layered streams:
a work-around for a performance limitation in the original SSL stream.
]]
[[
[link beast.ref.boost__beast__stranded_stream `stranded_stream`]
[link beast.ref.boost__beast__stranded_socket `stranded_socket`]
][
A timeout stream meets the requirements for synchronous and asynchronous
read and write streams by passing I/O through to an underlying
@ -131,4 +131,3 @@ streams:
[code_core_3_layers_5]
[endsect]

View File

@ -46,7 +46,7 @@
<member><link linkend="beast.ref.boost__beast__span">span</link></member>
<member><link linkend="beast.ref.boost__beast__static_string">static_string</link></member>
<member><link linkend="beast.ref.boost__beast__stable_async_op_base">stable_async_op_base</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__stranded_stream">stranded_stream</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__stranded_socket">stranded_socket</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__string_param">string_param</link></member>
<member><link linkend="beast.ref.boost__beast__string_view">string_view</link></member>
<member><link linkend="beast.ref.boost__beast__timeout_stream">timeout_stream</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
@ -69,6 +69,7 @@
<member><link linkend="beast.ref.boost__beast__bind_handler">bind_handler</link></member>
<member><link linkend="beast.ref.boost__beast__buffer_size">buffer_size</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__close_socket">close_socket</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__connect">connect</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__generic_category">generic_category</link></member>
<member><link linkend="beast.ref.boost__beast__get_lowest_layer">get_lowest_layer</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__iequals">iequals</link></member>

View File

@ -39,6 +39,9 @@
<xsl:when test="type = 'class EndpointSequence'">
<xsl:text>class __EndpointSequence__</xsl:text>
</xsl:when>
<xsl:when test="type = 'class ExecutionContext'">
<xsl:text>class __ExecutionContext__</xsl:text>
</xsl:when>
<xsl:when test="type = 'class Executor'">
<xsl:text>class __Executor__</xsl:text>
</xsl:when>

View File

@ -41,7 +41,7 @@
#include <boost/beast/core/span.hpp>
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/static_string.hpp>
#include <boost/beast/core/stranded_stream.hpp>
#include <boost/beast/core/stranded_socket.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/string_param.hpp>

View File

@ -682,6 +682,7 @@ async_connect(
indicate success. The @c next parameter is the next endpoint to be tried.
The function object should return true if the next endpoint should be tried,
and false if it should be skipped.
@param handler The handler to be called when the connect operation
completes. Ownership of the handler may be transferred. The function
signature of the handler must be:
@ -701,7 +702,7 @@ async_connect(
not, the handler will not be invoked from within this function. Invocation
of the handler will be performed in a manner equivalent to using
`net::io_context::post()`.
@par Example
The following connect condition function object can be used to output
information about the individual connection attempts:

View File

@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_DETAIL_STRANDED_STREAM_HPP
#define BOOST_BEAST_CORE_DETAIL_STRANDED_STREAM_HPP
#ifndef BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
#define BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
#include <boost/beast/core/detail/bind_default_executor.hpp>
#include <boost/asio/basic_stream_socket.hpp>
@ -19,20 +19,20 @@ namespace beast {
namespace detail {
template<class Protocol>
class stranded_stream_base
class stranded_socket_base
{
protected:
net::basic_stream_socket<Protocol> socket_;
template<class... Args>
explicit
stranded_stream_base(Args&&... args)
stranded_socket_base(Args&&... args)
: socket_(std::forward<Args>(args)...)
{
}
stranded_stream_base(stranded_stream_base&&) = default;
stranded_stream_base& operator=(stranded_stream_base&&) = default;
stranded_socket_base(stranded_socket_base&&) = default;
stranded_socket_base& operator=(stranded_socket_base&&) = delete;
};
} // detail

File diff suppressed because it is too large Load Diff

View File

@ -1,433 +0,0 @@
//
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_CORE_STRANDED_STREAM_HPP
#define BOOST_BEAST_CORE_STRANDED_STREAM_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/stranded_stream.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/executor.hpp>
#include <boost/core/empty_value.hpp>
#include <type_traits>
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
/** A stream socket using a custom executor, defaulting to a strand
This class template is parameterized on the executor type to be
used for all asynchronous operations. This achieves partial support for
[P1322]. The default template parameter uses a strand for the next
layer's executor.
@see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0]</a>
<em>Networking TS enhancement to enable custom I/O executors</em>
*/
template<
class Protocol,
class Executor = beast::executor_type<net::basic_stream_socket<Protocol>>
>
class stranded_stream
#ifndef BOOST_BEAST_DOXYGEN
: private detail::stranded_stream_base<Protocol>
, private boost::empty_value<Executor>
#endif
{
// Restricted until P1322R0 is incorporated into Boost.Asio.
static_assert(
std::is_convertible<decltype(
std::declval<Executor const&>().context()),
net::io_context&>::value,
"Only net::io_context is currently supported for executor_type::context()");
public:
/// The type of the executor associated with the object.
using executor_type = Executor;
/// The type of the next layer.
using next_layer_type = net::basic_stream_socket<Protocol>;
/// The protocol type.
using protocol_type = Protocol;
/// The endpoint type.
using endpoint_type = typename Protocol::endpoint;
/** Construct the stream without opening it.
This constructor creates a stream. The underlying socket needs
to be opened and then connected or accepted before data can be
sent or received on it.
@param ctx An object whose type meets the requirements of
<em>ExecutionContext</em>, which the stream will use to dispatch
handlers for any asynchronous operations performed on the socket.
Currently, the only supported type for `ctx` is `net::io_context`.
@param args A list of parameters forwarded to the constructor of
the underlying socket.
@note This function does not participate in overload resolution unless:
@li `std::is_convertible<ExecutionContext&, net::execution_context&>::value` is `true`, and
@li `std::is_constructible<executor_type, typename ExecutionContext::executor_type>::value` is `true`.
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
*/
template<
class ExecutionContext,
class... Args
#if ! BOOST_BEAST_DOXYGEN
, class = typename std::enable_if<
std::is_convertible<
ExecutionContext&,
net::execution_context&>::value &&
std::is_constructible<
executor_type,
typename ExecutionContext::executor_type>::value
>::type
#endif
>
explicit
stranded_stream(ExecutionContext& ctx, Args&&... args)
: detail::stranded_stream_base<Protocol>(
ctx, std::forward<Args>(args)...)
, boost::empty_value<Executor>(
boost::empty_init_t{}, ctx.get_executor())
{
// Restriction is necessary until Asio fully supports P1322R0
static_assert(
std::is_same<ExecutionContext, net::io_context>::value,
"Only net::io_context is currently supported for ExecutionContext");
}
/** Construct the stream without opening it.
This constructor creates a stream. The underlying socket needs
to be opened and then connected or accepted before data can be
sent or received on it.
@param ex The executor which stream will use to dispatch handlers for
any asynchronous operations performed on the underlying socket.
Currently, only executors that return a `net::io_context&` from
`ex.context()` are supported.
@param args A list of parameters forwarded to the constructor of
the underlying socket.
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
*/
template<class... Args>
explicit
stranded_stream(executor_type const& ex, Args&&... args)
: detail::stranded_stream_base<Protocol>(
ex.context(), std::forward<Args>(args)...)
, boost::empty_value<Executor>(
boost::empty_init_t{}, ex)
{
// Restriction is necessary until Asio fully supports P1322R0
if(ex.context().get_executor() != this->socket_.get_executor())
throw std::invalid_argument(
"ctx.get_executor() != socket.get_executor()");
}
/** Move-construct a stream from another stream
This constructor moves a stream from one object to another.
The behavior of moving a stream while asynchronous operations
are outstanding is undefined.
@param other The other object from which the move will occur.
@note Following the move, the moved-from object is in a newly
constructed state.
*/
stranded_stream(stranded_stream&& other) = default;
/** Move-assign a stream from another stream
This assignment operator moves a stream socket from one object
to another.
The behavior of move assignment while asynchronous operations
are pending is undefined.
@param other The other basic_timeout_stream object from which the
move will occur.
@note Following the move, the moved-from object is a newly
constructed state.
*/
stranded_stream&
operator=(stranded_stream&& other) = default;
//--------------------------------------------------------------------------
/** Return the executor associated with the object.
@return A copy of the executor that stream will use to dispatch handlers.
*/
executor_type
get_executor() const noexcept
{
return this->get();
}
/** Get a reference to the underlying socket.
This function returns a reference to the next layer
in a stack of stream layers.
@return A reference to the next layer in the stack of
stream layers.
*/
next_layer_type&
next_layer() noexcept
{
return this->socket_;
}
/** Get a reference to the underlying socket.
This function returns a reference to the next layer in a
stack of stream layers.
@return A reference to the next layer in the stack of
stream layers.
*/
next_layer_type const&
next_layer() const noexcept
{
return this->socket_;
}
/** Start an asynchronous connect.
This function is used to asynchronously connect a socket to the
specified remote endpoint. The function call always returns immediately.
The underlying socket is automatically opened if it is not already open.
If the connect fails, and the socket was automatically opened, the socket
is not returned to the closed state.
@param ep The remote endpoint to which the underlying socket will be
connected. Copies will be made of the endpoint object as required.
@param handler The handler to be called when the operation completes.
The implementation will take ownership of the handler by move construction.
The handler must be invocable with this signature:
@code
void handler(
error_code ec // Result of operation
);
@endcode
Regardless of whether the asynchronous operation completes immediately or
not, the handler will not be invoked from within this function. Invocation
of the handler will be performed in a manner equivalent to using
`net::post()`.
*/
template<class ConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
void(error_code))
async_connect(
endpoint_type ep,
ConnectHandler&& handler);
/** Read some data from the stream.
This function is used to read data from the stream. The function call will
block until one or more bytes of data has been read successfully, or until
an error occurs.
@param buffers The buffers into which the data will be read.
@returns The number of bytes read.
@throws boost::system::system_error Thrown on failure.
@note The `read_some` operation may not read all of the requested number of
bytes. Consider using the function `net::read` if you need to ensure
that the requested amount of data is read before the blocking operation
completes.
*/
template<class MutableBufferSequence>
std::size_t
read_some(MutableBufferSequence const& buffers)
{
return this->socket_.read_some(buffers);
}
/** Read some data from the stream.
This function is used to read data from the stream. The function call will
block until one or more bytes of data has been read successfully, or until
an error occurs.
@param buffers The buffers into which the data will be read.
@param ec Set to indicate what error occurred, if any.
@returns The number of bytes read.
@note The `read_some` operation may not read all of the requested number of
bytes. Consider using the function `net::read` if you need to ensure
that the requested amount of data is read before the blocking operation
completes.
*/
template<class MutableBufferSequence>
std::size_t
read_some(
MutableBufferSequence const& buffers,
error_code& ec)
{
return this->socket_.read_some(buffers, ec);
}
/** Start an asynchronous read.
This function is used to asynchronously read data from the stream.
The function call always returns immediately.
@param buffers A range of zero or more buffers to read stream data into.
Although the buffers object may be copied as necessary, ownership of the
underlying memory blocks is retained by the caller, which must guarantee
that they remain valid until the handler is called.
@param handler The handler to be called when the operation completes.
The implementation will take ownership of the handler by move construction.
The handler must be invocable with this signature:
@code
void handler(
error_code error, // Result of operation.
std::size_t bytes_transferred // Number of bytes read.
);
@endcode
Regardless of whether the asynchronous operation completes immediately or
not, the handler will not be invoked from within this function. Invocation
of the handler will be performed in a manner equivalent to using
`net::post()`.
*/
template<class MutableBufferSequence, class ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
void(error_code, std::size_t))
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
BOOST_BEAST_HANDLER_INIT(ReadHandler,
void(error_code, std::size_t));
this->socket_.async_read_some(
buffers,
detail::bind_default_executor(
this->get(),
std::move(init.completion_handler)));
return init.result.get();
}
/** Write some data to the stream.
This function is used to write data on the stream. The function call will
block until one or more bytes of data has been written successfully, or
until an error occurs.
@param buffers The data to be written.
@returns The number of bytes written.
@throws boost::system::system_error Thrown on failure.
@note The `write_some` operation may not transmit all of the data to the
peer. Consider using the function `net::write` if you need to
ensure that all data is written before the blocking operation completes.
*/
template<class ConstBufferSequence>
std::size_t
write_some(ConstBufferSequence const& buffers)
{
return this->socket_.write_some(buffers);
}
/** Write some data to the stream.
This function is used to write data on the stream. The function call will
block until one or more bytes of data has been written successfully, or
until an error occurs.
@param buffers The data to be written.
@param ec Set to indicate what error occurred, if any.
@returns The number of bytes written.
@note The `write_some` operation may not transmit all of the data to the
peer. Consider using the function `net::write` if you need to
ensure that all data is written before the blocking operation completes.
*/
template<class ConstBufferSequence>
std::size_t
write_some(
ConstBufferSequence const& buffers,
error_code& ec)
{
return this->socket_.write_some(buffers, ec);
}
/** Start an asynchronous write.
This function is used to asynchronously write data to the stream.
The function call always returns immediately.
@param buffers A range of zero or more buffers to be written to the stream.
Although the buffers object may be copied as necessary, ownership of the
underlying memory blocks is retained by the caller, which must guarantee
that they remain valid until the handler is called.
@param handler The handler to be called when the operation completes.
The implementation will take ownership of the handler by move construction.
The handler must be invocable with this signature:
@code
void handler(
error_code error, // Result of operation.
std::size_t bytes_transferred // Number of bytes written.
);
@endcode
Regardless of whether the asynchronous operation completes immediately or
not, the handler will not be invoked from within this function. Invocation
of the handler will be performed in a manner equivalent to using
`net::post()`.
*/
template<class ConstBufferSequence, class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
void(error_code, std::size_t))
async_write_some(
ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
BOOST_BEAST_HANDLER_INIT(WriteHandler,
void(error_code, std::size_t));
this->socket_.async_write_some(
buffers,
detail::bind_default_executor(
this->get(),
std::move(init.completion_handler)));
return init.result.get();
}
};
} // beast
} // boost
#endif

View File

@ -61,7 +61,7 @@ add_executable (tests-beast-core
span.cpp
static_buffer.cpp
static_string.cpp
stranded_stream.cpp
stranded_socket.cpp
stream_traits.cpp
string.cpp
string_param.cpp

View File

@ -49,7 +49,7 @@ local SOURCES =
span.cpp
static_buffer.cpp
static_string.cpp
stranded_stream.cpp
stranded_socket.cpp
stream_traits.cpp
string.cpp
string_param.cpp

View File

@ -134,7 +134,7 @@ public:
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
s_.fail("unexpected post", __FILE__, __LINE__);
BEAST_FAIL();
}
template<class F, class Alloc>
@ -142,7 +142,7 @@ public:
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
s_.fail("unexpected defer", __FILE__, __LINE__);
BEAST_FAIL();
}
};

View File

@ -0,0 +1,519 @@
//
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
// Test that header file is self-contained.
#include <boost/beast/core/stranded_socket.hpp>
#include "stream_tests.hpp"
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <memory>
namespace boost {
namespace beast {
namespace {
template<class Executor = net::io_context::executor_type>
class test_executor
{
public:
// VFALCO These need to be atomic or something
struct info
{
int dispatch = 0;
int post = 0;
int defer = 0;
int work = 0;
int total = 0;
};
private:
struct state
{
Executor ex;
info info_;
state(Executor const& ex_)
: ex(ex_)
{
}
};
std::shared_ptr<state> sp_;
public:
test_executor(test_executor const&) = default;
test_executor& operator=(test_executor const&) = default;
explicit
test_executor(Executor const& ex)
: sp_(std::make_shared<state>(ex))
{
}
decltype(sp_->ex.context())
context() const noexcept
{
return sp_->ex.context();
}
info&
operator*() noexcept
{
return sp_->info_;
}
info*
operator->() noexcept
{
return &sp_->info_;
}
void
on_work_started() const noexcept
{
++sp_->info_.work;
}
void
on_work_finished() const noexcept
{
}
template<class F, class A>
void
dispatch(F&& f, A const& a)
{
++sp_->info_.dispatch;
++sp_->info_.total;
sp_->ex.dispatch(
std::forward<F>(f), a);
}
template<class F, class A>
void
post(F&& f, A const& a)
{
++sp_->info_.post;
++sp_->info_.total;
sp_->ex.post(
std::forward<F>(f), a);
}
template<class F, class A>
void
defer(F&& f, A const& a)
{
++sp_->info_.defer;
++sp_->info_.total;
sp_->ex.defer(
std::forward<F>(f), a);
}
};
struct test_handler
{
int& flags;
void
operator()()
{
flags |= 1;
}
template<class F>
friend
void
asio_handler_invoke(F&& f, test_handler* p)
{
p->flags |= 2;
std::move(f)();
}
};
struct test_acceptor
{
net::io_context ioc;
net::ip::tcp::acceptor a;
net::ip::tcp::endpoint ep;
test_acceptor()
: a(ioc)
, ep(net::ip::make_address_v4("127.0.0.1"), 0)
{
a.open(ep.protocol());
a.set_option(
net::socket_base::reuse_address(true));
a.bind(ep);
a.listen(1);
ep = a.local_endpoint();
a.async_accept(
[](error_code, net::ip::tcp::socket)
{
});
}
};
} // (anon)
//------------------------------------------------------------------------------
class stranded_socket_test
: public beast::unit_test::suite
{
public:
using tcp = net::ip::tcp;
using strand = net::io_context::strand;
using executor = net::io_context::executor_type;
void
testStream()
{
net::io_context ioc;
// default Executor
{
stranded_socket<tcp> s1{strand(ioc)};
stranded_socket<tcp> s2{strand{ioc}};
//stranded_socket<tcp> s3{strand{ioc}}; // ambiguous parse
}
// explicit Executor
{
auto ex = ioc.get_executor();
stranded_socket<tcp, executor> s1(ioc);
stranded_socket<tcp, executor> s2(ex);
stranded_socket<tcp, executor> s3(ioc, tcp::v4());
stranded_socket<tcp, executor> s4(std::move(s1));
s2.socket() = tcp::socket(ioc);
BEAST_EXPECT(s1.get_executor() == ex);
BEAST_EXPECT(s2.get_executor() == ex);
BEAST_EXPECT(s3.get_executor() == ex);
BEAST_EXPECT(s4.get_executor() == ex);
BEAST_EXPECT((! static_cast<
stranded_socket<tcp, executor> const&>(
s2).socket().is_open()));
}
{
auto ex = strand{ioc};
stranded_socket<tcp, strand> s1(ex);
stranded_socket<tcp, strand> s2(ex, tcp::v4());
stranded_socket<tcp, strand> s3(std::move(s1));
s2.socket() = tcp::socket(ioc);
BEAST_EXPECT(s1.get_executor() == ex);
BEAST_EXPECT(s2.get_executor() == ex);
BEAST_EXPECT(s3.get_executor() == ex);
BEAST_EXPECT((! static_cast<
stranded_socket<tcp, strand> const&>(
s2).socket().is_open()));
}
{
test_sync_stream<stranded_socket<tcp, executor>>();
test_async_stream<stranded_socket<tcp, executor>>();
test_sync_stream<stranded_socket<tcp, strand>>();
test_async_stream<stranded_socket<tcp, strand>>();
}
}
void
testMembers()
{
net::io_context ioc;
// connect (member)
auto const cond =
[](error_code, tcp::endpoint)
{
return true;
};
{
stranded_socket<tcp, executor> s(ioc);
error_code ec;
test_acceptor a;
try
{
s.connect(a.ep);
BEAST_PASS();
}
catch(std::exception const&)
{
BEAST_FAIL();
}
}
{
stranded_socket<tcp, executor> s(ioc);
error_code ec;
test_acceptor a;
s.connect(a.ep, ec);
BEAST_EXPECT(! ec);
}
// connect
{
test_acceptor a;
std::array<tcp::endpoint, 1> epa;
epa[0] = a.ep;
stranded_socket<tcp, executor> s(ioc);
error_code ec;
connect(s, epa);
connect(s, epa, ec);
}
{
test_acceptor a;
std::array<tcp::endpoint, 1> epa;
epa[0] = a.ep;
stranded_socket<tcp, executor> s(ioc);
error_code ec;
connect(s, epa, cond);
connect(s, epa, cond, ec);
}
{
test_acceptor a;
std::array<tcp::endpoint, 1> epa;
epa[0] = a.ep;
stranded_socket<tcp, executor> s(ioc);
error_code ec;
connect(s, epa.begin(), epa.end());
connect(s, epa.begin(), epa.end(), ec);
}
{
test_acceptor a;
std::array<tcp::endpoint, 1> epa;
epa[0] = a.ep;
stranded_socket<tcp, executor> s(ioc);
error_code ec;
connect(s, epa.begin(), epa.end(), cond);
connect(s, epa.begin(), epa.end(), cond, ec);
}
// async_connect
{
stranded_socket<tcp, executor> s(ioc);
test_acceptor a;
error_code ec;
s.async_connect(a. ep,
[](error_code ec)
{
BEAST_EXPECT(! ec);
});
ioc.run();
ioc.restart();
}
{
std::array<tcp::endpoint, 1> epa;
epa[0] = tcp::endpoint(
net::ip::make_address_v4("127.0.0.1"), 0);
stranded_socket<tcp, executor> s(ioc);
async_connect(s, epa,
[](error_code, tcp::endpoint)
{
});
}
{
std::array<tcp::endpoint, 1> epa;
epa[0] = tcp::endpoint(
net::ip::make_address_v4("127.0.0.1"), 0);
stranded_socket<tcp, executor> s(ioc);
async_connect(s, epa, cond,
[](error_code, tcp::endpoint)
{
});
}
{
std::array<tcp::endpoint, 1> epa;
epa[0] = tcp::endpoint(
net::ip::make_address_v4("127.0.0.1"), 0);
using iter_type = decltype(epa)::const_iterator;
stranded_socket<tcp, executor> s(ioc);
async_connect(s, epa.begin(), epa.end(),
[](error_code, iter_type)
{
});
}
{
std::array<tcp::endpoint, 1> epa;
epa[0] = tcp::endpoint(
net::ip::make_address_v4("127.0.0.1"), 0);
using iter_type = decltype(epa)::const_iterator;
stranded_socket<tcp, executor> s(ioc);
async_connect(s, epa.begin(), epa.end(), cond,
[](error_code, iter_type)
{
});
}
// read/write
{
error_code ec;
stranded_socket<tcp, executor> s(ioc, tcp::v4());
BEAST_EXPECT(s.read_some(net::mutable_buffer{}) == 0);
BEAST_EXPECT(s.read_some(net::mutable_buffer{}, ec) == 0);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(s.write_some(net::const_buffer{}) == 0);
BEAST_EXPECT(s.write_some(net::const_buffer{}, ec) == 0);
BEAST_EXPECTS(! ec, ec.message());
bool invoked;
invoked = false;
s.async_read_some(net::mutable_buffer{},
[&](error_code ec, std::size_t)
{
invoked = true;
BEAST_EXPECTS(! ec, ec.message());
});
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked);
invoked = false;
s.async_write_some(net::const_buffer{},
[&](error_code ec, std::size_t)
{
invoked = true;
BEAST_EXPECTS(! ec, ec.message());
});
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked);
}
// stranded
{
error_code ec;
stranded_socket<tcp, strand> s(strand(ioc), tcp::v4());
bool invoked;
invoked = false;
s.async_read_some(net::mutable_buffer{},
[&](error_code ec, std::size_t)
{
invoked = true;
BEAST_EXPECTS(! ec, ec.message());
});
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked);
invoked = false;
s.async_write_some(net::const_buffer{},
[&](error_code ec, std::size_t)
{
invoked = true;
BEAST_EXPECTS(! ec, ec.message());
});
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked);
}
// test_executor
{
error_code ec;
stranded_socket<tcp, test_executor<>> s(
test_executor<>(ioc.get_executor()), tcp::v4());
bool invoked;
invoked = false;
s.async_read_some(net::mutable_buffer{},
[&](error_code ec, std::size_t)
{
invoked = true;
BEAST_EXPECTS(! ec, ec.message());
});
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked);
BEAST_EXPECT(s.get_executor()->total > 0);
s.get_executor()->total = 0;
invoked = false;
s.async_write_some(net::const_buffer{},
[&](error_code ec, std::size_t)
{
invoked = true;
BEAST_EXPECTS(! ec, ec.message());
});
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked);
BEAST_EXPECT(s.get_executor()->total > 0);
s.get_executor()->total = 0;
}
// bind_default_executor::asio_handler_invoke
#if 0
// VFALCO This test fails, because it is unclear how
// asio_handler_invoke interacts with the wrapper.
// Need to ask Chris Kohlhoff about this one.
{
int flags = 0;
net::post(
ioc,
detail::bind_default_executor(
strand(ioc),
test_handler{flags}));
ioc.run();
ioc.restart();
BEAST_EXPECT(flags == 3);
}
#endif
}
//--------------------------------------------------------------------------
void
testJavadocs()
{
}
//--------------------------------------------------------------------------
void
run()
{
testStream();
testJavadocs();
testMembers();
}
};
BEAST_DEFINE_TESTSUITE(beast,core,stranded_socket);
} // beast
} // boost

View File

@ -1,81 +0,0 @@
//
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
// Test that header file is self-contained.
#include <boost/beast/core/stranded_stream.hpp>
#include "stream_tests.hpp"
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace boost {
namespace beast {
class stranded_stream_test
: public beast::unit_test::suite
{
public:
using tcp = net::ip::tcp;
void
testStream()
{
net::io_context ioc;
{
using ex_t = net::io_context::executor_type;
auto ex = ioc.get_executor();
stranded_stream<tcp, ex_t> s1(ioc);
stranded_stream<tcp, ex_t> s2(ex);
stranded_stream<tcp, ex_t> s3(ioc, tcp::v4());
stranded_stream<tcp, ex_t> s4(std::move(s1));
s2.next_layer() = tcp::socket(ioc);
BEAST_EXPECT(s1.get_executor() == ex);
BEAST_EXPECT(s2.get_executor() == ex);
BEAST_EXPECT(s3.get_executor() == ex);
BEAST_EXPECT(s4.get_executor() == ex);
}
{
using ex_t = net::io_context::strand;
auto ex = ex_t{ioc};
stranded_stream<tcp, ex_t> s1(ex);
stranded_stream<tcp, ex_t> s2(ex, tcp::v4());
stranded_stream<tcp, ex_t> s3(std::move(s1));
s2.next_layer() = tcp::socket(ioc);
BEAST_EXPECT(s1.get_executor() == ex);
BEAST_EXPECT(s2.get_executor() == ex);
BEAST_EXPECT(s3.get_executor() == ex);
}
{
using ex_t = net::io_context::executor_type;
test_sync_stream<stranded_stream<tcp, ex_t>>();
test_async_stream<stranded_stream<tcp, ex_t>>();
}
}
void
testJavadocs()
{
}
//--------------------------------------------------------------------------
void
run()
{
testStream();
testJavadocs();
pass();
}
};
BEAST_DEFINE_TESTSUITE(beast,core,stranded_stream);
} // beast
} // boost