KRunner

abstractrunnertest.h
1/*
2 SPDX-FileCopyrightText: 2020 Alexander Lohnau <alexander.lohnau@gmx.de>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#ifndef KRUNNER_ABSTRACTRUNNERTEST_H
7#define KRUNNER_ABSTRACTRUNNERTEST_H
8
9#include <KPluginMetaData>
10#include <KRunner/AbstractRunner>
11#include <KRunner/RunnerManager>
12#include <QStandardPaths>
13
14#include <QSignalSpy>
15#include <QTest>
16#if KRUNNER_DBUS_RUNNER_TESTING
17#include <QDBusConnection>
18#include <QDBusConnectionInterface>
19#include <QDBusServiceWatcher>
20#include <QProcess>
21#include <QTimer>
22#endif
23
24namespace KRunner
25{
26/**
27 * This class provides a basic structure for a runner test.
28 * The compile definitions should be configured using the `krunner_configure_test` cmake macro
29 * @since 5.80
30 */
32{
33public:
34 using QObject::QObject;
35 std::unique_ptr<KRunner::RunnerManager> manager = nullptr;
36 KRunner::AbstractRunner *runner = nullptr;
37
38 /**
39 * Load the runner and set the manager and runner properties.
40 */
42 {
43 qputenv("LC_ALL", "C.utf-8");
44 manager.reset(new KRunner::RunnerManager());
45
46#if KRUNNER_DBUS_RUNNER_TESTING
47 auto md = manager->convertDBusRunnerToJson(QStringLiteral(KRUNNER_TEST_DESKTOP_FILE));
48 QVERIFY(md.isValid());
49 manager->loadRunner(md);
50#else
51 const QString pluginId = QFileInfo(QStringLiteral(KRUNNER_TEST_RUNNER_PLUGIN_NAME)).completeBaseName();
52 auto metaData = KPluginMetaData::findPluginById(QStringLiteral(KRUNNER_TEST_RUNNER_PLUGIN_DIR), pluginId);
53 QVERIFY2(metaData.isValid(),
54 qPrintable(QStringLiteral("Could not find plugin %1 in folder %2").arg(pluginId, QStringLiteral(KRUNNER_TEST_RUNNER_PLUGIN_DIR))));
55
56 // Set internal variables
57 manager->loadRunner(metaData);
58#endif
59 QCOMPARE(manager->runners().count(), 1);
60 runner = manager->runners().constFirst();
61
62 // Just make sure all went well
63 QVERIFY(runner);
64 }
65
66 /**
67 * Launch a query and wait for the RunnerManager to finish
68 * @param query
69 * @param runnerName
70 * @return matches of the current query
71 */
72 QList<QueryMatch> launchQuery(const QString &query, const QString &runnerName = QString())
73 {
75 manager->launchQuery(query, runnerName);
76 if (!QTest::qVerify(spy.wait(), "spy.wait()", "RunnerManager did not emit the queryFinished signal", __FILE__, __LINE__)) {
77 return {};
78 }
79 return manager->matches();
80 }
81#if KRUNNER_DBUS_RUNNER_TESTING
82 /**
83 * Launch the configured DBus executable with the given arguments and wait for the process to be started.
84 * @param args
85 * @param waitForService Wait for this service to be registered, this will default to the service from the metadata
86 * @return Process that was successfully started
87 */
88 QProcess *startDBusRunnerProcess(const QStringList &args = {}, const QString waitForService = QString())
89 {
90 qputenv("LC_ALL", "C.utf-8");
91 QProcess *process = new QProcess();
92 auto md = manager->convertDBusRunnerToJson(QStringLiteral(KRUNNER_TEST_DESKTOP_FILE));
93 QString serviceToWatch = waitForService;
94 if (serviceToWatch.isEmpty()) {
95 serviceToWatch = md.value(QStringLiteral("X-Plasma-DBusRunner-Service"));
96 }
97 QEventLoop loop;
98 // Wait for the service to show up. Same logic as the dbusrunner
101 &loop,
102 [&loop, serviceToWatch](const QString &serviceName, const QString &, const QString &newOwner) {
103 if (serviceName == serviceToWatch && !newOwner.isEmpty()) {
104 loop.quit();
105 }
106 });
107
108 // Otherwise, we just wait forever without any indication what we are waiting for
109 QTimer::singleShot(10000, &loop, [&loop, process]() {
110 loop.quit();
111
112 if (process->state() == QProcess::ProcessState::NotRunning) {
113 qWarning() << "stderr of" << KRUNNER_TEST_DBUS_EXECUTABLE << "is:";
114 qWarning().noquote() << process->readAllStandardError();
115 }
116 Q_ASSERT_X(false, "AbstractRunnerTest::startDBusRunnerProcess", "DBus service was not registered within 10 seconds");
117 });
118 process->start(QStringLiteral(KRUNNER_TEST_DBUS_EXECUTABLE), args);
119 loop.exec();
120 process->waitForStarted(5);
121
122 Q_ASSERT(process->state() == QProcess::ProcessState::Running);
123 m_runningProcesses << process;
124 return process;
125 }
126
127 /**
128 * Kill all processes that got started with the startDBusRunnerProcess
129 */
130 void killRunningDBusProcesses()
131 {
132 for (auto &process : std::as_const(m_runningProcesses)) {
133 process->kill();
134 QVERIFY(process->waitForFinished());
136 qWarning().noquote() << "Output from " << process->program() << ": " << process->readAll();
137 }
138 }
139 qDeleteAll(m_runningProcesses);
140 m_runningProcesses.clear();
141 }
142
143private:
144 QList<QProcess *> m_runningProcesses;
145#endif
146};
147}
148
149#endif
static KPluginMetaData findPluginById(const QString &directory, const QString &pluginId, KPluginMetaDataOptions options={})
This class provides a basic structure for a runner test.
void initProperties()
Load the runner and set the manager and runner properties.
QList< QueryMatch > launchQuery(const QString &query, const QString &runnerName=QString())
Launch a query and wait for the RunnerManager to finish.
An abstract base class for Plasma Runner plugins.
The RunnerManager class decides what installed runners are runnable, and their ratings.
void queryFinished()
Emitted when the launchQuery finish.
QDBusConnection sessionBus()
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
int exec(ProcessEventsFlags flags)
void quit()
QString completeBaseName() const const
QByteArray readAll()
QObject(QObject *parent)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void kill()
QString program() const const
void start(OpenMode mode)
QProcess::ProcessState state() const const
bool waitForFinished(int msecs)
bool waitForStarted(int msecs)
bool wait(int timeout)
bool isEmpty() const const
QVERIFY(condition)
bool currentTestFailed()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:51:25 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.