13#include <boost/test/unit_test.hpp>
16#include <condition_variable>
19#include <unordered_set>
30#ifdef DEBUG_LOCKCONTENTION
55 n_calls.fetch_add(1, std::memory_order_relaxed);
108 static std::condition_variable
cv;
119 std::unique_lock<std::mutex> l(
m);
120 nFrozen.store(1, std::memory_order_relaxed);
122 cv.wait(l, []{
return nFrozen.load(std::memory_order_relaxed) == 0;});
128 other.should_freeze =
false;
133 other.should_freeze =
false;
143std::unordered_multiset<size_t> UniqueCheck::results;
163 std::vector<FakeCheckCheckCompletion> vChecks;
165 for (
const size_t i : range) {
172 total -= vChecks.size();
173 control.
Add(std::move(vChecks));
175 BOOST_REQUIRE(!control.
Complete().has_value());
186 std::vector<size_t> range;
187 range.push_back(
size_t{0});
188 Correct_Queue_range(range);
194 std::vector<size_t> range;
195 range.push_back(
size_t{1});
196 Correct_Queue_range(range);
202 std::vector<size_t> range;
203 range.push_back(100000);
204 Correct_Queue_range(range);
210 std::vector<size_t> range;
211 range.reserve(100000/1000);
212 for (
size_t i = 2; i < 100000; i += std::max((
size_t)1, (
size_t)m_rng.randrange(std::min((
size_t)1000, ((
size_t)100000) - i))))
214 Correct_Queue_range(range);
222 for (
size_t i = 0; i < 1001; ++i) {
224 size_t remaining = i;
226 size_t r = m_rng.randrange(10);
228 std::vector<FixedCheck> vChecks;
230 for (
size_t k = 0;
k < r && remaining;
k++, remaining--)
231 vChecks.emplace_back(remaining == 1 ? std::make_optional<int>(17 * i) : std::nullopt);
232 control.
Add(std::move(vChecks));
236 BOOST_REQUIRE(result.has_value() && *result ==
static_cast<int>(17 * i));
238 BOOST_REQUIRE(!result.has_value());
247 for (
auto times = 0; times < 10; ++times) {
248 for (
const bool end_fails : {
true,
false}) {
251 std::vector<FixedCheck> vChecks;
252 vChecks.resize(100,
FixedCheck(std::nullopt));
253 vChecks[99] =
FixedCheck(end_fails ? std::make_optional<int>(2) : std::nullopt);
254 control.
Add(std::move(vChecks));
256 bool r = !control.
Complete().has_value();
257 BOOST_REQUIRE(r != end_fails);
268 size_t COUNT = 100000;
269 size_t total =
COUNT;
273 size_t r = m_rng.randrange(10);
274 std::vector<UniqueCheck> vChecks;
275 for (
size_t k = 0;
k < r && total;
k++)
276 vChecks.emplace_back(--total);
277 control.
Add(std::move(vChecks));
283 BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(),
COUNT);
284 for (
size_t i = 0; i <
COUNT; ++i) {
285 r = r && UniqueCheck::results.count(i) == 1;
300 for (
size_t i = 0; i < 1000; ++i) {
305 size_t r = m_rng.randrange(10);
306 std::vector<MemoryCheck> vChecks;
307 for (
size_t k = 0;
k < r && total;
k++) {
311 vChecks.emplace_back(total == 0 || total == i || total == i/2);
313 control.
Add(std::move(vChecks));
326 std::thread t0([&]() {
328 std::vector<FrozenCleanupCheck> vChecks(1);
329 control.
Add(std::move(vChecks));
339 for (
auto x = 0; x < 100 && !fails; ++x) {
340 fails = queue->m_control_mutex.try_lock();
351 BOOST_REQUIRE(!fails);
360 std::vector<std::thread> tg;
362 std::atomic<int> nThreads {0};
363 std::atomic<int> fails {0};
364 for (
size_t i = 0; i < 3; ++i) {
369 auto observed = ++nThreads;
371 fails += observed != nThreads;
374 for (
auto& thread: tg) {
375 if (thread.joinable()) thread.join();
377 BOOST_REQUIRE_EQUAL(fails, 0);
380 std::vector<std::thread> tg;
382 std::condition_variable cv;
383 bool has_lock{
false};
384 bool has_tried{
false};
386 bool done_ack{
false};
388 std::unique_lock<std::mutex> l(
m);
391 std::unique_lock<std::mutex> ll(
m);
394 cv.wait(ll, [&]{
return has_tried;});
399 cv.wait(ll, [&]{
return done_ack;});
402 cv.wait(l, [&](){
return has_lock;});
404 for (
auto x = 0; x < 100 && !fails; ++x) {
405 fails = queue->m_control_mutex.try_lock();
409 cv.wait(l, [&](){
return done;});
413 BOOST_REQUIRE(!fails);
415 for (
auto& thread: tg) {
416 if (thread.joinable()) thread.join();
CCheckQueue< FakeCheckCheckCompletion > Correct_Queue
CCheckQueue< FrozenCleanupCheck > FrozenCleanup_Queue
static const int SCRIPT_CHECK_THREADS
CCheckQueue< UniqueCheck > Unique_Queue
CCheckQueue< FixedCheck > Fixed_Queue
CCheckQueue< FakeCheck > Standard_Queue
CCheckQueue< MemoryCheck > Memory_Queue
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
Test that 0 checks is correct.
static const unsigned int QUEUE_BATCH_SIZE
RAII-style controller object for a CCheckQueue that guarantees the passed queue is finished before co...
std::optional< R > Complete()
void Add(std::vector< T > &&vChecks)
Queue for verifications that have to be performed.
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
void Correct_Queue_range(std::vector< size_t > range)
This test case checks that the CCheckQueue works properly with each specified size_t Checks pushed.
static std::atomic< size_t > n_calls
std::optional< int > operator()()
std::optional< int > operator()() const
std::optional< int > m_result
FixedCheck(std::optional< int > result)
std::optional< int > operator()() const
static std::atomic< uint64_t > nFrozen
static std::condition_variable cv
std::optional< int > operator()() const
FrozenCleanupCheck & operator=(FrozenCleanupCheck &&other) noexcept
FrozenCleanupCheck(FrozenCleanupCheck &&other) noexcept
FrozenCleanupCheck()=default
static std::atomic< size_t > fake_allocated_memory
std::optional< int > operator()() const
MemoryCheck(const MemoryCheck &x)
Identical to TestingSetup but excludes lock contention logging if DEBUG_LOCKCONTENTION is defined,...
NoLockLoggingTestingSetup()
Testing setup that configures a complete environment.
static std::unordered_multiset< size_t > results GUARDED_BY(m)
std::optional< int > operator()()
UniqueCheck(size_t check_id_in)
void UninterruptibleSleep(const std::chrono::microseconds &n)