Warning, file /frameworks/krunner/autotests/dbusrunnertest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "runnermanager.h" 0008 0009 #ifdef KSERVICE_BUILD_DEPRECATED_SINCE 0010 #if KRUNNER_BUILD_DEPRECATED_SINCE(5, 72) && KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0011 #define WITH_KSERVICE 1 0012 #endif 0013 #endif 0014 0015 #ifndef WITH_KSERVICE 0016 #define WITH_KSERVICE 0 0017 #endif 0018 0019 #include <QAction> 0020 #include <QObject> 0021 #include <QProcess> 0022 #include <QSignalSpy> 0023 #include <QStandardPaths> 0024 #include <QTest> 0025 #include <QTime> 0026 #include <QTimer> 0027 0028 #if WITH_KSERVICE 0029 #include <KSycoca> 0030 #endif 0031 0032 #include "abstractrunnertest.h" 0033 #include "kpluginmetadata_utils_p.h" 0034 0035 using namespace Plasma; 0036 0037 Q_DECLARE_METATYPE(Plasma::QueryMatch) 0038 Q_DECLARE_METATYPE(QList<Plasma::QueryMatch>) 0039 0040 class DBusRunnerTest : public AbstractRunnerTest 0041 { 0042 Q_OBJECT 0043 public: 0044 DBusRunnerTest(); 0045 ~DBusRunnerTest() override; 0046 0047 private Q_SLOTS: 0048 void initTestCase(); 0049 void cleanup(); 0050 void testMatch(); 0051 void testMulti(); 0052 void testFilterProperties(); 0053 void testFilterProperties_data(); 0054 void testRequestActionsOnce(); 0055 void testDBusRunnerSyntaxIntegration(); 0056 void testIconData(); 0057 void testLifecycleMethods(); 0058 void testRequestActionsOnceWildcards(); 0059 #if WITH_KSERVICE 0060 void testMulti_data(); 0061 #endif 0062 }; 0063 0064 DBusRunnerTest::DBusRunnerTest() 0065 : AbstractRunnerTest() 0066 { 0067 qRegisterMetaType<QList<Plasma::QueryMatch>>(); 0068 } 0069 0070 DBusRunnerTest::~DBusRunnerTest() 0071 { 0072 } 0073 0074 void DBusRunnerTest::initTestCase() 0075 { 0076 // Set up a layer in the bin dir so ksycoca & KPluginMetaData find the Plasma/Runner service type 0077 const QByteArray defaultDataDirs = qEnvironmentVariableIsSet("XDG_DATA_DIRS") ? qgetenv("XDG_DATA_DIRS") : QByteArray("/usr/local:/usr"); 0078 const QByteArray modifiedDataDirs = QFile::encodeName(QCoreApplication::applicationDirPath()) + QByteArrayLiteral("/data:") + defaultDataDirs; 0079 qputenv("XDG_DATA_DIRS", modifiedDataDirs); 0080 0081 QStandardPaths::setTestModeEnabled(true); 0082 } 0083 0084 void DBusRunnerTest::cleanup() 0085 { 0086 // Make sure kill the running processes after each test 0087 killRunningDBusProcesses(); 0088 } 0089 0090 void DBusRunnerTest::testMatch() 0091 { 0092 QProcess *process = startDBusRunnerProcess({QStringLiteral("net.krunnertests.dave")}); 0093 initProperties(); 0094 launchQuery(QStringLiteral("foo")); 0095 0096 // verify matches 0097 const QList<QueryMatch> matches = manager->matches(); 0098 QCOMPARE(matches.count(), 1); 0099 auto result = matches.first(); 0100 0101 // see testremoterunner.cpp 0102 QCOMPARE(result.id(), QStringLiteral("dbusrunnertest_id1")); // note the runner name is prepended 0103 QCOMPARE(result.text(), QStringLiteral("Match 1")); 0104 QCOMPARE(result.iconName(), QStringLiteral("icon1")); 0105 QCOMPARE(result.type(), Plasma::QueryMatch::ExactMatch); 0106 QCOMPARE(result.isMultiLine(), true); 0107 // relevance can't be compared easily because RunnerContext meddles with it 0108 0109 // verify actions 0110 QTRY_COMPARE_WITH_TIMEOUT(manager->actionsForMatch(result).count(), 1, 10000); 0111 auto action = manager->actionsForMatch(result).constFirst(); 0112 0113 QCOMPARE(action->text(), QStringLiteral("Action 1")); 0114 0115 QSignalSpy processSpy(process, &QProcess::readyRead); 0116 manager->run(result); 0117 processSpy.wait(); 0118 QCOMPARE(process->readAllStandardOutput().trimmed().split('\n').constLast(), QByteArray("Running:id1:")); 0119 0120 result.setSelectedAction(action); 0121 manager->run(result); 0122 processSpy.wait(); 0123 QCOMPARE(process->readAllStandardOutput().trimmed().split('\n').constLast(), QByteArray("Running:id1:action1")); 0124 } 0125 0126 #if WITH_KSERVICE 0127 void DBusRunnerTest::testMulti_data() 0128 { 0129 QTest::addColumn<bool>("useKService"); 0130 0131 QTest::newRow("deprecated") << true; 0132 QTest::newRow("non-deprecated") << false; 0133 } 0134 #endif 0135 0136 void DBusRunnerTest::testMulti() 0137 { 0138 #if WITH_KSERVICE 0139 QFETCH(bool, useKService); 0140 #endif 0141 startDBusRunnerProcess({QStringLiteral("net.krunnertests.multi.a1")}, QStringLiteral("net.krunnertests.multi.a1")); 0142 startDBusRunnerProcess({QStringLiteral("net.krunnertests.multi.a2")}, QStringLiteral("net.krunnertests.multi.a2")); 0143 manager.reset(new RunnerManager()); // This case is special, because we want to load the runners manually 0144 0145 #if WITH_KSERVICE 0146 if (useKService) { 0147 KService::Ptr s(new KService(QFINDTESTDATA("dbusrunnertestmulti.desktop"))); 0148 QVERIFY(s); 0149 manager->loadRunner(s); 0150 } else { 0151 #endif 0152 auto md = parseMetaDataFromDesktopFile(QFINDTESTDATA("dbusrunnertestmulti.desktop")); 0153 QVERIFY(md.isValid()); 0154 manager->loadRunner(md); 0155 #if WITH_KSERVICE 0156 } 0157 #endif 0158 launchQuery(QStringLiteral("foo")); 0159 0160 // verify matches, must be one from each 0161 const QList<QueryMatch> matches = manager->matches(); 0162 QCOMPARE(matches.count(), 2); 0163 0164 const QString first = matches.at(0).data().toList().constFirst().toString(); 0165 const QString second = matches.at(1).data().toList().constFirst().toString(); 0166 QVERIFY(first != second); 0167 QVERIFY(first == QLatin1String("net.krunnertests.multi.a1") || first == QStringLiteral("net.krunnertests.multi.a2")); 0168 QVERIFY(second == QLatin1String("net.krunnertests.multi.a1") || second == QStringLiteral("net.krunnertests.multi.a2")); 0169 } 0170 0171 void DBusRunnerTest::testRequestActionsOnce() 0172 { 0173 startDBusRunnerProcess({QStringLiteral("net.krunnertests.dave")}); 0174 initProperties(); 0175 0176 // Construct a fake match with necessary data 0177 QueryMatch fakeMatch(runner); 0178 fakeMatch.setId(QStringLiteral("dbusrunnertest_id1")); 0179 fakeMatch.setData(QVariantList({QStringLiteral("net.krunnertests.dave"), QStringList({QStringLiteral("action1"), QStringLiteral("action2")})})); 0180 0181 // The actions should not be fetched before we have set up the match session 0182 QCOMPARE(manager->actionsForMatch(fakeMatch).count(), 0); 0183 launchQuery(QStringLiteral("foo")); 0184 // We need to retry this, because the DBus call to fetch the actions is async 0185 QTRY_COMPARE_WITH_TIMEOUT(manager->actionsForMatch(fakeMatch).count(), 2, 2500); 0186 } 0187 0188 void DBusRunnerTest::testFilterProperties_data() 0189 { 0190 QTest::addColumn<QString>("rejectedQuery"); 0191 QTest::addColumn<QString>("acceptedQuery"); 0192 0193 QTest::newRow("min-letter-count") << "fo" 0194 << "foo"; 0195 QTest::newRow("match-regex") << "barfoo" 0196 << "foobar"; 0197 } 0198 0199 void DBusRunnerTest::testFilterProperties() 0200 { 0201 QFETCH(QString, rejectedQuery); 0202 QFETCH(QString, acceptedQuery); 0203 QProcess *process = startDBusRunnerProcess({QStringLiteral("net.krunnertests.dave")}); 0204 initProperties(); 0205 0206 launchQuery(rejectedQuery); 0207 // Match method was not called, because of the min letter count or match regex property 0208 QVERIFY(process->readAllStandardOutput().isEmpty()); 0209 // accepted query fits those constraints 0210 launchQuery(acceptedQuery); 0211 QCOMPARE(process->readAllStandardOutput().trimmed(), QString(QStringLiteral("Matching:") + acceptedQuery).toLocal8Bit()); 0212 } 0213 0214 void DBusRunnerTest::testDBusRunnerSyntaxIntegration() 0215 { 0216 startDBusRunnerProcess({QStringLiteral("net.krunnertests.dave")}); 0217 initProperties(); 0218 const QList<RunnerSyntax> syntaxes = runner->syntaxes(); 0219 QCOMPARE(syntaxes.size(), 2); 0220 0221 QCOMPARE(syntaxes.at(0).exampleQueries().size(), 1); 0222 QCOMPARE(syntaxes.at(0).exampleQueries().constFirst(), QStringLiteral("syntax1")); 0223 QCOMPARE(syntaxes.at(0).description(), QStringLiteral("description1")); 0224 QCOMPARE(syntaxes.at(1).exampleQueries().size(), 1); 0225 QCOMPARE(syntaxes.at(1).exampleQueries().constFirst(), QStringLiteral("syntax2")); 0226 QCOMPARE(syntaxes.at(1).description(), QStringLiteral("description2")); 0227 } 0228 0229 void DBusRunnerTest::testIconData() 0230 { 0231 startDBusRunnerProcess({QStringLiteral("net.krunnertests.dave")}); 0232 initProperties(); 0233 0234 launchQuery(QStringLiteral("fooCostomIcon")); 0235 0236 const auto matches = manager->matches(); 0237 QCOMPARE(matches.count(), 1); 0238 auto result = matches.first(); 0239 0240 QImage expectedIcon(10, 10, QImage::Format_RGBA8888); 0241 expectedIcon.fill(Qt::blue); 0242 0243 QCOMPARE(result.icon().availableSizes().first(), QSize(10, 10)); 0244 QCOMPARE(result.icon().pixmap(QSize(10, 10)), QPixmap::fromImage(expectedIcon)); 0245 } 0246 0247 void DBusRunnerTest::testLifecycleMethods() 0248 { 0249 QProcess *process = startDBusRunnerProcess({QStringLiteral("net.krunnertests.dave"), QString()}); 0250 manager.reset(new RunnerManager()); // This case is special, because we want to load the runners manually 0251 auto md = parseMetaDataFromDesktopFile(QFINDTESTDATA("dbusrunnertestruntimeconfig.desktop")); 0252 manager->loadRunner(md); 0253 QCOMPARE(manager->runners().count(), 1); 0254 // Match session should be set up automatically 0255 launchQuery(QStringLiteral("fooo")); 0256 0257 // Make sure we got our match, end the match session and give the process a bit of time to get the DBus signal 0258 QTRY_COMPARE_WITH_TIMEOUT(manager->matches().count(), 1, 2000); 0259 manager->matchSessionComplete(); 0260 QTest::qWait(500); 0261 0262 const QStringList lifeCycleSteps = QString::fromLocal8Bit(process->readAllStandardOutput()).split(QLatin1Char('\n'), Qt::SkipEmptyParts); 0263 const QStringList expectedLifeCycleSteps = { 0264 QStringLiteral("Config"), 0265 QStringLiteral("Matching:fooo"), 0266 QStringLiteral("Teardown"), 0267 }; 0268 QCOMPARE(lifeCycleSteps, expectedLifeCycleSteps); 0269 0270 // The query does not match our min letter count we set at runtime 0271 launchQuery(QStringLiteral("foo")); 0272 QVERIFY(manager->matches().isEmpty()); 0273 // The query does not match our match regex we set at runtime 0274 launchQuery(QStringLiteral("barfoo")); 0275 QVERIFY(manager->matches().isEmpty()); 0276 } 0277 0278 void DBusRunnerTest::testRequestActionsOnceWildcards() 0279 { 0280 initProperties(); 0281 manager.reset(new RunnerManager()); // This case is special, because we want to load the runners manually 0282 auto md = parseMetaDataFromDesktopFile(QFINDTESTDATA("dbusrunnertestmulti.desktop")); 0283 QVERIFY(md.isValid()); 0284 manager->loadRunner(md); 0285 QCOMPARE(manager->runners().count(), 1); 0286 launchQuery("foo"); 0287 QVERIFY(manager->matches().isEmpty()); 0288 QueryMatch match(manager->runners().constFirst()); 0289 match.setId("test"); 0290 match.setData(QStringList{"net.krunnertests.multi.a1"}); 0291 QVERIFY(manager->actionsForMatch(match).isEmpty()); 0292 manager->matchSessionComplete(); 0293 0294 // We have started the process later and the actions should now be fetched when the match session is started 0295 startDBusRunnerProcess({QStringLiteral("net.krunnertests.multi.a1")}, QStringLiteral("net.krunnertests.multi.a1")); 0296 QTest::qWait(500); // Wait a bit for the runner to pick up the new service 0297 0298 launchQuery("fooo"); 0299 QVERIFY(!manager->matches().isEmpty()); 0300 QVERIFY(!manager->actionsForMatch(match).isEmpty()); 0301 } 0302 0303 QTEST_MAIN(DBusRunnerTest) 0304 0305 #include "dbusrunnertest.moc"