diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9beaec3ac..8cdea977e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,6 +9,7 @@ set(base_test_SOURCES base-convert.cpp base-dictionary.cpp base-fifo.cpp + base-io-engine.cpp base-json.cpp base-match.cpp base-netstring.cpp @@ -76,6 +77,11 @@ add_boost_test(base base_dictionary/keys_ordered base_fifo/construct base_fifo/io + base_io_engine/timeout_run + base_io_engine/timeout_cancelled + base_io_engine/timeout_scope + base_io_engine/timeout_due_cancelled + base_io_engine/timeout_due_scope base_json/encode base_json/decode base_json/invalid1 diff --git a/test/base-io-engine.cpp b/test/base-io-engine.cpp new file mode 100644 index 000000000..2261bab91 --- /dev/null +++ b/test/base-io-engine.cpp @@ -0,0 +1,143 @@ +/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */ + +#include "base/io-engine.hpp" +#include "base/utility.hpp" +#include +#include +#include + +using namespace icinga; + +BOOST_AUTO_TEST_SUITE(base_io_engine) + +BOOST_AUTO_TEST_CASE(timeout_run) +{ + boost::asio::io_context io; + boost::asio::io_context::strand strand (io); + int called = 0; + + boost::asio::spawn(strand, [&](boost::asio::yield_context yc) { + boost::asio::deadline_timer timer (io); + + Timeout::Ptr timeout = new Timeout(io, strand, boost::posix_time::millisec(300), [&called] { ++called; }); + BOOST_CHECK_EQUAL(called, 0); + + timer.expires_from_now(boost::posix_time::millisec(200)); + timer.async_wait(yc); + BOOST_CHECK_EQUAL(called, 0); + + timer.expires_from_now(boost::posix_time::millisec(200)); + timer.async_wait(yc); + }); + + io.run(); + BOOST_CHECK_EQUAL(called, 1); +} + +BOOST_AUTO_TEST_CASE(timeout_cancelled) +{ + boost::asio::io_context io; + boost::asio::io_context::strand strand (io); + int called = 0; + + boost::asio::spawn(strand, [&](boost::asio::yield_context yc) { + boost::asio::deadline_timer timer (io); + Timeout::Ptr timeout = new Timeout(io, strand, boost::posix_time::millisec(300), [&called] { ++called; }); + + timer.expires_from_now(boost::posix_time::millisec(200)); + timer.async_wait(yc); + + timeout->Cancel(); + BOOST_CHECK_EQUAL(called, 0); + + timer.expires_from_now(boost::posix_time::millisec(200)); + timer.async_wait(yc); + }); + + io.run(); + BOOST_CHECK_EQUAL(called, 0); +} + +BOOST_AUTO_TEST_CASE(timeout_scope) +{ + boost::asio::io_context io; + boost::asio::io_context::strand strand (io); + int called = 0; + + boost::asio::spawn(strand, [&](boost::asio::yield_context yc) { + boost::asio::deadline_timer timer (io); + + { + Timeout::Ptr timeout = new Timeout(io, strand, boost::posix_time::millisec(300), [&called] { ++called; }); + + timer.expires_from_now(boost::posix_time::millisec(200)); + timer.async_wait(yc); + } + + BOOST_CHECK_EQUAL(called, 0); + + timer.expires_from_now(boost::posix_time::millisec(200)); + timer.async_wait(yc); + }); + + io.run(); + BOOST_CHECK_EQUAL(called, 0); +} + +BOOST_AUTO_TEST_CASE(timeout_due_cancelled) +{ + boost::asio::io_context io; + boost::asio::io_context::strand strand (io); + int called = 0; + + boost::asio::spawn(strand, [&](boost::asio::yield_context yc) { + boost::asio::deadline_timer timer (io); + Timeout::Ptr timeout = new Timeout(io, strand, boost::posix_time::millisec(300), [&called] { ++called; }); + + // Give the timeout enough time to become due while blocking its strand to prevent it from actually running... + Utility::Sleep(0.4); + + BOOST_CHECK_EQUAL(called, 0); + + // ... so that this shall still work: + timeout->Cancel(); + + BOOST_CHECK_EQUAL(called, 0); + + timer.expires_from_now(boost::posix_time::millisec(100)); + timer.async_wait(yc); + }); + + io.run(); + BOOST_CHECK_EQUAL(called, 0); +} + +BOOST_AUTO_TEST_CASE(timeout_due_scope) +{ + boost::asio::io_context io; + boost::asio::io_context::strand strand (io); + int called = 0; + + boost::asio::spawn(strand, [&](boost::asio::yield_context yc) { + boost::asio::deadline_timer timer (io); + + { + Timeout::Ptr timeout = new Timeout(io, strand, boost::posix_time::millisec(300), [&called] { ++called; }); + + // Give the timeout enough time to become due while blocking its strand to prevent it from actually running... + Utility::Sleep(0.4); + + BOOST_CHECK_EQUAL(called, 0); + } // ... so that Timeout#~Timeout() shall still work here. + + BOOST_CHECK_EQUAL(called, 0); + + timer.expires_from_now(boost::posix_time::millisec(100)); + timer.async_wait(yc); + }); + + io.run(); + BOOST_CHECK_EQUAL(called, 0); +} + +BOOST_AUTO_TEST_SUITE_END()