1 /*
2     SPDX-FileCopyrightText: 2012 Volker Krause <vkrause@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include <qtest_akonadi.h>
8 
9 #include "fakesession.h"
10 #include "job.h"
11 
12 Q_DECLARE_METATYPE(KJob *)
13 Q_DECLARE_METATYPE(Akonadi::Job *)
14 
15 using namespace Akonadi;
16 
17 class FakeJob : public Job
18 {
19     Q_OBJECT
20 public:
FakeJob(QObject * parent=nullptr)21     explicit FakeJob(QObject *parent = nullptr)
22         : Job(parent)
23     {
24     }
done()25     void done()
26     {
27         emitResult();
28     }
29 
30 protected:
doStart()31     void doStart() override
32     {
33         emitWriteFinished();
34     }
35 };
36 
37 class JobTest : public QObject
38 {
39     Q_OBJECT
40 private Q_SLOTS:
initTestCase()41     void initTestCase()
42     {
43         qRegisterMetaType<KJob *>();
44         qRegisterMetaType<Akonadi::Job *>();
45     }
46 
testTopLevelJobExecution()47     void testTopLevelJobExecution()
48     {
49         FakeSession session("fakeSession", FakeSession::EndJobsManually);
50 
51         QSignalSpy sessionQueueSpy(&session, &FakeSession::jobAdded);
52         QVERIFY(sessionQueueSpy.isValid());
53 
54         auto job1 = new FakeJob(&session);
55         QSignalSpy job1DoneSpy(job1, &KJob::result);
56         QVERIFY(job1DoneSpy.isValid());
57 
58         auto job2 = new FakeJob(&session);
59         QSignalSpy job2DoneSpy(job2, &KJob::result);
60         QVERIFY(job2DoneSpy.isValid());
61 
62         QCOMPARE(sessionQueueSpy.size(), 2);
63         QCOMPARE(job1DoneSpy.size(), 0);
64 
65         QSignalSpy job1AboutToStartSpy(job1, &Job::aboutToStart);
66         QVERIFY(job1AboutToStartSpy.wait());
67 
68         QCOMPARE(job1DoneSpy.size(), 0);
69 
70         job1->done();
71         QCOMPARE(job1DoneSpy.size(), 1);
72 
73         QSignalSpy job2AboutToStartSpy(job2, &Job::aboutToStart);
74         QVERIFY(job2AboutToStartSpy.wait());
75         QCOMPARE(job2DoneSpy.size(), 0);
76         job2->done();
77 
78         QCOMPARE(job1DoneSpy.size(), 1);
79         QCOMPARE(job2DoneSpy.size(), 1);
80     }
81 
testKillSession()82     void testKillSession()
83     {
84         FakeSession session("fakeSession", FakeSession::EndJobsManually);
85 
86         QSignalSpy sessionQueueSpy(&session, &FakeSession::jobAdded);
87         QVERIFY(sessionQueueSpy.isValid());
88         QSignalSpy sessionReconnectSpy(&session, &Session::reconnected);
89         QVERIFY(sessionReconnectSpy.isValid());
90 
91         auto job1 = new FakeJob(&session);
92         QSignalSpy job1DoneSpy(job1, &KJob::result);
93         QVERIFY(job1DoneSpy.isValid());
94 
95         auto job2 = new FakeJob(&session);
96         QSignalSpy job2DoneSpy(job2, &KJob::result);
97         QVERIFY(job2DoneSpy.isValid());
98 
99         QCOMPARE(sessionQueueSpy.size(), 2);
100         QSignalSpy job1AboutToStartSpy(job1, &Job::aboutToStart);
101         QVERIFY(job1AboutToStartSpy.wait());
102 
103         // one job running, one queued, now kill the session
104         session.clear();
105         QVERIFY(sessionReconnectSpy.wait());
106 
107         QCOMPARE(job1DoneSpy.size(), 1);
108         QCOMPARE(job2DoneSpy.size(), 1);
109         QCOMPARE(sessionReconnectSpy.size(), 2);
110     }
111 
testKillQueuedJob()112     void testKillQueuedJob()
113     {
114         FakeSession session("fakeSession", FakeSession::EndJobsManually);
115 
116         QSignalSpy sessionQueueSpy(&session, &FakeSession::jobAdded);
117         QVERIFY(sessionQueueSpy.isValid());
118         QSignalSpy sessionReconnectSpy(&session, &Session::reconnected);
119         QVERIFY(sessionReconnectSpy.isValid());
120 
121         auto job1 = new FakeJob(&session);
122         QSignalSpy job1DoneSpy(job1, &KJob::result);
123         QVERIFY(job1DoneSpy.isValid());
124 
125         auto job2 = new FakeJob(&session);
126         QSignalSpy job2DoneSpy(job2, &KJob::result);
127         QVERIFY(job2DoneSpy.isValid());
128 
129         QCOMPARE(sessionQueueSpy.size(), 2);
130         QSignalSpy job1AboutToStartSpy(job1, &Job::aboutToStart);
131         QVERIFY(job1AboutToStartSpy.wait());
132 
133         // one job running, one queued, now kill the waiting job
134         QVERIFY(job2->kill(KJob::EmitResult));
135 
136         QCOMPARE(job1DoneSpy.size(), 0);
137         QCOMPARE(job2DoneSpy.size(), 1);
138 
139         job1->done();
140         QCOMPARE(job1DoneSpy.size(), 1);
141         QCOMPARE(job2DoneSpy.size(), 1);
142         QCOMPARE(sessionReconnectSpy.size(), 1);
143     }
144 
testKillRunningJob()145     void testKillRunningJob()
146     {
147         FakeSession session("fakeSession", FakeSession::EndJobsManually);
148 
149         QSignalSpy sessionQueueSpy(&session, &FakeSession::jobAdded);
150         QVERIFY(sessionQueueSpy.isValid());
151         QSignalSpy sessionReconnectSpy(&session, &Session::reconnected);
152         QVERIFY(sessionReconnectSpy.isValid());
153 
154         auto job1 = new FakeJob(&session);
155         QSignalSpy job1DoneSpy(job1, &KJob::result);
156         QVERIFY(job1DoneSpy.isValid());
157 
158         auto job2 = new FakeJob(&session);
159         QSignalSpy job2DoneSpy(job2, &KJob::result);
160         QVERIFY(job2DoneSpy.isValid());
161 
162         QCOMPARE(sessionQueueSpy.size(), 2);
163         QSignalSpy job1AboutToStartSpy(job1, &Job::aboutToStart);
164         QVERIFY(job1AboutToStartSpy.wait());
165 
166         // one job running, one queued, now kill the running one
167         QVERIFY(job1->kill(KJob::EmitResult));
168 
169         QCOMPARE(job1DoneSpy.size(), 1);
170         QCOMPARE(job2DoneSpy.size(), 0);
171 
172         // session needs to reconnect, then execute the next job
173         QSignalSpy job2AboutToStartSpy(job2, &Job::aboutToStart);
174         QVERIFY(job2AboutToStartSpy.wait());
175         QCOMPARE(sessionReconnectSpy.size(), 2);
176         job2->done();
177 
178         QCOMPARE(job1DoneSpy.size(), 1);
179         QCOMPARE(job2DoneSpy.size(), 1);
180         QCOMPARE(sessionReconnectSpy.size(), 2);
181     }
182 
testKillRunningSubjob()183     void testKillRunningSubjob()
184     {
185         FakeSession session("fakeSession", FakeSession::EndJobsManually);
186 
187         QSignalSpy sessionQueueSpy(&session, &FakeSession::jobAdded);
188         QSignalSpy sessionReconnectSpy(&session, &Session::reconnected);
189 
190         auto parentJob = new FakeJob(&session);
191         parentJob->setObjectName(QStringLiteral("parentJob"));
192         QSignalSpy parentJobDoneSpy(parentJob, &KJob::result);
193 
194         auto subjob = new FakeJob(parentJob);
195         subjob->setObjectName(QStringLiteral("subjob"));
196         QSignalSpy subjobDoneSpy(subjob, &KJob::result);
197 
198         auto subjob2 = new FakeJob(parentJob);
199         subjob2->setObjectName(QStringLiteral("subjob2"));
200         QSignalSpy subjob2DoneSpy(subjob2, &KJob::result);
201 
202         auto nextJob = new FakeJob(&session);
203         nextJob->setObjectName(QStringLiteral("nextJob"));
204         QSignalSpy nextJobDoneSpy(nextJob, &KJob::result);
205 
206         QCOMPARE(sessionQueueSpy.size(), 2);
207         QSignalSpy parentJobAboutToStart(parentJob, &Job::aboutToStart);
208         QVERIFY(parentJobAboutToStart.wait());
209 
210         QSignalSpy subjobAboutToStart(subjob, &Job::aboutToStart);
211         QVERIFY(subjobAboutToStart.wait());
212 
213         // one parent job, one subjob running (another one waiting), now kill the running subjob
214         QVERIFY(subjob->kill(KJob::EmitResult));
215 
216         QCOMPARE(subjobDoneSpy.size(), 1);
217         QCOMPARE(subjob2DoneSpy.size(), 0);
218 
219         // Note that killing a subjob aborts the whole parent job
220         // Since the session only knows about the parent
221         QCOMPARE(parentJobDoneSpy.size(), 1);
222 
223         // session needs to reconnect, then execute the next job
224         QSignalSpy nextJobAboutToStartSpy(nextJob, &Job::aboutToStart);
225         QVERIFY(nextJobAboutToStartSpy.wait());
226         QCOMPARE(sessionReconnectSpy.size(), 2);
227         nextJob->done();
228 
229         QCOMPARE(subjob2DoneSpy.size(), 0);
230         QCOMPARE(nextJobDoneSpy.size(), 1);
231     }
232 };
233 
234 QTEST_AKONADIMAIN(JobTest)
235 
236 #include "jobtest.moc"
237