File indexing completed on 2024-05-12 05:52:46

0001 /*
0002  * SPDX-License-Identifier: GPL-3.0-or-later
0003  * SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
0004  */
0005 #include "account/actions_p.h"
0006 
0007 #include "../test-utils/spy.h"
0008 
0009 #include <QSignalSpy>
0010 #include <QTest>
0011 #include <QTimer>
0012 #include <QtDebug>
0013 
0014 class TestJob: public accounts::AccountJob // clazy:exclude=ctor-missing-parent-argument
0015 {
0016     Q_OBJECT
0017 public:
0018     ~TestJob()
0019     {
0020         qDebug() << "TestJob is being destroyed on thread:" << QThread::currentThread() << "should be:" << thread();
0021     }
0022 
0023 public Q_SLOTS:
0024     void run(void) override
0025     {
0026         Q_EMIT finished();
0027         qDebug() << "Did finish on thread:" << QThread::currentThread() << "should be:" << thread();
0028         qDebug() << "Current thread should NOT be finished, check:" << (QThread::currentThread()->isFinished() == false);
0029     }
0030 };
0031 
0032 class DispatchTest: public QObject // clazy:exclude=ctor-missing-parent-argument
0033 {
0034     Q_OBJECT
0035 private Q_SLOTS:
0036     void liveDispatch(void);
0037     void coldDispatch(void);
0038 };
0039 
0040 /*
0041  * Test whether queueing jobs up-front before actually starting a worker thread works,
0042  * i.e. whether the job is automatically dispatched once the worker thread starts
0043  */
0044 void DispatchTest::coldDispatch(void)
0045 {
0046 
0047     QThread *thread = new QThread(this);
0048     QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
0049 
0050     QSignalSpy threadStarted(thread, &QThread::started);
0051     QSignalSpy threadFinished(thread, &QThread::finished);
0052     QSignalSpy threadCleaned(thread, &QThread::destroyed);
0053 
0054     accounts::Dispatcher *uut = new accounts::Dispatcher(thread);
0055     QSignalSpy dispatcherDispatched(uut, &accounts::Dispatcher::dispatch);
0056     QSignalSpy dispatcherCleaned(uut, &accounts::Dispatcher::destroyed);
0057 
0058     TestJob *job = new TestJob();
0059     QSignalSpy jobFinished(job, &TestJob::finished);
0060     QSignalSpy jobCleaned(job, &TestJob::destroyed);
0061 
0062     bool jobCallBackCalled = false;
0063     uut->queueAndProceed(job, [job, thread, &jobCallBackCalled](void) -> void
0064     {
0065         QCOMPARE(job->thread(), thread);
0066         jobCallBackCalled = true;
0067     });
0068     QVERIFY2(jobCallBackCalled, "signal setup call back should have been called for job");
0069 
0070     qDebug() << "About to start thread:" << thread;
0071     thread->start();
0072     QVERIFY2(test::signal_eventually_emitted_once(threadStarted), "worker thread should have started by now");
0073 
0074     QVERIFY2(test::signal_eventually_emitted_once(dispatcherDispatched), "dispatcher should have dispatched the job by now");
0075     QVERIFY2(test::signal_eventually_emitted_once(jobFinished), "job should be finished by now");
0076     QVERIFY2(test::signal_eventually_emitted_once(jobCleaned), "job should be disposed of by now");
0077 
0078     QTimer::singleShot(0, thread, &QThread::quit);
0079     QVERIFY2(test::signal_eventually_emitted_once(threadFinished), "worker thread should be finished by now");
0080     QVERIFY2(test::signal_eventually_emitted_once(threadCleaned), "thread should be disposed of by now");
0081 
0082     uut->deleteLater();
0083     QVERIFY2(test::signal_eventually_emitted_once(dispatcherCleaned), "dispatcher should be disposed of by now");
0084 }
0085 
0086 /*
0087  * Test whether queueing jobs works while a worker thread is running already,
0088  * i.e. whether the job is dispatched straight away.
0089  */
0090 void DispatchTest::liveDispatch(void)
0091 {
0092     QThread *thread = new QThread(this);
0093     QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
0094 
0095     QSignalSpy threadStarted(thread, &QThread::started);
0096     QSignalSpy threadFinished(thread, &QThread::finished);
0097     QSignalSpy threadCleaned(thread, &QThread::destroyed);
0098 
0099     qDebug() << "About to start thread:" << thread;
0100     thread->start();
0101     QVERIFY2(test::signal_eventually_emitted_once(threadStarted), "worker thread should have started by now");
0102 
0103     accounts::Dispatcher *uut = new accounts::Dispatcher(thread);
0104     QSignalSpy dispatcherDispatched(uut, &accounts::Dispatcher::dispatch);
0105     QSignalSpy dispatcherCleaned(uut, &accounts::Dispatcher::destroyed);
0106 
0107     TestJob *job = new TestJob();
0108     QSignalSpy jobFinished(job, &TestJob::finished);
0109     QSignalSpy jobCleaned(job, &TestJob::destroyed);\
0110 
0111     bool jobCallBackCalled = false;
0112 
0113     uut->queueAndProceed(job, [job, thread, &jobCallBackCalled](void) -> void
0114     {
0115         QCOMPARE(job->thread(), thread);
0116         jobCallBackCalled = true;
0117     });
0118     QVERIFY2(jobCallBackCalled, "signal setup call back should have been called for job");
0119 
0120     QVERIFY2(test::signal_eventually_emitted_once(dispatcherDispatched), "dispatcher should have dispatched the job by now");
0121     QVERIFY2(test::signal_eventually_emitted_once(jobFinished), "job should be finished by now");
0122     QVERIFY2(test::signal_eventually_emitted_once(jobCleaned), "job should be disposed of by now");
0123 
0124     QTimer::singleShot(0, thread, &QThread::quit);
0125     QVERIFY2(test::signal_eventually_emitted_once(threadFinished), "worker thread should be finished by now");
0126     QVERIFY2(test::signal_eventually_emitted_once(threadCleaned), "thread should be disposed of by now");
0127 
0128     uut->deleteLater();
0129     QVERIFY2(test::signal_eventually_emitted_once(dispatcherCleaned), "dispatcher should be disposed of by now");
0130 }
0131 
0132 QTEST_MAIN(DispatchTest)
0133 
0134 #include "dispatcher-dispatch.moc"