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(), qPrintable("Could not find plugin " + pluginId + " in folder " + KRUNNER_TEST_RUNNER_PLUGIN_DIR));
54
55 // Set internal variables
56 manager->loadRunner(metaData);
57#endif
58 QCOMPARE(manager->runners().count(), 1);
59 runner = manager->runners().constFirst();
60
61 // Just make sure all went well
62 QVERIFY(runner);
63 }
64
65 /**
66 * Launch a query and wait for the RunnerManager to finish
67 * @param query
68 * @param runnerName
69 * @return matches of the current query
70 */
71 QList<QueryMatch> launchQuery(const QString &query, const QString &runnerName = QString())
72 {
74 manager->launchQuery(query, runnerName);
75 if (!QTest::qVerify(spy.wait(), "spy.wait()", "RunnerManager did not emit the queryFinished signal", __FILE__, __LINE__)) {
76 return {};
77 }
78 return manager->matches();
79 }
80#if KRUNNER_DBUS_RUNNER_TESTING
81 /**
82 * Launch the configured DBus executable with the given arguments and wait for the process to be started.
83 * @param args
84 * @param waitForService Wait for this service to be registered, this will default to the service from the metadata
85 * @return Process that was successfully started
86 */
87 QProcess *startDBusRunnerProcess(const QStringList &args = {}, const QString waitForService = QString())
88 {
89 qputenv("LC_ALL", "C.utf-8");
90 QProcess *process = new QProcess();
91 auto md = manager->convertDBusRunnerToJson(QStringLiteral(KRUNNER_TEST_DESKTOP_FILE));
92 QString serviceToWatch = waitForService;
93 if (serviceToWatch.isEmpty()) {
94 serviceToWatch = md.value(QStringLiteral("X-Plasma-DBusRunner-Service"));
95 }
96 QEventLoop loop;
97 // Wait for the service to show up. Same logic as the dbusrunner
100 &loop,
101 [&loop, serviceToWatch](const QString &serviceName, const QString &, const QString &newOwner) {
102 if (serviceName == serviceToWatch && !newOwner.isEmpty()) {
103 loop.quit();
104 }
105 });
106
107 // Otherwise, we just wait forever without any indication what we are waiting for
108 QTimer::singleShot(10000, &loop, [&loop, process]() {
109 loop.quit();
110
111 if (process->state() == QProcess::ProcessState::NotRunning) {
112 qWarning() << "stderr of" << KRUNNER_TEST_DBUS_EXECUTABLE << "is:";
113 qWarning().noquote() << process->readAllStandardError();
114 }
115 Q_ASSERT_X(false, "AbstractRunnerTest::startDBusRunnerProcess", "DBus service was not registered within 10 seconds");
116 });
117 process->start(QStringLiteral(KRUNNER_TEST_DBUS_EXECUTABLE), args);
118 loop.exec();
119 process->waitForStarted(5);
120
121 Q_ASSERT(process->state() == QProcess::ProcessState::Running);
122 m_runningProcesses << process;
123 return process;
124 }
125
126 /**
127 * Kill all processes that got started with the startDBusRunnerProcess
128 */
129 void killRunningDBusProcesses()
130 {
131 for (auto &process : std::as_const(m_runningProcesses)) {
132 process->kill();
133 QVERIFY(process->waitForFinished());
135 qWarning().noquote() << "Output from " << process->program() << ": " << process->readAll();
136 }
137 }
138 qDeleteAll(m_runningProcesses);
139 m_runningProcesses.clear();
140 }
141
142private:
143 QList<QProcess *> m_runningProcesses;
144#endif
145};
146}
147
148#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 Tue Mar 26 2024 11:17:29 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.