mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-03-26 17:03:08 +00:00
tests: add ProcessScanner stability test
Add a new QtTest that spawns marker processes and verifies ProcessScanner::scan() matches by env/cmdline, preferEnvironmentMatches behavior, and cancellation. Register the test with ctest.
This commit is contained in:
parent
f03eb95b52
commit
5b26b85cc3
2 changed files with 226 additions and 0 deletions
|
|
@ -43,3 +43,27 @@ add_test(NAME alakarte_stop_launching_regression_test
|
|||
set_tests_properties(alakarte_stop_launching_regression_test PROPERTIES
|
||||
TIMEOUT 60
|
||||
)
|
||||
|
||||
add_executable(alakarte_processscanner_test
|
||||
processscanner_test.cpp
|
||||
../src/gamecenter/processscanner.cpp
|
||||
../src/gamecenter/processscanner.h
|
||||
)
|
||||
|
||||
target_include_directories(alakarte_processscanner_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src/gamecenter
|
||||
)
|
||||
|
||||
target_link_libraries(alakarte_processscanner_test PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Concurrent
|
||||
Qt6::Test
|
||||
)
|
||||
|
||||
add_test(NAME alakarte_processscanner_test
|
||||
COMMAND alakarte_processscanner_test
|
||||
)
|
||||
|
||||
set_tests_properties(alakarte_processscanner_test PROPERTIES
|
||||
TIMEOUT 20
|
||||
)
|
||||
|
|
|
|||
202
tests/processscanner_test.cpp
Normal file
202
tests/processscanner_test.cpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2026 A-La-Karte Contributors
|
||||
|
||||
#include "processscanner.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QStandardPaths>
|
||||
#include <QString>
|
||||
#include <QUuid>
|
||||
#include <QtTest>
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
class ProcessScannerTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
void scanFindsEnvAndCmdline();
|
||||
void preferEnvironmentMatchesFilters();
|
||||
void cancelledScanReturnsEmpty();
|
||||
|
||||
private:
|
||||
QString m_shell;
|
||||
QString m_marker;
|
||||
QProcess m_envProc;
|
||||
QProcess m_cmdProc;
|
||||
|
||||
static bool containsPid(const QList<ProcessScanner::Match> &matches, qint64 pid)
|
||||
{
|
||||
for (const auto &m : matches) {
|
||||
if (m.pid == static_cast<uint>(pid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const ProcessScanner::Match *findByPid(const QList<ProcessScanner::Match> &matches, qint64 pid)
|
||||
{
|
||||
for (const auto &m : matches) {
|
||||
if (m.pid == static_cast<uint>(pid)) {
|
||||
return &m;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool waitForScan(std::function<bool()> predicate, int timeoutMs)
|
||||
{
|
||||
QElapsedTimer t;
|
||||
t.start();
|
||||
while (t.elapsed() < timeoutMs) {
|
||||
if (predicate()) {
|
||||
return true;
|
||||
}
|
||||
QTest::qWait(50);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void startProcesses();
|
||||
void stopProcess(QProcess &p);
|
||||
};
|
||||
|
||||
void ProcessScannerTest::initTestCase()
|
||||
{
|
||||
if (!QFileInfo(QStringLiteral("/proc")).isDir()) {
|
||||
QSKIP("/proc not available");
|
||||
}
|
||||
|
||||
m_shell = QStandardPaths::findExecutable(QStringLiteral("sh"));
|
||||
if (m_shell.isEmpty()) {
|
||||
QSKIP("sh not found");
|
||||
}
|
||||
|
||||
m_marker = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
startProcesses();
|
||||
}
|
||||
|
||||
void ProcessScannerTest::cleanupTestCase()
|
||||
{
|
||||
stopProcess(m_envProc);
|
||||
stopProcess(m_cmdProc);
|
||||
}
|
||||
|
||||
void ProcessScannerTest::startProcesses()
|
||||
{
|
||||
const QString script = QStringLiteral("while true; do sleep 60; done # %1").arg(m_marker);
|
||||
|
||||
{
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert(QStringLiteral("ALAKARTE_PROCESSSCANNER_TEST_MARKER"), m_marker);
|
||||
m_envProc.setProcessEnvironment(env);
|
||||
m_envProc.start(m_shell, {QStringLiteral("-c"), script});
|
||||
QVERIFY2(m_envProc.waitForStarted(5000), qPrintable(m_envProc.errorString()));
|
||||
QVERIFY(m_envProc.processId() > 0);
|
||||
}
|
||||
|
||||
{
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
m_cmdProc.setProcessEnvironment(env);
|
||||
m_cmdProc.start(m_shell, {QStringLiteral("-c"), script});
|
||||
QVERIFY2(m_cmdProc.waitForStarted(5000), qPrintable(m_cmdProc.errorString()));
|
||||
QVERIFY(m_cmdProc.processId() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessScannerTest::stopProcess(QProcess &p)
|
||||
{
|
||||
if (p.state() == QProcess::NotRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
p.terminate();
|
||||
if (!p.waitForFinished(3000)) {
|
||||
p.kill();
|
||||
p.waitForFinished(3000);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessScannerTest::scanFindsEnvAndCmdline()
|
||||
{
|
||||
QVERIFY(m_envProc.processId() > 0);
|
||||
QVERIFY(m_cmdProc.processId() > 0);
|
||||
|
||||
ProcessScanner::ScanOptions opts;
|
||||
opts.envKeys = {QStringLiteral("ALAKARTE_PROCESSSCANNER_TEST_MARKER")};
|
||||
opts.envValue = m_marker;
|
||||
opts.cmdlineSubstring = m_marker;
|
||||
opts.preferEnvironmentMatches = false;
|
||||
|
||||
QList<ProcessScanner::Match> results;
|
||||
const bool ok = waitForScan(
|
||||
[&]() {
|
||||
results = ProcessScanner::scan(opts);
|
||||
return containsPid(results, m_envProc.processId()) && containsPid(results, m_cmdProc.processId());
|
||||
},
|
||||
5000);
|
||||
|
||||
QVERIFY(ok);
|
||||
|
||||
const auto *envMatch = findByPid(results, m_envProc.processId());
|
||||
QVERIFY(envMatch);
|
||||
QVERIFY(envMatch->envMatched);
|
||||
|
||||
const auto *cmdMatch = findByPid(results, m_cmdProc.processId());
|
||||
QVERIFY(cmdMatch);
|
||||
QVERIFY(!cmdMatch->envMatched);
|
||||
}
|
||||
|
||||
void ProcessScannerTest::preferEnvironmentMatchesFilters()
|
||||
{
|
||||
QVERIFY(m_envProc.processId() > 0);
|
||||
QVERIFY(m_cmdProc.processId() > 0);
|
||||
|
||||
ProcessScanner::ScanOptions opts;
|
||||
opts.envKeys = {QStringLiteral("ALAKARTE_PROCESSSCANNER_TEST_MARKER")};
|
||||
opts.envValue = m_marker;
|
||||
opts.cmdlineSubstring = m_marker;
|
||||
opts.preferEnvironmentMatches = true;
|
||||
|
||||
QList<ProcessScanner::Match> results;
|
||||
const bool ok = waitForScan(
|
||||
[&]() {
|
||||
results = ProcessScanner::scan(opts);
|
||||
return containsPid(results, m_envProc.processId());
|
||||
},
|
||||
5000);
|
||||
|
||||
QVERIFY(ok);
|
||||
QVERIFY(containsPid(results, m_envProc.processId()));
|
||||
QVERIFY(!containsPid(results, m_cmdProc.processId()));
|
||||
|
||||
for (const auto &m : std::as_const(results)) {
|
||||
QVERIFY(m.envMatched);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessScannerTest::cancelledScanReturnsEmpty()
|
||||
{
|
||||
ProcessScanner::ScanOptions opts;
|
||||
opts.envKeys = {QStringLiteral("ALAKARTE_PROCESSSCANNER_TEST_MARKER")};
|
||||
opts.envValue = m_marker;
|
||||
opts.cmdlineSubstring = m_marker;
|
||||
opts.preferEnvironmentMatches = false;
|
||||
|
||||
const std::atomic_bool cancelled(true);
|
||||
const QList<ProcessScanner::Match> results = ProcessScanner::scan(opts, cancelled);
|
||||
QVERIFY(results.isEmpty());
|
||||
}
|
||||
|
||||
QTEST_MAIN(ProcessScannerTest)
|
||||
|
||||
#include "processscanner_test.moc"
|
||||
Loading…
Reference in a new issue