From fa6e010759aa737d737f0a7f70795494cfac8abb Mon Sep 17 00:00:00 2001 From: Thomas Horstink Date: Sun, 17 Sep 2023 11:31:21 +0200 Subject: [PATCH] fix race in test --- symmetri/tests/CMakeLists.txt | 5 --- symmetri/tests/test_external_input.cc | 61 +++++++++++++++------------ 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/symmetri/tests/CMakeLists.txt b/symmetri/tests/CMakeLists.txt index 1f29a45..615e0ab 100644 --- a/symmetri/tests/CMakeLists.txt +++ b/symmetri/tests/CMakeLists.txt @@ -13,11 +13,6 @@ FetchContent_Declare( # https://stackoverflow.com/questions/65527126/disable-install-for-fetchcontent FetchContent_GetProperties(concurrentqueue) -if(NOT concurrentqueue_POPULATED) - FetchContent_Populate(concurrentqueue) - add_subdirectory(${concurrentqueue_SOURCE_DIR} ${concurrentqueue_BINARY_DIR} EXCLUDE_FROM_ALL) -endif() - include_directories(${EIGEN3_INCLUDE_DIRS} ../include ..) include(CTest) diff --git a/symmetri/tests/test_external_input.cc b/symmetri/tests/test_external_input.cc index 2e81b92..f66e146 100644 --- a/symmetri/tests/test_external_input.cc +++ b/symmetri/tests/test_external_input.cc @@ -1,37 +1,44 @@ #include #include +#include #include "symmetri/symmetri.h" using namespace symmetri; -std::atomic i_ran(false); -void tExtInput() { i_ran.store(true); } +std::atomic can_continue(false), done(false); +void tAllowExitInput() { + can_continue.store(true); + while (!done.load()) { + } // wait till trigger is done, otherwise we would deadlock +} TEST_CASE("Test external input.") { - Net net = { - {"t0", {{}, {"Pa"}}}, {"t1", {{"Pa"}, {"Pb"}}}, {"t2", {{"Pc"}, {"Pb"}}}}; - // we can omit t0, it will be auto-filled as {"t0", DirectMutation{}} - Store store = {{"t1", &tExtInput}, - {"t2", []() { - std::this_thread::sleep_for(std::chrono::milliseconds(15)); - }}}; - Marking m0 = {{"Pa", 0}, {"Pb", 0}, {"Pc", 1}}; - Marking final_m = {{"Pb", 2}}; - auto stp = std::make_shared(3); - - PetriNet app(net, m0, final_m, store, {}, "test_net_ext_input", stp); - - // enqueue a trigger; - stp->push([trigger = app.registerTransitionCallback("t0")]() { - // sleep a bit so it gets triggered _after_ the net started. - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - trigger(); - }); - - // run the net - auto res = fire(app); - - REQUIRE(res == state::Completed); - REQUIRE(i_ran); + { + Net net = {{"t0", {{}, {"Pb"}}}, + {"t1", {{"Pa"}, {"Pb"}}}, + {"t2", {{"Pb", "Pb"}, {"Pc"}}}}; + // we can omit t0, it will be auto-filled as {"t0", DirectMutation{}} + Store store = {{"t1", &tAllowExitInput}, {"t2", DirectMutation{}}}; + Marking m0 = {{"Pa", 2}, {"Pb", 0}, {"Pc", 0}}; + Marking final_m = {{"Pc", 1}}; + auto stp = std::make_shared(3); + + PetriNet app(net, m0, final_m, store, {}, "test_net_ext_input", stp); + + // enqueue a trigger; + stp->push([trigger = app.registerTransitionCallback("t0")]() { + // sleep a bit so it gets triggered _after_ the net started. Otherwise the + // net would deadlock + while (!can_continue.load()) { + } + trigger(); + done.store(true); + }); + + // run the net + auto res = fire(app); + CHECK(can_continue); + CHECK(res == state::Completed); + } }