mirror of
https://github.com/YACReader/yacreader
synced 2025-05-28 03:10:27 -04:00
tests: add ConcurrentQueueTest::cancelPending1UserThread()
This new test consistently fails because of a bug in ConcurrentQueue::cancelPending() described in the following comment: https://github.com/YACReader/yacreader/issues/201#issuecomment-774987383
This commit is contained in:
parent
228fe1284e
commit
4bbd16c3b3
@ -126,8 +126,47 @@ private:
|
||||
const int threadId;
|
||||
};
|
||||
|
||||
class QueueControlMessagePrinter
|
||||
{
|
||||
public:
|
||||
explicit QueueControlMessagePrinter(const Total &total, int threadId, int threadCount)
|
||||
: total { total }, threadId { threadId }, threadCount { threadCount } { }
|
||||
|
||||
void printStartedMessage() const
|
||||
{
|
||||
log() << messageFormatString().arg("started");
|
||||
}
|
||||
void printCanceledMessage() const
|
||||
{
|
||||
log() << messageFormatString().arg("canceled");
|
||||
}
|
||||
void printWaitedMessage() const
|
||||
{
|
||||
log() << messageFormatString().arg("waited for");
|
||||
}
|
||||
|
||||
private:
|
||||
QString messageFormatString() const
|
||||
{
|
||||
auto format = QStringLiteral("#%1 %5 %2 %3 => %4").arg(threadId);
|
||||
const char *const threadStr = threadCount == 1 ? "thread" : "threads";
|
||||
return format.arg(threadCount).arg(threadStr).arg(total.load());
|
||||
}
|
||||
|
||||
const Total &total;
|
||||
const int threadId;
|
||||
const int threadCount;
|
||||
};
|
||||
|
||||
void waitAndPrint(ConcurrentQueue &queue, const QueueControlMessagePrinter &printer)
|
||||
{
|
||||
queue.waitAll();
|
||||
printer.printWaitedMessage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(Clock::duration)
|
||||
Q_DECLARE_METATYPE(JobData)
|
||||
|
||||
class ConcurrentQueueTest : public QObject
|
||||
@ -142,23 +181,15 @@ private slots:
|
||||
void multipleUserThreads_data();
|
||||
void multipleUserThreads();
|
||||
|
||||
void cancelPending1UserThread_data();
|
||||
void cancelPending1UserThread();
|
||||
|
||||
private:
|
||||
static constexpr int primaryThreadId { 0 };
|
||||
|
||||
QString messageFormatString(int threadCount) const
|
||||
QueueControlMessagePrinter makeMessagePrinter(int threadCount) const
|
||||
{
|
||||
auto format = QStringLiteral("#%1 %5 %2 %3 => %4").arg(primaryThreadId);
|
||||
const char *const threadStr = threadCount == 1 ? "thread" : "threads";
|
||||
return format.arg(threadCount).arg(threadStr).arg(total.load());
|
||||
}
|
||||
|
||||
void printStartedMessage(int threadCount) const
|
||||
{
|
||||
log() << messageFormatString(threadCount).arg("started");
|
||||
}
|
||||
void printWaitedMessage(int threadCount) const
|
||||
{
|
||||
log() << messageFormatString(threadCount).arg("waited for");
|
||||
return QueueControlMessagePrinter(total, primaryThreadId, threadCount);
|
||||
}
|
||||
|
||||
Total total { 0 };
|
||||
@ -191,13 +222,14 @@ void ConcurrentQueueTest::singleUserThread()
|
||||
QFETCH(const int, threadCount);
|
||||
QFETCH(const JobDataSet, jobs);
|
||||
|
||||
const auto printer = makeMessagePrinter(threadCount);
|
||||
|
||||
ConcurrentQueue queue(threadCount);
|
||||
printStartedMessage(threadCount);
|
||||
printer.printStartedMessage();
|
||||
|
||||
Enqueuer(queue, total, jobs, primaryThreadId)();
|
||||
|
||||
queue.waitAll();
|
||||
printWaitedMessage(threadCount);
|
||||
waitAndPrint(queue, printer);
|
||||
|
||||
QCOMPARE(total.load(), expectedTotal(jobs));
|
||||
}
|
||||
@ -243,8 +275,10 @@ void ConcurrentQueueTest::multipleUserThreads()
|
||||
QFETCH(const int, threadCount);
|
||||
QFETCH(const QVector<JobDataSet>, jobs);
|
||||
|
||||
const auto printer = makeMessagePrinter(threadCount);
|
||||
|
||||
ConcurrentQueue queue(threadCount);
|
||||
printStartedMessage(threadCount);
|
||||
printer.printStartedMessage();
|
||||
|
||||
if (!jobs.empty()) {
|
||||
std::vector<std::thread> enqueuerThreads;
|
||||
@ -257,12 +291,74 @@ void ConcurrentQueueTest::multipleUserThreads()
|
||||
t.join();
|
||||
}
|
||||
|
||||
queue.waitAll();
|
||||
printWaitedMessage(threadCount);
|
||||
waitAndPrint(queue, printer);
|
||||
|
||||
QCOMPARE(total.load(), expectedTotal(jobs));
|
||||
}
|
||||
|
||||
void ConcurrentQueueTest::cancelPending1UserThread_data()
|
||||
{
|
||||
QTest::addColumn<int>("threadCount");
|
||||
QTest::addColumn<JobDataSet>("jobs");
|
||||
QTest::addColumn<Clock::duration>("cancelDelay");
|
||||
QTest::addColumn<int>("expectedTotal");
|
||||
|
||||
const auto ms = [](int count) -> Clock::duration { return chrono::milliseconds(count); };
|
||||
const auto us = [](int count) -> Clock::duration { return chrono::microseconds(count); };
|
||||
|
||||
QTest::newRow("-") << 0 << JobDataSet {} << ms(0) << 0;
|
||||
QTest::newRow("01") << 2 << JobDataSet {} << ms(0) << 0;
|
||||
QTest::newRow("02") << 3 << JobDataSet {} << ms(1) << 0;
|
||||
QTest::newRow("A") << 1 << JobDataSet { { 5, ms(3) } } << ms(1) << 5;
|
||||
QTest::newRow("B") << 5 << JobDataSet { { 12, ms(1) } } << ms(1) << 12;
|
||||
|
||||
JobDataSet dataSet { { 1, ms(3) }, { 5, ms(2) }, { 3, ms(1) } };
|
||||
QTest::newRow("C1") << 1 << dataSet << ms(1) << 1;
|
||||
QTest::newRow("C2") << 1 << dataSet << ms(4) << 6;
|
||||
QTest::newRow("C3") << 2 << dataSet << ms(1) << 6;
|
||||
QTest::newRow("C4") << 3 << dataSet << ms(1) << 9;
|
||||
QTest::newRow("C5") << 1 << dataSet << ms(7) << 9;
|
||||
|
||||
dataSet.push_back({ 10, ms(5) });
|
||||
dataSet.push_back({ 20, ms(8) });
|
||||
dataSet.push_back({ 40, ms(20) });
|
||||
dataSet.push_back({ 80, ms(2) });
|
||||
QTest::newRow("D1") << 1 << dataSet << ms(1) << 1;
|
||||
QTest::newRow("D2") << 1 << dataSet << ms(15) << 39;
|
||||
QTest::newRow("D3") << 1 << dataSet << ms(50) << 159;
|
||||
QTest::newRow("D4") << 2 << dataSet << ms(4) << 39;
|
||||
QTest::newRow("D5") << 3 << dataSet << ms(4) << 79;
|
||||
QTest::newRow("D6") << 4 << dataSet << ms(4) << 159;
|
||||
QTest::newRow("D7") << 2 << dataSet << us(300) << 6;
|
||||
QTest::newRow("D8") << 3 << dataSet << us(500) << 9;
|
||||
QTest::newRow("D9") << 4 << dataSet << us(700) << 19;
|
||||
|
||||
QTest::newRow("E") << 4 << JobDataSet { { 20, ms(1) }, { 8, ms(5) }, { 5, ms(2) } } << ms(1) << 33;
|
||||
}
|
||||
|
||||
void ConcurrentQueueTest::cancelPending1UserThread()
|
||||
{
|
||||
QFETCH(const int, threadCount);
|
||||
QFETCH(const JobDataSet, jobs);
|
||||
QFETCH(const Clock::duration, cancelDelay);
|
||||
QFETCH(const int, expectedTotal);
|
||||
|
||||
const auto printer = makeMessagePrinter(threadCount);
|
||||
|
||||
ConcurrentQueue queue(threadCount);
|
||||
printer.printStartedMessage();
|
||||
|
||||
Enqueuer(queue, total, jobs, primaryThreadId)();
|
||||
|
||||
std::this_thread::sleep_for(cancelDelay);
|
||||
queue.cancelPending();
|
||||
printer.printCanceledMessage();
|
||||
|
||||
waitAndPrint(queue, printer);
|
||||
|
||||
QCOMPARE(total.load(), expectedTotal);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(ConcurrentQueueTest)
|
||||
|
||||
#include "concurrent_queue_test.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user