File indexing completed on 2024-04-28 15:34:48

0001 /* -*- C++ -*-
0002     This file contains a testsuite for the queueing behaviour in ThreadWeaver.
0003 
0004     SPDX-FileCopyrightText: 2005-2013 Mirko Boehm <mirko@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "QueueTests.h"
0010 
0011 #include <QChar>
0012 
0013 #include <QDebug>
0014 #include <QObject>
0015 #include <QTest>
0016 
0017 #include <ThreadWeaver/Collection>
0018 #include <ThreadWeaver/DebuggingAids>
0019 #include <ThreadWeaver/DependencyPolicy>
0020 #include <ThreadWeaver/Job>
0021 #include <ThreadWeaver/QueuePolicy>
0022 #include <ThreadWeaver/Queueing>
0023 #include <ThreadWeaver/ResourceRestrictionPolicy>
0024 #include <ThreadWeaver/Sequence>
0025 #include <ThreadWeaver/State>
0026 
0027 #include <ThreadWeaver/QObjectDecorator>
0028 #include <ThreadWeaver/Thread>
0029 #include <ThreadWeaver/ThreadWeaver>
0030 
0031 QMutex s_GlobalMutex;
0032 
0033 LowPriorityAppendCharacterJob::LowPriorityAppendCharacterJob(QChar c, QString *stringref)
0034     : AppendCharacterJob(c, stringref)
0035 {
0036 }
0037 
0038 int LowPriorityAppendCharacterJob ::priority() const
0039 {
0040     return -1;
0041 }
0042 
0043 HighPriorityAppendCharacterJob::HighPriorityAppendCharacterJob(QChar c, QString *stringref)
0044     : AppendCharacterJob(c, stringref)
0045 {
0046 }
0047 
0048 int HighPriorityAppendCharacterJob::priority() const
0049 {
0050     return 1;
0051 }
0052 
0053 SecondThreadThatQueues::SecondThreadThatQueues()
0054     : QThread()
0055 {
0056 }
0057 
0058 void SecondThreadThatQueues::run()
0059 {
0060     QString sequence;
0061     AppendCharacterJob a('a', &sequence);
0062 
0063     ThreadWeaver::enqueue_raw(&a);
0064     ThreadWeaver::Queue::instance()->finish();
0065     QCOMPARE(sequence, QString("a"));
0066 }
0067 
0068 QueueTests::QueueTests(QObject *parent)
0069     : QObject(parent)
0070     , autoDeleteJob(nullptr)
0071 {
0072 }
0073 
0074 void QueueTests::initTestCase()
0075 {
0076     ThreadWeaver::setDebugLevel(true, 1);
0077 }
0078 
0079 void QueueTests::SimpleQueuePrioritiesTest()
0080 {
0081     using namespace ThreadWeaver;
0082 
0083     Queue weaver;
0084     weaver.setMaximumNumberOfThreads(1); // just one thread
0085     QString sequence;
0086     LowPriorityAppendCharacterJob jobA(QChar('a'), &sequence);
0087     AppendCharacterJob jobB(QChar('b'), &sequence);
0088     HighPriorityAppendCharacterJob jobC(QChar('c'), &sequence);
0089 
0090     // queue low priority, then normal priority, then high priority
0091     // if priorities are processed correctly, the jobs will be executed in reverse order
0092 
0093     weaver.suspend();
0094 
0095     enqueue_raw(&weaver, &jobA);
0096     enqueue_raw(&weaver, &jobB);
0097     enqueue_raw(&weaver, &jobC);
0098 
0099     weaver.resume();
0100     weaver.finish();
0101 
0102     QCOMPARE(sequence, QString("cba"));
0103 }
0104 
0105 void QueueTests::WeaverInitializationTest()
0106 {
0107     // this one mostly tests the sanity of the startup behaviour
0108     ThreadWeaver::Queue weaver;
0109     QCOMPARE(weaver.currentNumberOfThreads(), 0);
0110     QVERIFY(weaver.isEmpty());
0111     QVERIFY(weaver.isIdle());
0112     QVERIFY(weaver.queueLength() == 0);
0113     weaver.finish();
0114 }
0115 
0116 void QueueTests::QueueFromSecondThreadTest()
0117 {
0118     ThreadWeaver::Queue::instance(); // create global instance in the main thread
0119     SecondThreadThatQueues thread;
0120     thread.start();
0121     thread.wait();
0122     QVERIFY(ThreadWeaver::Queue::instance()->isIdle());
0123 }
0124 
0125 void QueueTests::deleteJob(ThreadWeaver::JobPointer job)
0126 {
0127     // test that signals are properly emitted (asynchronously, that is):
0128     QVERIFY(thread() == QThread::currentThread());
0129     QVERIFY(job == autoDeleteJob);
0130     delete autoDeleteJob;
0131     autoDeleteJob = nullptr;
0132 }
0133 
0134 void QueueTests::DeleteDoneJobsFromSequenceTest()
0135 {
0136     using namespace ThreadWeaver;
0137     QString sequence;
0138     autoDeleteJob = new QObjectDecorator(new AppendCharacterJob(QChar('a'), &sequence));
0139     AppendCharacterJob b(QChar('b'), &sequence);
0140     AppendCharacterJob c(QChar('c'), &sequence);
0141     Collection collection;
0142     collection << make_job_raw(autoDeleteJob) << b << c;
0143     QVERIFY(autoDeleteJob != nullptr);
0144     QVERIFY(connect(autoDeleteJob, SIGNAL(done(ThreadWeaver::JobPointer)), SLOT(deleteJob(ThreadWeaver::JobPointer))));
0145     stream() << collection;
0146     QTest::qWait(100); // return to event queue to make sure signals are delivered
0147     Queue::instance()->finish();
0148     QTest::qWait(100); // return to event queue to make sure signals are delivered
0149     // no need to delete a, that should be done in deleteJob
0150     QVERIFY(autoDeleteJob == nullptr);
0151 }
0152 
0153 void QueueTests::deleteCollection(ThreadWeaver::JobPointer collection)
0154 {
0155     QVERIFY(thread() == QThread::currentThread());
0156     QVERIFY(collection == autoDeleteCollection);
0157     delete autoDeleteCollection;
0158     autoDeleteCollection = nullptr;
0159 }
0160 
0161 void QueueTests::DeleteCollectionOnDoneTest()
0162 {
0163     using namespace ThreadWeaver;
0164     QString sequence;
0165     autoDeleteCollection = new QObjectDecorator(new Collection);
0166     QVERIFY(connect(autoDeleteCollection, SIGNAL(done(ThreadWeaver::JobPointer)), SLOT(deleteCollection(ThreadWeaver::JobPointer))));
0167 
0168     AppendCharacterJob a(QChar('a'), &sequence);
0169     AppendCharacterJob b(QChar('b'), &sequence);
0170     *autoDeleteCollection->collection() << a << b;
0171 
0172     enqueue_raw(autoDeleteCollection);
0173     // return to event queue to make sure signals are delivered
0174     // (otherwise, no slot calls would happen before the end of this function)
0175     // I assume the amount of time that we wait does not matter
0176     QTest::qWait(10);
0177     Queue::instance()->finish();
0178     // return to event queue to make sure signals are delivered
0179     QTest::qWait(10);
0180     // no need to delete a, that should be done in deleteJob
0181     QVERIFY(sequence.length() == 2);
0182     QVERIFY(autoDeleteCollection == nullptr);
0183 }
0184 
0185 QTEST_MAIN(QueueTests)
0186 
0187 #include "moc_QueueTests.cpp"