diff options
Diffstat (limited to 'src/boost/libs/beast/test/extras')
8 files changed, 1072 insertions, 0 deletions
diff --git a/src/boost/libs/beast/test/extras/README.md b/src/boost/libs/beast/test/extras/README.md new file mode 100644 index 00000000..ea6ffce9 --- /dev/null +++ b/src/boost/libs/beast/test/extras/README.md @@ -0,0 +1,3 @@ +# Extras + +These are not part of the official public Beast interface but they are used by the tests and some third party programs. diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/doc_debug.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/doc_debug.hpp new file mode 100644 index 00000000..61c39b03 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/doc_debug.hpp @@ -0,0 +1,170 @@ +// +// Copyright (c) 2016-2019 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) +// + +#ifndef BOOST_BEAST_DOC_DEBUG_HPP +#define BOOST_BEAST_DOC_DEBUG_HPP + +namespace beast { + +#if BOOST_BEAST_DOXYGEN + +/// doc type (documentation debug helper) +using doc_type = int; + +/// doc enum (documentation debug helper) +enum doc_enum +{ + /// One (documentation debug helper) + one, + + /// Two (documentation debug helper) + two +}; + +/// doc enum class (documentation debug helper) +enum class doc_enum_class : unsigned +{ + /// one (documentation debug helper) + one, + + /// two (documentation debug helper) + two +}; + +/// doc func (documentation debug helper) +void doc_func(); + +/// doc class (documentation debug helper) +struct doc_class +{ + /// doc class member func (documentation debug helper) + void func(); +}; + +/// (documentation debug helper) +namespace nested { + +/// doc type (documentation debug helper) +using nested_doc_type = int; + +/// doc enum (documentation debug helper) +enum nested_doc_enum +{ + /// One (documentation debug helper) + one, + + /// Two (documentation debug helper) + two +}; + +/// doc enum class (documentation debug helper) +enum class nested_doc_enum_class : unsigned +{ + /// one (documentation debug helper) + one, + + /// two (documentation debug helper) + two +}; + +/// doc func (documentation debug helper) +void nested_doc_func(); + +/// doc class (documentation debug helper) +struct nested_doc_class +{ + /// doc class member func (documentation debug helper) + void func(); +}; + +} // nested + +/** This is here to help troubleshoot doc/reference.xsl problems + + Embedded references: + + @li type @ref doc_type + + @li enum @ref doc_enum + + @li enum item @ref doc_enum::one + + @li enum_class @ref doc_enum_class + + @li enum_class item @ref doc_enum_class::one + + @li func @ref doc_func + + @li class @ref doc_class + + @li class func @ref doc_class::func + + @li nested type @ref nested::nested_doc_type + + @li nested enum @ref nested::nested_doc_enum + + @li nested enum item @ref nested::nested_doc_enum::one + + @li nested enum_class @ref nested::nested_doc_enum_class + + @li nested enum_class item @ref nested::nested_doc_enum_class::one + + @li nested func @ref nested::nested_doc_func + + @li nested class @ref nested::nested_doc_class + + @li nested class func @ref nested::nested_doc_class::func +*/ +void doc_debug(); + +namespace nested { + +/** This is here to help troubleshoot doc/reference.xsl problems + + Embedded references: + + @li type @ref doc_type + + @li enum @ref doc_enum + + @li enum item @ref doc_enum::one + + @li enum_class @ref doc_enum_class + + @li enum_class item @ref doc_enum_class::one + + @li func @ref doc_func + + @li class @ref doc_class + + @li class func @ref doc_class::func + + @li nested type @ref nested_doc_type + + @li nested enum @ref nested_doc_enum + + @li nested enum item @ref nested_doc_enum::one + + @li nested enum_class @ref nested_doc_enum_class + + @li nested enum_class item @ref nested_doc_enum_class::one + + @li nested func @ref nested_doc_func + + @li nested class @ref nested_doc_class + + @li nested class func @ref nested_doc_class::func +*/ +void nested_doc_debug(); + +} // nested + +#endif + +} // beast + +#endif diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/test/fuzz.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/test/fuzz.hpp new file mode 100644 index 00000000..5491b2e2 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/test/fuzz.hpp @@ -0,0 +1,105 @@ +// +// Copyright (c) 2016-2019 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_TEST_FUZZ_HPP +#define BOOST_BEAST_TEST_FUZZ_HPP + +#include <boost/beast/core/static_string.hpp> +#include <boost/beast/core/string.hpp> +#include <random> + +namespace boost { +namespace beast { +namespace test { + +class fuzz_rand +{ + std::mt19937 rng_; + +public: + std::mt19937& + rng() + { + return rng_; + } + + template<class Unsigned> + Unsigned + operator()(Unsigned n) + { + return static_cast<Unsigned>( + std::uniform_int_distribution< + Unsigned>{0, n-1}(rng_)); + } +}; + +template<std::size_t N, class Rand, class F> +static +void +fuzz( + static_string<N> const& input, + std::size_t repeat, + std::size_t depth, + Rand& r, + F const& f) +{ + static_string<N> mod{input}; + for(auto i = repeat; i; --i) + { + switch(r(4)) + { + case 0: // insert + if(mod.size() >= mod.max_size()) + continue; + mod.insert(r(mod.size() + 1), 1, + static_cast<char>(r(256))); + break; + + case 1: // erase + if(mod.size() == 0) + continue; + mod.erase(r(mod.size()), 1); + break; + + case 2: // swap + { + if(mod.size() <= 1) + continue; + auto off = r(mod.size() - 1); + auto const temp = mod[off]; + mod[off] = mod[off + 1]; + mod[off + 1] = temp; + break; + } + case 3: // repeat + { + if(mod.empty()) + continue; + auto n = (std::min)( + std::geometric_distribution< + std::size_t>{}(r.rng()), + mod.max_size() - mod.size()); + if(n == 0) + continue; + auto off = r(mod.size()); + mod.insert(off, n, mod[off + 1]); + break; + } + } + f(string_view{mod.data(), mod.size()}); + if(depth > 0) + fuzz(mod, repeat, depth - 1, r, f); + } +} + +} // test +} // beast +} // boost + +#endif diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/test/sig_wait.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/test/sig_wait.hpp new file mode 100644 index 00000000..96c41da1 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/test/sig_wait.hpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2016-2019 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_TEST_SIG_WAIT_HPP +#define BOOST_BEAST_TEST_SIG_WAIT_HPP + +#include <boost/asio.hpp> + +namespace boost { +namespace beast { +namespace test { + +/// Block until SIGINT or SIGTERM is received. +inline +void +sig_wait() +{ + net::io_context ioc; + net::signal_set signals( + ioc, SIGINT, SIGTERM); + signals.async_wait( + [&](boost::system::error_code const&, int) + { + }); + ioc.run(); +} + +} // test +} // beast +} // boost + +#endif diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/test/test_allocator.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/test/test_allocator.hpp new file mode 100644 index 00000000..b985c539 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/test/test_allocator.hpp @@ -0,0 +1,310 @@ +// +// Copyright (c) 2016-2019 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_TEST_TEST_ALLOCATOR_HPP +#define BOOST_BEAST_TEST_TEST_ALLOCATOR_HPP + +#include <atomic> +#include <cstddef> +#include <cstdint> +#include <memory> + +namespace boost { +namespace beast { +namespace test { + +struct test_allocator_info +{ + std::size_t id; + std::size_t ncopy = 0; + std::size_t nmove = 0; + std::size_t nmassign = 0; + std::size_t ncpassign = 0; + std::size_t nselect = 0; + std::size_t max_size = ( + std::numeric_limits<std::size_t>::max)(); + + test_allocator_info() + : id([] + { + static std::atomic<std::size_t> sid(0); + return ++sid; + }()) + { + } +}; + +template< + class T, + bool Equal, + bool Assign, + bool Move, + bool Swap, + bool Select> +class test_allocator; + +template< + class T, + bool Equal, + bool Assign, + bool Move, + bool Swap, + bool Select> +struct test_allocator_base +{ +}; + +// Select == true +template< + class T, + bool Equal, + bool Assign, + bool Move, + bool Swap> +struct test_allocator_base< + T, Equal, Assign, Move, Swap, true> +{ + static + test_allocator<T, Equal, Assign, Move, Swap, true> + select_on_container_copy_construction(test_allocator< + T, Equal, Assign, Move, Swap, true> const&) + { + return test_allocator<T, + Equal, Assign, Move, Swap, true>{}; + } +}; + +template< + class T, + bool Equal, + bool Assign, + bool Move, + bool Swap, + bool Select> +class test_allocator + : public test_allocator_base< + T, Equal, Assign, Move, Swap, Select> +{ + std::shared_ptr<test_allocator_info> info_; + + template<class, bool, bool, bool, bool, bool> + friend class test_allocator; + +public: + using value_type = T; + + using propagate_on_container_copy_assignment = + std::integral_constant<bool, Assign>; + + using propagate_on_container_move_assignment = + std::integral_constant<bool, Move>; + + using propagate_on_container_swap = + std::integral_constant<bool, Swap>; + + template<class U> + struct rebind + { + using other = test_allocator<U, Equal, Assign, Move, Swap, Select>; + }; + + test_allocator() + : info_(std::make_shared< + test_allocator_info>()) + { + } + + test_allocator(test_allocator const& u) noexcept + : info_(u.info_) + { + ++info_->ncopy; + } + + template<class U> + test_allocator(test_allocator<U, + Equal, Assign, Move, Swap, Select> const& u) noexcept + : info_(u.info_) + { + ++info_->ncopy; + } + + test_allocator(test_allocator&& t) + : info_(t.info_) + { + ++info_->nmove; + } + + test_allocator& + operator=(test_allocator const& u) noexcept + { + info_ = u.info_; + ++info_->ncpassign; + return *this; + } + + test_allocator& + operator=(test_allocator&& u) noexcept + { + info_ = u.info_; + ++info_->nmassign; + return *this; + } + + value_type* + allocate(std::size_t n) + { + return static_cast<value_type*>( + ::operator new (n*sizeof(value_type))); + } + + void + deallocate(value_type* p, std::size_t) noexcept + { + ::operator delete(p); + } + + std::size_t + max_size() const + { + return info_->max_size; + } + + void + max_size(std::size_t n) + { + info_->max_size = n; + } + + bool + operator==(test_allocator const& other) const + { + return id() == other.id() || Equal; + } + + bool + operator!=(test_allocator const& other) const + { + return ! this->operator==(other); + } + + std::size_t + id() const + { + return info_->id; + } + + test_allocator_info* + operator->() const + { + return info_.get(); + } +}; + +//------------------------------------------------------------------------------ + +#if 0 +struct allocator_info +{ + std::size_t const id; + + allocator_info() + : id([] + { + static std::atomic<std::size_t> sid(0); + return ++sid; + }()) + { + } +}; + +struct allocator_defaults +{ + static std::size_t constexpr max_size = + (std::numeric_limits<std::size_t>::max)(); +}; + +template< + class T, + class Traits = allocator_defaults> +struct allocator +{ +public: + using value_type = T; + +#if 0 + template<class U> + struct rebind + { + using other = + test_allocator<U, Traits>; + }; +#endif + + allocator() = default; + allocator(allocator&& t) = default; + allocator(allocator const& u) = default; + + template< + class U, + class = typename std::enable_if< + ! std::is_same<U, T>::value>::type> + allocator( + allocator<U, Traits> const& u) noexcept + { + } + + allocator& + operator=(allocator&& u) noexcept + { + return *this; + } + + allocator& + operator=(allocator const& u) noexcept + { + return *this; + } + + value_type* + allocate(std::size_t n) + { + return static_cast<value_type*>( + ::operator new(n * sizeof(value_type))); + } + + void + deallocate(value_type* p, std::size_t) noexcept + { + ::operator delete(p); + } + + std::size_t + max_size() const + { + } + + bool + operator==(test_allocator const& other) const + { + return id() == other.id() || Equal; + } + + bool + operator!=(test_allocator const& other) const + { + return ! this->operator==(other); + } +}; +#endif + +} // test +} // beast +} // boost + +#endif diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/test/throughput.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/test/throughput.hpp new file mode 100644 index 00000000..c7eca048 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/test/throughput.hpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2016-2019 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_TEST_THROUGHPUT_HPP +#define BOOST_BEAST_TEST_THROUGHPUT_HPP + +#include <chrono> +#include <cstdint> + +namespace boost { +namespace beast { +namespace test { + +class timer +{ + using clock_type = + std::chrono::system_clock; + + clock_type::time_point when_; + +public: + using duration = + clock_type::duration; + + timer() + : when_(clock_type::now()) + { + } + + duration + elapsed() const + { + return clock_type::now() - when_; + } +}; + +inline +std::uint64_t +throughput(std::chrono::duration< + double> const& elapsed, std::uint64_t items) +{ + using namespace std::chrono; + return static_cast<std::uint64_t>( + 1 / (elapsed/items).count()); +} + +} // test +} // beast +} // boost + +#endif diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/test/websocket.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/test/websocket.hpp new file mode 100644 index 00000000..20a541b5 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/test/websocket.hpp @@ -0,0 +1,250 @@ +// +// Copyright (c) 2016-2019 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_TEST_WEBSOCKET_HPP +#define BOOST_BEAST_TEST_WEBSOCKET_HPP + +#include <boost/beast/core/multi_buffer.hpp> +#include <boost/beast/websocket/stream.hpp> +#include <boost/beast/_experimental/test/stream.hpp> +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/spawn.hpp> +#include <cstdlib> +#include <memory> +#include <ostream> +#include <thread> + +namespace boost { +namespace beast { +namespace test { + +// DEPRECATED +class ws_echo_server +{ + std::ostream& log_; + net::io_context ioc_; + net::executor_work_guard< + net::io_context::executor_type> work_; + multi_buffer buffer_; + test::stream ts_; + std::thread t_; + websocket::stream<test::stream&> ws_; + bool close_ = false; + +public: + enum class kind + { + sync, + async, + async_client + }; + + explicit + ws_echo_server( + std::ostream& log, + kind k = kind::sync) + : log_(log) + , work_(ioc_.get_executor()) + , ts_(ioc_) + , ws_(ts_) + { + beast::websocket::permessage_deflate pmd; + pmd.server_enable = true; + pmd.server_max_window_bits = 9; + pmd.compLevel = 1; + ws_.set_option(pmd); + + switch(k) + { + case kind::sync: + t_ = std::thread{[&]{ do_sync(); }}; + break; + + case kind::async: + t_ = std::thread{[&]{ ioc_.run(); }}; + do_accept(); + break; + + case kind::async_client: + t_ = std::thread{[&]{ ioc_.run(); }}; + break; + } + } + + ~ws_echo_server() + { + work_.reset(); + t_.join(); + } + + test::stream& + stream() + { + return ts_; + } + + void + async_handshake() + { + ws_.async_handshake("localhost", "/", + std::bind( + &ws_echo_server::on_handshake, + this, + std::placeholders::_1)); + } + + void + async_close() + { + net::post(ioc_, + [&] + { + if(ws_.is_open()) + { + ws_.async_close({}, + std::bind( + &ws_echo_server::on_close, + this, + std::placeholders::_1)); + } + else + { + close_ = true; + } + }); + } + +private: + void + do_sync() + { + try + { + ws_.accept(); + for(;;) + { + ws_.read(buffer_); + ws_.text(ws_.got_text()); + ws_.write(buffer_.data()); + buffer_.consume(buffer_.size()); + } + } + catch(system_error const& se) + { + boost::ignore_unused(se); +#if 0 + if( se.code() != error::closed && + se.code() != error::failed && + se.code() != net::error::eof) + log_ << "ws_echo_server: " << se.code().message() << std::endl; +#endif + } + catch(std::exception const& e) + { + log_ << "ws_echo_server: " << e.what() << std::endl; + } + } + + void + do_accept() + { + ws_.async_accept(std::bind( + &ws_echo_server::on_accept, + this, + std::placeholders::_1)); + } + + void + on_handshake(error_code ec) + { + if(ec) + return fail(ec); + + do_read(); + } + + void + on_accept(error_code ec) + { + if(ec) + return fail(ec); + + if(close_) + { + return ws_.async_close({}, + std::bind( + &ws_echo_server::on_close, + this, + std::placeholders::_1)); + } + + do_read(); + } + + void + do_read() + { + ws_.async_read(buffer_, + std::bind( + &ws_echo_server::on_read, + this, + std::placeholders::_1)); + } + + void + on_read(error_code ec) + { + if(ec) + return fail(ec); + ws_.text(ws_.got_text()); + ws_.async_write(buffer_.data(), + std::bind( + &ws_echo_server::on_write, + this, + std::placeholders::_1)); + } + + void + on_write(error_code ec) + { + if(ec) + return fail(ec); + buffer_.consume(buffer_.size()); + do_read(); + } + + void + on_close(error_code ec) + { + if(ec) + return fail(ec); + } + + void + fail(error_code ec) + { + boost::ignore_unused(ec); +#if 0 + if( ec != error::closed && + ec != error::failed && + ec != net::error::eof) + log_ << + "echo_server_async: " << + ec.message() << + std::endl; +#endif + } +}; + +} // test +} // beast +} // boost + +#endif diff --git a/src/boost/libs/beast/test/extras/include/boost/beast/test/yield_to.hpp b/src/boost/libs/beast/test/extras/include/boost/beast/test/yield_to.hpp new file mode 100644 index 00000000..e0064830 --- /dev/null +++ b/src/boost/libs/beast/test/extras/include/boost/beast/test/yield_to.hpp @@ -0,0 +1,139 @@ +// +// Copyright (c) 2016-2019 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_TEST_YIELD_TO_HPP +#define BOOST_BEAST_TEST_YIELD_TO_HPP + +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/spawn.hpp> +#include <condition_variable> +#include <functional> +#include <mutex> +#include <thread> +#include <vector> + +namespace boost { +namespace beast { +namespace test { + +/** Mix-in to support tests using asio coroutines. + + Derive from this class and use yield_to to launch test + functions inside coroutines. This is handy for testing + asynchronous asio code. +*/ +class enable_yield_to +{ +protected: + net::io_context ioc_; + +private: + net::executor_work_guard< + net::io_context::executor_type> work_; + std::vector<std::thread> threads_; + std::mutex m_; + std::condition_variable cv_; + std::size_t running_ = 0; + +public: + /// The type of yield context passed to functions. + using yield_context = + net::yield_context; + + explicit + enable_yield_to(std::size_t concurrency = 1) + : work_(ioc_.get_executor()) + { + threads_.reserve(concurrency); + while(concurrency--) + threads_.emplace_back( + [&]{ ioc_.run(); }); + } + + ~enable_yield_to() + { + work_.reset(); + for(auto& t : threads_) + t.join(); + } + + /// Return the `io_context` associated with the object + net::io_context& + get_io_service() + { + return ioc_; + } + + /** Run one or more functions, each in a coroutine. + + This call will block until all coroutines terminate. + + Each functions should have this signature: + @code + void f(yield_context); + @endcode + + @param fn... One or more functions to invoke. + */ +#if BOOST_BEAST_DOXYGEN + template<class... FN> + void + yield_to(FN&&... fn) +#else + template<class F0, class... FN> + void + yield_to(F0&& f0, FN&&... fn); +#endif + +private: + void + spawn() + { + } + + template<class F0, class... FN> + void + spawn(F0&& f, FN&&... fn); +}; + +template<class F0, class... FN> +void +enable_yield_to:: +yield_to(F0&& f0, FN&&... fn) +{ + running_ = 1 + sizeof...(FN); + spawn(f0, fn...); + std::unique_lock<std::mutex> lock{m_}; + cv_.wait(lock, [&]{ return running_ == 0; }); +} + +template<class F0, class... FN> +inline +void +enable_yield_to:: +spawn(F0&& f, FN&&... fn) +{ + asio::spawn(ioc_, + [&](yield_context yield) + { + f(yield); + std::lock_guard<std::mutex> lock{m_}; + if(--running_ == 0) + cv_.notify_all(); + } + , boost::coroutines::attributes(2 * 1024 * 1024)); + spawn(fn...); +} + +} // test +} // beast +} // boost + +#endif |