File indexing completed on 2024-05-12 05:11:09
0001 /* 0002 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "racetest.h" 0008 0009 #include <KProcess> 0010 #include <QDebug> 0011 0012 #include <Akonadi/AgentInstance> 0013 #include <Akonadi/AgentInstanceCreateJob> 0014 #include <Akonadi/AgentManager> 0015 #include <Akonadi/AgentType> 0016 #include <akonadi/qtest_akonadi.h> 0017 #include <control.h> 0018 //#include <localfolders.h> 0019 0020 #define TIMEOUT_SECONDS 20 0021 #define MAXCOUNT 10 0022 // NOTE: REQUESTER_EXE is defined by cmake. 0023 0024 Q_DECLARE_METATYPE(QProcess::ProcessError) 0025 Q_DECLARE_METATYPE(QProcess::ExitStatus) 0026 0027 using namespace Akonadi; 0028 0029 void RaceTest::initTestCase() 0030 { 0031 QVERIFY(Control::start()); 0032 QTest::qWait(1000); // give the MDA time to start so that we can kill it in peace 0033 qRegisterMetaType<QProcess::ProcessError>(); 0034 qRegisterMetaType<QProcess::ExitStatus>(); 0035 } 0036 0037 void RaceTest::testMultipleProcesses_data() 0038 { 0039 QTest::addColumn<int>("count"); // how many processes to create 0040 QTest::addColumn<int>("delay"); // number of ms to wait before starting next process 0041 0042 QTest::newRow("1-nodelay") << 1 << 0; 0043 QTest::newRow("2-nodelay") << 2 << 0; 0044 QTest::newRow("5-nodelay") << 5 << 0; 0045 QTest::newRow("10-nodelay") << 10 << 0; 0046 QTest::newRow("2-shortdelay") << 2 << 100; 0047 QTest::newRow("5-shortdelay") << 5 << 100; 0048 QTest::newRow("10-shortdelay") << 10 << 100; 0049 QTest::newRow("2-longdelay") << 2 << 1000; 0050 QTest::newRow("5-longdelay") << 5 << 1000; 0051 QTest::newRow("5-verylongdelay") << 5 << 4000; 0052 Q_ASSERT(10 <= MAXCOUNT); 0053 } 0054 0055 void RaceTest::testMultipleProcesses() 0056 { 0057 QFETCH(int, count); 0058 QFETCH(int, delay); 0059 0060 killZombies(); 0061 0062 // Remove all maildir instances (at most 1 really) and MDAs (which use LocalFolders). 0063 // (This is to ensure that one of *our* instances is the main instance.) 0064 AgentType::List types; 0065 types.append(AgentManager::self()->type(QLatin1StringView("akonadi_maildir_resource"))); 0066 types.append(AgentManager::self()->type(QLatin1StringView("akonadi_maildispatcher_agent"))); 0067 AgentInstance::List instances = AgentManager::self()->instances(); 0068 for (const AgentInstance &instance : std::as_const(instances)) { 0069 if (types.contains(instance.type())) { 0070 qDebug() << "Removing instance of type" << instance.type().identifier(); 0071 AgentManager::self()->removeInstance(instance); 0072 QSignalSpy removedSpy(AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance))); 0073 QVERIFY(removedSpy.wait()); 0074 } 0075 } 0076 instances = AgentManager::self()->instances(); 0077 for (const AgentInstance &instance : std::as_const(instances)) { 0078 QVERIFY(!types.contains(instance.type())); 0079 } 0080 0081 QSignalSpy *errorSpy[MAXCOUNT]; 0082 QSignalSpy *finishedSpy[MAXCOUNT]; 0083 for (int i = 0; i < count; i++) { 0084 qDebug() << "Starting process" << i + 1 << "of" << count; 0085 KProcess *proc = new KProcess; 0086 procs.append(proc); 0087 proc->setProgram(QStringLiteral(REQUESTER_EXE)); 0088 errorSpy[i] = new QSignalSpy(proc, SIGNAL(error(QProcess::ProcessError))); 0089 finishedSpy[i] = new QSignalSpy(proc, SIGNAL(finished(int, QProcess::ExitStatus))); 0090 proc->start(); 0091 QTest::qWait(delay); 0092 } 0093 qDebug() << "Launched" << count << "processes."; 0094 0095 int seconds = 0; 0096 int error, finished; 0097 while (true) { 0098 seconds++; 0099 QTest::qWait(1000); 0100 0101 error = 0; 0102 finished = 0; 0103 for (int i = 0; i < count; i++) { 0104 if (errorSpy[i]->count() > 0) { 0105 error++; 0106 } 0107 if (finishedSpy[i]->count() > 0) { 0108 finished++; 0109 } 0110 } 0111 qDebug() << seconds << "seconds elapsed." << error << "processes error'd," << finished << "processes finished."; 0112 0113 if (error + finished >= count) { 0114 break; 0115 } 0116 0117 #if 0 0118 if (seconds >= TIMEOUT_SECONDS) { 0119 qDebug() << "Timeout, gdb master!"; 0120 QTest::qWait(1000 * 1000); 0121 } 0122 #endif 0123 QVERIFY2(seconds < TIMEOUT_SECONDS, "Timeout"); 0124 } 0125 0126 QCOMPARE(error, 0); 0127 QCOMPARE(finished, count); 0128 for (int i = 0; i < count; i++) { 0129 qDebug() << "Checking exit status of process" << i + 1 << "of" << count; 0130 QCOMPARE(finishedSpy[i]->count(), 1); 0131 QList<QVariant> args = finishedSpy[i]->takeFirst(); 0132 if (args[0].toInt() != 2) { 0133 qDebug() << "Exit status" << args[0].toInt() << ", expected 2. Timeout, gdb master!"; 0134 QTest::qWait(1000 * 1000); 0135 } 0136 QCOMPARE(args[0].toInt(), 2); 0137 } 0138 0139 while (!procs.isEmpty()) { 0140 KProcess *proc = procs.takeFirst(); 0141 QCOMPARE(proc->exitStatus(), QProcess::NormalExit); 0142 QCOMPARE(proc->exitCode(), 2); 0143 delete proc; 0144 } 0145 QVERIFY(procs.isEmpty()); 0146 } 0147 0148 void RaceTest::killZombies() 0149 { 0150 while (!procs.isEmpty()) { 0151 // These processes probably hung, and will never recover, so we need to kill them. 0152 // (This happens if the last test failed.) 0153 qDebug() << "Killing zombies from the past."; 0154 KProcess *proc = procs.takeFirst(); 0155 proc->kill(); 0156 proc->deleteLater(); 0157 } 0158 } 0159 0160 QTEST_AKONADIMAIN(RaceTest) 0161 0162 #include "moc_racetest.cpp"