From e60c80214e227a4f18345e213857e687d7a974c9 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 15 Sep 2019 21:54:01 +0200 Subject: [PATCH] improve tests --- test/test.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index 61638ec..665a161 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,4 +1,5 @@ #define CATCH_CONFIG_MAIN +#define CATCH_CONFIG_FAST_COMPILE #include @@ -20,11 +21,66 @@ bool worker(sgnl::AtomicCondition& exit_condition) return exit_condition.get(); } +int looping_worker(sgnl::AtomicCondition& exit_condition) +{ + int i = 0; + while( exit_condition.get() == false ) + { + exit_condition.wait_for(std::chrono::milliseconds(2), true); + ++i; + } + + return i; +} + } // namespace -TEST_CASE("main") +TEST_CASE("condition-get-set") +{ + sgnl::AtomicCondition condition(23); + REQUIRE( condition.get() == 23 ); + condition.set(42); + REQUIRE( condition.get() == 42 ); +} + +TEST_CASE("constructor-thread-blocks-signals") +{ + sgnl::AtomicCondition condition(false); + + sgnl::SignalHandler signal_handler({{SIGTERM, true}, {SIGINT, true}}, condition); + + std::promise signal_handler_thread_id; + std::future ft_sig_handler = + std::async(std::launch::async, [&]() { + signal_handler_thread_id.set_value(pthread_self()); + return signal_handler(); + }); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::yield(); + + // send terminate signal to main thread .. + REQUIRE( pthread_kill(pthread_self(), SIGTERM) == 0 ); + + // .. but we're still running + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::yield(); + + // send interrupt signal to signal handler thread + REQUIRE( + pthread_kill( + signal_handler_thread_id.get_future().get(), + SIGINT) == 0 ); + + CHECK( ft_sig_handler.get() == SIGINT ); + CHECK( condition.get() == true ); + + CHECK( signal_handler() == SIGTERM ); +} + +TEST_CASE("exit-condition") { std::vector signals({SIGINT, SIGTERM, SIGUSR1, SIGUSR2}); for( auto test_signal : signals ) @@ -40,7 +96,7 @@ TEST_CASE("main") }); std::vector> futures; - for(int i = 0; i < 10; ++i) + for(int i = 0; i < 50; ++i) futures.push_back( std::async( std::launch::async, @@ -48,6 +104,8 @@ TEST_CASE("main") std::ref(exit_condition))); std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::yield(); + REQUIRE( pthread_kill( signal_handler_thread_id.get_future().get(), @@ -61,3 +119,46 @@ TEST_CASE("main") } } +TEST_CASE("exit-condition-looping") +{ + std::vector signals({SIGINT, SIGTERM, SIGUSR1, SIGUSR2}); + for( auto test_signal : signals ) + { + sgnl::AtomicCondition exit_condition(false); + + sgnl::SignalHandler signal_handler({{test_signal, true}}, exit_condition); + std::promise signal_handler_thread_id; + std::future ft_sig_handler = + std::async(std::launch::async, [&]() { + signal_handler_thread_id.set_value(pthread_self()); + return signal_handler(); + }); + + std::vector> futures; + for(int i = 0; i < 10; ++i) + futures.push_back( + std::async( + std::launch::async, + &looping_worker, + std::ref(exit_condition))); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::yield(); + + REQUIRE( + pthread_kill( + signal_handler_thread_id.get_future().get(), + test_signal) == 0 ); + + for(auto& future : futures) + // After 100 milliseconds, each worker thread should + // have looped at least 10 times. + // This might break if system is under heavy load + // or really slow. + REQUIRE(future.get() > 10); + + int signal = ft_sig_handler.get(); + REQUIRE( signal == test_signal ); + } +} +