File indexing completed on 2024-12-22 04:56:51

0001 /*
0002  * SPDX-FileCopyrightText: 2013 Christian Mollekopf <mollekopf@kolabsys.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  *
0006  */
0007 
0008 #include <KJobTrackerInterface>
0009 #include <QDebug>
0010 #include <QSignalSpy>
0011 #include <QTest>
0012 
0013 #include "../migrationscheduler.h"
0014 #include "migration/migratorbase.h"
0015 
0016 Q_DECLARE_METATYPE(QModelIndex)
0017 
0018 class Testmigrator : public MigratorBase
0019 {
0020     Q_OBJECT
0021 public:
0022     explicit Testmigrator(const QString &identifier, QObject *parent = nullptr)
0023         : MigratorBase(QLatin1StringView("testmigrator") + identifier, QString(), QString(), parent)
0024         , mAutostart(false)
0025     {
0026     }
0027 
0028     [[nodiscard]] QString displayName() const override
0029     {
0030         return QStringLiteral("name");
0031     }
0032 
0033     void startWork() override
0034     {
0035     }
0036 
0037     void abort() override
0038     {
0039         setMigrationState(Aborted);
0040     }
0041 
0042     virtual void complete()
0043     {
0044         setMigrationState(Complete);
0045     }
0046 
0047     [[nodiscard]] bool shouldAutostart() const override
0048     {
0049         return mAutostart;
0050     }
0051 
0052     void pause() override
0053     {
0054         setMigrationState(Paused);
0055     }
0056 
0057     void resume() override
0058     {
0059         setMigrationState(InProgress);
0060     }
0061 
0062     bool mAutostart;
0063 };
0064 
0065 class TestJobTracker : public KJobTrackerInterface
0066 {
0067 public:
0068     TestJobTracker()
0069         : mPercent(0)
0070     {
0071     }
0072 
0073     void registerJob(KJob *job) override
0074     {
0075         KJobTrackerInterface::registerJob(job);
0076         mJobs << job;
0077     }
0078 
0079     void unregisterJob(KJob *job) override
0080     {
0081         mJobs.removeAll(job);
0082     }
0083 
0084     void finished(KJob *job) override
0085     {
0086         mJobs.removeAll(job);
0087     }
0088 
0089     void percent(KJob *job, long unsigned int percent) override
0090     {
0091         Q_UNUSED(job)
0092         mPercent = percent;
0093     }
0094 
0095     QList<KJob *> mJobs;
0096     int mPercent;
0097 };
0098 
0099 class SchedulerTest : public QObject
0100 {
0101     Q_OBJECT
0102 private Q_SLOTS:
0103 
0104     void initTestcase()
0105     {
0106         qRegisterMetaType<QModelIndex>();
0107     }
0108 
0109     void testInsertRow()
0110     {
0111         MigrationScheduler scheduler;
0112         QAbstractItemModel &model(scheduler.model());
0113 
0114         QCOMPARE(model.rowCount(), 0);
0115 
0116         QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
0117         QVERIFY(rowsInsertedSpy.isValid());
0118 
0119         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id"))));
0120         QCOMPARE(model.rowCount(), 1);
0121         QCOMPARE(rowsInsertedSpy.count(), 1);
0122 
0123         QVERIFY(model.index(0, 0).isValid());
0124         QVERIFY(!model.index(1, 0).isValid());
0125 
0126         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id2"))));
0127         QCOMPARE(model.rowCount(), 2);
0128         QCOMPARE(rowsInsertedSpy.count(), 2);
0129     }
0130 
0131     void testDisplayName()
0132     {
0133         MigrationScheduler scheduler;
0134         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id"))));
0135         QAbstractItemModel &model(scheduler.model());
0136         QCOMPARE(model.data(model.index(0, 0)).toString(), QStringLiteral("name"));
0137     }
0138 
0139     void testStartStop()
0140     {
0141         MigrationScheduler scheduler;
0142         QSharedPointer<Testmigrator> migrator(new Testmigrator(QStringLiteral("id")));
0143         scheduler.addMigrator(migrator);
0144 
0145         scheduler.start(migrator->identifier());
0146         QCOMPARE(migrator->migrationState(), MigratorBase::InProgress);
0147 
0148         scheduler.abort(migrator->identifier());
0149         QCOMPARE(migrator->migrationState(), MigratorBase::Aborted);
0150     }
0151 
0152     void testNoDuplicates()
0153     {
0154         MigrationScheduler scheduler;
0155         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id"))));
0156         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id"))));
0157         QAbstractItemModel &model(scheduler.model());
0158         QCOMPARE(model.rowCount(), 1);
0159     }
0160 
0161     void testMigrationStateChanged()
0162     {
0163         MigrationScheduler scheduler;
0164         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id1"))));
0165         QSharedPointer<Testmigrator> migrator(new Testmigrator(QStringLiteral("id2")));
0166         scheduler.addMigrator(migrator);
0167         scheduler.addMigrator(QSharedPointer<Testmigrator>(new Testmigrator(QStringLiteral("id3"))));
0168         QAbstractItemModel &model(scheduler.model());
0169 
0170         QSignalSpy spy(&model, &QAbstractItemModel::dataChanged);
0171         QVERIFY(spy.isValid());
0172         migrator->start();
0173 
0174         QCOMPARE(spy.count(), 1);
0175         const QVariantList args = spy.takeFirst();
0176         QCOMPARE(args.at(0).value<QModelIndex>().row(), 1);
0177         QCOMPARE(args.at(1).value<QModelIndex>().row(), 1);
0178     }
0179 
0180     void testRunMultiple()
0181     {
0182         MigrationScheduler scheduler;
0183 
0184         QSharedPointer<Testmigrator> m1(new Testmigrator(QStringLiteral("id1")));
0185         scheduler.addMigrator(m1);
0186 
0187         QSharedPointer<Testmigrator> m2(new Testmigrator(QStringLiteral("id2")));
0188         scheduler.addMigrator(m2);
0189 
0190         scheduler.start(m1->identifier());
0191         scheduler.start(m2->identifier());
0192 
0193         QCOMPARE(m1->migrationState(), MigratorBase::InProgress);
0194         QCOMPARE(m2->migrationState(), MigratorBase::InProgress);
0195     }
0196 
0197     void testRunAutostart()
0198     {
0199         MigrationScheduler scheduler;
0200 
0201         QSharedPointer<Testmigrator> m1(new Testmigrator(QStringLiteral("id1")));
0202         m1->mAutostart = true;
0203         scheduler.addMigrator(m1);
0204 
0205         QSharedPointer<Testmigrator> m2(new Testmigrator(QStringLiteral("id2")));
0206         m2->mAutostart = true;
0207         scheduler.addMigrator(m2);
0208 
0209         QCOMPARE(m1->migrationState(), MigratorBase::InProgress);
0210         qDebug() << m2->migrationState();
0211         QCOMPARE(m2->migrationState(), MigratorBase::None);
0212         m1->complete();
0213         QCOMPARE(m2->migrationState(), MigratorBase::InProgress);
0214     }
0215 
0216     void testJobTracker()
0217     {
0218         TestJobTracker jobTracker;
0219         MigrationScheduler scheduler(&jobTracker);
0220         QSharedPointer<Testmigrator> m1(new Testmigrator(QStringLiteral("id1")));
0221         m1->mAutostart = true;
0222         scheduler.addMigrator(m1);
0223 
0224         QCOMPARE(jobTracker.mJobs.size(), 1);
0225 
0226         m1->complete();
0227 
0228         // Give the job some time to delete itself
0229         QTest::qWait(500);
0230 
0231         QCOMPARE(jobTracker.mJobs.size(), 0);
0232     }
0233 
0234     void testSuspend()
0235     {
0236         TestJobTracker jobTracker;
0237         MigrationScheduler scheduler(&jobTracker);
0238         QSharedPointer<Testmigrator> m1(new Testmigrator(QStringLiteral("id1")));
0239         m1->mAutostart = true;
0240         scheduler.addMigrator(m1);
0241         jobTracker.mJobs.first()->suspend();
0242         QCOMPARE(m1->migrationState(), MigratorBase::Paused);
0243         jobTracker.mJobs.first()->resume();
0244         QCOMPARE(m1->migrationState(), MigratorBase::InProgress);
0245     }
0246 
0247     /*
0248      * Even if the migrator doesn't implement suspend, the executor suspends after completing the current job and waits with starting the second job.
0249      */
0250     void testJobFinishesDuringSuspend()
0251     {
0252         TestJobTracker jobTracker;
0253         MigrationScheduler scheduler(&jobTracker);
0254         QSharedPointer<Testmigrator> m1(new Testmigrator(QStringLiteral("id1")));
0255         m1->mAutostart = true;
0256         scheduler.addMigrator(m1);
0257         QSharedPointer<Testmigrator> m2(new Testmigrator(QStringLiteral("id2")));
0258         m2->mAutostart = true;
0259         scheduler.addMigrator(m2);
0260         jobTracker.mJobs.first()->suspend();
0261         m1->complete();
0262         QCOMPARE(m2->migrationState(), MigratorBase::None);
0263         jobTracker.mJobs.first()->resume();
0264         QCOMPARE(m2->migrationState(), MigratorBase::InProgress);
0265     }
0266 
0267     void testProgressReporting()
0268     {
0269         TestJobTracker jobTracker;
0270         MigrationScheduler scheduler(&jobTracker);
0271         QSharedPointer<Testmigrator> m1(new Testmigrator(QStringLiteral("id1")));
0272         m1->mAutostart = true;
0273         scheduler.addMigrator(m1);
0274         QCOMPARE(jobTracker.mPercent, 0);
0275         m1->complete();
0276         QCOMPARE(jobTracker.mPercent, 100);
0277     }
0278 };
0279 
0280 QTEST_MAIN(SchedulerTest)
0281 
0282 #include "schedulertest.moc"