File indexing completed on 2024-04-28 16:49:46
0001 /* 0002 SPDX-FileCopyrightText: 2007 John Tapsell <tapsell@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <QDebug> 0008 #include <QTreeView> 0009 #include <QtCore> 0010 #include <QtTestGui> 0011 #include <QProcess> 0012 0013 #include <limits> 0014 0015 #include "processcore/process.h" 0016 #include "processcore/processes.h" 0017 #include "processcore/processes_base_p.h" 0018 #include "processcore_debug.h" 0019 0020 #include "processui/ksysguardprocesslist.h" 0021 0022 #include "processtest.h" 0023 0024 Q_DECLARE_METATYPE(KSysGuard::Process::Scheduler); 0025 Q_DECLARE_METATYPE(KSysGuard::Process::IoPriorityClass); 0026 0027 void testProcess::testSetScheduler_data() 0028 { 0029 QTest::addColumn<int>("priority"); 0030 QTest::addColumn<KSysGuard::Process::Scheduler>("scheduler"); 0031 QTest::addColumn<bool>("niceness"); 0032 0033 QTest::addRow("normal, 0") << 0 << KSysGuard::Process::Scheduler::Other << true; 0034 QTest::addRow("normal, 5") << 5 << KSysGuard::Process::Scheduler::Other << true; 0035 0036 QTest::addRow("batch, 0") << 0 << KSysGuard::Process::Scheduler::Batch << true; 0037 QTest::addRow("batch, 5") << 5 << KSysGuard::Process::Scheduler::Batch << true; 0038 0039 QTest::addRow("idle, 0") << 0 << KSysGuard::Process::Scheduler::SchedulerIdle << false; 0040 0041 QTest::addRow("rr, 5") << 5 << KSysGuard::Process::Scheduler::RoundRobin << false; 0042 0043 QTest::addRow("fifo, 5") << 5 << KSysGuard::Process::Scheduler::Fifo << false; 0044 } 0045 0046 void testProcess::testSetScheduler() 0047 { 0048 QFETCH(int, priority); 0049 QFETCH(KSysGuard::Process::Scheduler, scheduler); 0050 QFETCH(bool, niceness); 0051 0052 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0053 0054 QProcess proc; 0055 proc.start(QStringLiteral("sleep"), {QStringLiteral("100")}); 0056 QVERIFY(proc.waitForStarted()); 0057 0058 int pid=proc.processId(); 0059 QVERIFY(pid); 0060 0061 if (!processController->setScheduler(pid, scheduler, priority)) 0062 QSKIP("skipping verfifcation because setScheduler failed"); 0063 0064 if (niceness && !processController->setNiceness(pid, priority)) 0065 QSKIP("skipping verfifcation because setNiceness failed"); 0066 0067 processController->updateAllProcesses(); 0068 KSysGuard::Process* process = processController->getProcess(pid); 0069 0070 QVERIFY(process); 0071 QCOMPARE(process->scheduler(), scheduler); 0072 QCOMPARE(process->niceLevel(), priority); 0073 } 0074 0075 void testProcess::testSetIoScheduler_data() 0076 { 0077 QTest::addColumn<int>("priority"); 0078 QTest::addColumn<KSysGuard::Process::IoPriorityClass>("prioClass"); 0079 0080 QTest::addRow("idle, 0") << 0 << KSysGuard::Process::Idle; 0081 QTest::addRow("idle, 5") << 5 << KSysGuard::Process::Idle; 0082 0083 QTest::addRow("best-effort, 0") << 0 << KSysGuard::Process::BestEffort; 0084 QTest::addRow("best-effort, 5") << 5 << KSysGuard::Process::BestEffort; 0085 0086 QTest::addRow("rt, 0") << 0 << KSysGuard::Process::RealTime; 0087 QTest::addRow("rt, 5") << 5 << KSysGuard::Process::RealTime; 0088 } 0089 0090 void testProcess::testSetIoScheduler() 0091 { 0092 QFETCH(int, priority); 0093 QFETCH(KSysGuard::Process::IoPriorityClass, prioClass); 0094 0095 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0096 0097 QProcess proc; 0098 proc.start(QStringLiteral("sleep"), {QStringLiteral("100")}); 0099 QVERIFY(proc.waitForStarted()); 0100 0101 int pid=proc.processId(); 0102 QVERIFY(pid); 0103 0104 if (!processController->setIoNiceness(pid, prioClass, priority)) 0105 QSKIP("skipping verfifcation because setNiceness failed"); 0106 0107 processController->updateAllProcesses(); 0108 KSysGuard::Process* process = processController->getProcess(pid); 0109 0110 QVERIFY(process); 0111 QCOMPARE(process->ioPriorityClass(), prioClass); 0112 QCOMPARE(process->ioniceLevel(), priority); 0113 } 0114 0115 void testProcess::testProcesses() 0116 { 0117 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0118 processController->updateAllProcesses(); 0119 const QList<KSysGuard::Process *> processes = processController->getAllProcesses(); 0120 QSet<long> pids; 0121 for (KSysGuard::Process *process : processes) { 0122 if (process->pid() == 0) 0123 continue; 0124 QVERIFY(process->pid() > 0); 0125 QVERIFY(!process->name().isEmpty()); 0126 0127 // test all the pids are unique 0128 QVERIFY(!pids.contains(process->pid())); 0129 pids.insert(process->pid()); 0130 } 0131 processController->updateAllProcesses(); 0132 const QList<KSysGuard::Process *> processes2 = processController->getAllProcesses(); 0133 for (KSysGuard::Process *process : processes2) { 0134 if (process->pid() == 0) 0135 continue; 0136 QVERIFY(process->pid() > 0); 0137 QVERIFY(!process->name().isEmpty()); 0138 0139 // test all the pids are unique 0140 if (!pids.contains(process->pid())) { 0141 qCDebug(LIBKSYSGUARD_PROCESSCORE) << process->pid() << " not found. " << process->name(); 0142 } 0143 pids.remove(process->pid()); 0144 } 0145 0146 QVERIFY(processes2.size() == processes.size()); 0147 QCOMPARE(processes, 0148 processes2); // Make sure calling it twice gives the same results. The difference in time is so small that it really shouldn't have changed 0149 delete processController; 0150 } 0151 0152 unsigned long testProcess::countNumChildren(KSysGuard::Process *p) 0153 { 0154 unsigned long total = p->children().size(); 0155 for (int i = 0; i < p->children().size(); i++) { 0156 total += countNumChildren(p->children()[i]); 0157 } 0158 return total; 0159 } 0160 0161 void testProcess::testProcessesTreeStructure() 0162 { 0163 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0164 processController->updateAllProcesses(); 0165 0166 auto verify_counts = [this](const auto processes) { 0167 for (KSysGuard::Process *process : processes) { 0168 QCOMPARE(countNumChildren(process), process->numChildren()); 0169 0170 for(int i = 0; i < process->children().size(); i++) { 0171 QVERIFY(process->children()[i]->parent()); 0172 QCOMPARE(process->children()[i]->parent(), process); 0173 } 0174 } 0175 }; 0176 0177 verify_counts(processController->getAllProcesses()); 0178 0179 // this should test if the children accounting isn't off on updates 0180 QProcess proc; 0181 proc.start(QStringLiteral("/bin/sh"), {QStringLiteral("-c"), QStringLiteral("sleep 100& (sleep 50; sleep 50) & while true; do :; done")}); 0182 QVERIFY(proc.waitForStarted()); 0183 QTest::qSleep(2000); 0184 0185 processController->updateAllProcesses(); 0186 verify_counts(processController->getAllProcesses()); 0187 0188 proc.terminate(); 0189 0190 QVERIFY(proc.waitForFinished()); 0191 processController->updateAllProcesses(); 0192 verify_counts(processController->getAllProcesses()); 0193 0194 delete processController; 0195 } 0196 0197 void testProcess::testProcessesModification() 0198 { 0199 // We will modify the tree, then re-call getProcesses and make sure that it fixed everything we modified 0200 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0201 processController->updateAllProcesses(); 0202 KSysGuard::Process *initProcess = processController->getProcess(1); 0203 0204 if (!initProcess || initProcess->numChildren() < 3) { 0205 delete processController; 0206 return; 0207 } 0208 0209 QVERIFY(initProcess); 0210 QVERIFY(initProcess->children()[0]); 0211 QVERIFY(initProcess->children()[1]); 0212 qCDebug(LIBKSYSGUARD_PROCESSCORE) << initProcess->numChildren(); 0213 initProcess->children()[0]->setParent(initProcess->children()[1]); 0214 initProcess->children()[1]->children().append(initProcess->children()[0]); 0215 initProcess->children()[1]->numChildren()++; 0216 initProcess->numChildren()--; 0217 initProcess->children().removeAt(0); 0218 delete processController; 0219 } 0220 0221 void testProcess::testTimeToUpdateAllProcesses() 0222 { 0223 // See how long it takes to get process information 0224 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0225 QBENCHMARK { 0226 processController->updateAllProcesses(); 0227 } 0228 delete processController; 0229 } 0230 void testProcess::testTimeToUpdateModel() 0231 { 0232 KSysGuardProcessList *processList = new KSysGuardProcessList; 0233 processList->treeView()->setColumnHidden(13, false); 0234 processList->show(); 0235 QVERIFY(QTest::qWaitForWindowExposed(processList)); 0236 0237 QBENCHMARK { 0238 processList->updateList(); 0239 QTest::qWait(0); 0240 } 0241 delete processList; 0242 } 0243 0244 void testProcess::testHistories() 0245 { 0246 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0247 QBENCHMARK_ONCE { 0248 if (!processController->isHistoryAvailable()) { 0249 qWarning("History was not available"); 0250 delete processController; 0251 return; 0252 } 0253 } 0254 QCOMPARE(processController->historyFileName(), QStringLiteral("/var/log/atop.log")); 0255 QList<QPair<QDateTime, uint>> history = processController->historiesAvailable(); 0256 bool success = processController->setViewingTime(history[0].first); 0257 QVERIFY(success); 0258 QVERIFY(processController->viewingTime() == history[0].first); 0259 success = processController->setViewingTime(history[0].first.addSecs(-1)); 0260 QVERIFY(success); 0261 QVERIFY(processController->viewingTime() == history[0].first); 0262 success = processController->setViewingTime(history[0].first.addSecs(-history[0].second - 1)); 0263 QVERIFY(!success); 0264 QVERIFY(processController->viewingTime() == history[0].first); 0265 QCOMPARE(processController->historyFileName(), QStringLiteral("/var/log/atop.log")); 0266 0267 // Test the tree structure 0268 processController->updateAllProcesses(); 0269 const QList<KSysGuard::Process *> processes = processController->getAllProcesses(); 0270 0271 for (KSysGuard::Process *process : processes) { 0272 QCOMPARE(countNumChildren(process), process->numChildren()); 0273 0274 for (int i = 0; i < process->children().size(); i++) { 0275 QVERIFY(process->children()[i]->parent()); 0276 QCOMPARE(process->children()[i]->parent(), process); 0277 } 0278 } 0279 0280 // test all the pids are unique 0281 QSet<long> pids; 0282 for (KSysGuard::Process *process : processes) { 0283 if (process->pid() == 0) 0284 continue; 0285 QVERIFY(process->pid() > 0); 0286 QVERIFY(!process->name().isEmpty()); 0287 0288 QVERIFY(!pids.contains(process->pid())); 0289 pids.insert(process->pid()); 0290 } 0291 delete processController; 0292 } 0293 0294 void testProcess::testUpdateOrAddProcess() 0295 { 0296 KSysGuard::Processes *processController = new KSysGuard::Processes(); 0297 processController->updateAllProcesses(); 0298 KSysGuard::Process *process; 0299 // Make sure that this doesn't crash at least 0300 process = processController->getProcess(0); 0301 process = processController->getProcess(1); 0302 if (process) 0303 QCOMPARE(process->pid(), 1l); 0304 0305 // Make sure that this doesn't crash at least 0306 processController->updateOrAddProcess(1); 0307 processController->updateOrAddProcess(0); 0308 processController->updateOrAddProcess(-1); 0309 0310 processController->updateOrAddProcess(std::numeric_limits<long>::max()-1); 0311 QVERIFY(processController->getProcess(std::numeric_limits<long>::max()-1)); 0312 processController->updateAllProcesses(); 0313 QVERIFY(processController->getProcess(std::numeric_limits<long>::max()-1)); 0314 QCOMPARE(processController->getProcess(std::numeric_limits<long>::max()-1)->status(), KSysGuard::Process::Ended); 0315 processController->updateAllProcesses(); 0316 QVERIFY(!processController->getProcess(std::numeric_limits<long>::max()-1)); 0317 } 0318 0319 void testProcess::testHistoriesWithWidget() 0320 { 0321 KSysGuardProcessList *processList = new KSysGuardProcessList; 0322 processList->treeView()->setColumnHidden(13, false); 0323 processList->show(); 0324 QVERIFY(QTest::qWaitForWindowExposed(processList)); 0325 KSysGuard::Processes *processController = processList->processModel()->processController(); 0326 0327 QList<QPair<QDateTime, uint>> history = processController->historiesAvailable(); 0328 0329 for (int i = 0; i < history.size(); i++) { 0330 qCDebug(LIBKSYSGUARD_PROCESSCORE) << "Viewing time" << history[i].first; 0331 bool success = processController->setViewingTime(history[i].first); 0332 QVERIFY(success); 0333 QCOMPARE(processController->viewingTime(), history[i].first); 0334 processList->updateList(); 0335 QTest::qWait(100); 0336 } 0337 delete processList; 0338 } 0339 0340 void testProcess::testCPUGraphHistory() 0341 { 0342 KSysGuardProcessList processList; 0343 processList.show(); 0344 QVERIFY(QTest::qWaitForWindowExposed(&processList)); 0345 auto model = processList.processModel(); 0346 // Access the PercentageHistoryRole to enable collection 0347 for (int i = 0; i < model->rowCount(); i++) { 0348 auto index = model->index(i, ProcessModel::HeadingCPUUsage, {}); 0349 auto percentageHist = index.data(ProcessModel::PercentageHistoryRole).value<QVector<ProcessModel::PercentageHistoryEntry>>(); 0350 } 0351 0352 processList.updateList(); 0353 0354 // Verify that the current value is the newest history entry 0355 for (int i = 0; i < model->rowCount(); i++) { 0356 auto index = model->index(i, ProcessModel::HeadingCPUUsage, {}); 0357 auto percentage = index.data(ProcessModel::PercentageRole).toFloat(); 0358 auto percentageHist = index.data(ProcessModel::PercentageHistoryRole).value<QVector<ProcessModel::PercentageHistoryEntry>>(); 0359 QVERIFY(percentageHist.size() > 0); 0360 QCOMPARE(percentage, percentageHist.constLast().value); 0361 } 0362 } 0363 0364 QTEST_MAIN(testProcess)