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"