X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ceph%2Fsrc%2Fspawn%2Ftest%2Ftest_exception.cc;fp=ceph%2Fsrc%2Fspawn%2Ftest%2Ftest_exception.cc;h=5dea81badada20652cc33fcc93bd0e8595292227;hb=f67539c23b11f3b8a2ecaeeddf7a403ae1c442a8;hp=0000000000000000000000000000000000000000;hpb=64a4c04e6850c6d9086e4c37f57c4eada541b05e;p=ceph.git diff --git a/ceph/src/spawn/test/test_exception.cc b/ceph/src/spawn/test/test_exception.cc new file mode 100644 index 000000000..5dea81bad --- /dev/null +++ b/ceph/src/spawn/test/test_exception.cc @@ -0,0 +1,142 @@ +// +// test_exception.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2020 Casey Bodley (cbodley at redhat 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) +// + +#include + +#include +#include +#include + + +struct throwing_handler { + template + void operator()(spawn::basic_yield_context) { + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnThrowInHelper) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, throwing_handler()); + EXPECT_THROW(ioc.run_one(), std::runtime_error); // spawn->throw +} + +struct noop_handler { + template + void operator()(spawn::basic_yield_context) {} +}; + +struct throwing_completion_handler { + void operator()() { + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnHandlerThrowInHelper) +{ + boost::asio::io_context ioc; + spawn::spawn(bind_executor(ioc.get_executor(), + throwing_completion_handler()), + noop_handler()); + EXPECT_THROW(ioc.run_one(), std::runtime_error); // spawn->throw +} + +template +auto async_yield(CompletionToken&& token) + -> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) +{ + boost::asio::async_completion init(token); + boost::asio::post(std::move(init.completion_handler)); + return init.result.get(); +} + +struct yield_throwing_handler { + template + void operator()(spawn::basic_yield_context y) { + async_yield(y); // suspend and resume before throwing + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnThrowAfterYield) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, yield_throwing_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_throwing_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw +} + +struct yield_handler { + template + void operator()(spawn::basic_yield_context y) { + async_yield(y); + } +}; + +TEST(Exception, SpawnHandlerThrowAfterYield) +{ + boost::asio::io_context ioc; + spawn::spawn(bind_executor(ioc.get_executor(), + throwing_completion_handler()), + yield_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw +} + +struct nested_throwing_handler { + template + void operator()(spawn::basic_yield_context y) { + spawn::spawn(y, throwing_handler()); + } +}; + +TEST(Exception, SpawnThrowInNestedHelper) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, nested_throwing_handler()); + EXPECT_THROW(ioc.run_one(), std::runtime_error); // spawn->spawn->throw +} + +struct yield_nested_throwing_handler { + template + void operator()(spawn::basic_yield_context y) { + async_yield(y); // suspend and resume before spawning + spawn::spawn(y, yield_throwing_handler()); + } +}; + +TEST(Exception, SpawnThrowAfterNestedYield) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, yield_nested_throwing_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_nested_throwing_handler suspend + ASSERT_NO_THROW(ioc.run_one()); // yield_throwing_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw +} + +struct yield_throw_after_nested_handler { + template + void operator()(spawn::basic_yield_context y) { + async_yield(y); // suspend and resume before spawning + spawn::spawn(y, yield_handler()); + throw std::runtime_error(""); + } +}; + +TEST(Exception, SpawnThrowAfterNestedSpawn) +{ + boost::asio::io_context ioc; + spawn::spawn(ioc, yield_throw_after_nested_handler()); + ASSERT_NO_THROW(ioc.run_one()); // yield_throw_after_nested_handler suspend + EXPECT_THROW(ioc.run_one(), std::runtime_error); // resume + throw + EXPECT_EQ(1, ioc.poll()); // yield_handler resume + EXPECT_TRUE(ioc.stopped()); +}