#include #include #include #include #include #include #include "detail/render_snapshot.hpp" namespace { struct snapshot { std::atomic& live; std::array samples{}; explicit snapshot(std::atomic& count, int value = 0) : live(count) { ++live; samples.fill(value); } ~snapshot() { --live; } }; } BOOST_AUTO_TEST_CASE(sonus_snapshots_are_reclaimed_without_rendering) { auto live = std::atomic{0}; auto state = sonus::detail::render_snapshot{}; for (auto index = 0; index < 1000; ++index) { state.publish(std::make_unique(live, index)); BOOST_TEST(live.load() == 1); } state.publish(nullptr); BOOST_TEST(live.load() == 0); } BOOST_AUTO_TEST_CASE(sonus_snapshots_outlive_readers_and_are_collected_on_control_thread) { auto live = std::atomic{0}; auto state = sonus::detail::render_snapshot{}; state.publish(std::make_unique(live, 42)); { auto first = state.read(); state.publish(std::make_unique(live, 43)); { auto second = state.read(); state.publish(std::make_unique(live, 44)); state.collect(); BOOST_TEST(live.load() == 3); BOOST_TEST(second.get()->samples.front() == 43); } state.collect(); BOOST_TEST(live.load() == 3); BOOST_TEST(first.get()->samples.back() == 42); } BOOST_TEST(live.load() == 3); state.collect(); BOOST_TEST(live.load() == 1); } BOOST_AUTO_TEST_CASE(sonus_snapshot_publication_overlaps_readers) { auto live = std::atomic{0}; auto state = sonus::detail::render_snapshot{}; state.publish(std::make_unique(live)); auto start = std::barrier{3}; auto failed = std::atomic{false}; auto reader = [&] { start.arrive_and_wait(); for (auto index = 0; index < 20000; ++index) { auto guard = state.read(); auto const* value = guard.get(); for (auto sample : value->samples) { if (sample != value->samples.front()) { failed.store(true); } } } }; auto first = std::thread{reader}; auto second = std::thread{reader}; start.arrive_and_wait(); for (auto index = 0; index < 20000; ++index) { state.publish(std::make_unique(live, index)); } first.join(); second.join(); state.collect(); BOOST_TEST(!failed.load()); BOOST_TEST(live.load() == 1); }