servicerunnertest.cpp 8.63 KB
Newer Older
1
/*
2
 *   Copyright (C) 2016-2020 Harald Sitter <sitter@kde.org>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License as published by the Free Software Foundation; either
 *   version 2.1 of the License, or (at your option) version 3, or any
 *   later version accepted by the membership of KDE e.V. (or its
 *   successor approved by the membership of KDE e.V.), which shall
 *   act as a proxy defined in Section 6 of version 3 of the license.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <QDebug>
#include <QDir>
#include <QFile>
#include <QObject>
#include <QStandardPaths>
#include <QTest>
27
#include <QThread>
28
29
30
31
32

#include <KSycoca>

#include "../servicerunner.h"

33
#include <clocale>
34
#include <optional>
35
36
#include <sys/types.h>
#include <unistd.h>
37

38
39
40
41
42
43
44
45
46
class ServiceRunnerTest : public QObject
{
    Q_OBJECT
private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    void testChromeAppsRelevance();
    void testKonsoleVsYakuakeComment();
47
    void testSystemSettings();
48
    void testForeignAppsOutscoreKCMs();
49
    void testINotifyUsage();
50
51
52
53
54
55
56
57
58
59
};

void ServiceRunnerTest::initTestCase()
{
    QStandardPaths::setTestModeEnabled(true);

    auto appsPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
    QDir(appsPath).removeRecursively();
    QVERIFY(QDir().mkpath(appsPath));
    auto fixtureDir = QDir(QFINDTESTDATA("fixtures"));
Alexander Lohnau's avatar
Alexander Lohnau committed
60
61
    const auto infoList = fixtureDir.entryInfoList(QDir::Files);
    for (const auto &fileInfo : infoList) {
62
63
64
        auto source = fileInfo.absoluteFilePath();
        auto target = appsPath + QDir::separator() + fileInfo.fileName();
        QVERIFY2(QFile::copy(fileInfo.absoluteFilePath(), target),
65
                 qPrintable(QStringLiteral("can't copy %1 => %2").arg(source, target)));
66
67
68
69
70
    }

    setlocale(LC_ALL, "C.utf8");

    KSycoca::self()->ensureCacheValid();
71
72
73
74
75

    // Make sure noDisplay behaves consistently WRT OnlyShowIn etc.
    QVERIFY(setenv("XDG_CURRENT_DESKTOP", "KDE", 1) == 0);
    // NOTE: noDisplay also includes X-KDE-OnlyShowOnQtPlatforms which is a bit harder to fake
    //       and not currently under testing anyway.
76
77
78
79
80
81
82
83
84
85
}

void ServiceRunnerTest::cleanupTestCase()
{
}

void ServiceRunnerTest::testChromeAppsRelevance()
{
    ServiceRunner runner(this, QVariantList());
    Plasma::RunnerContext context;
86
    context.setQuery(QStringLiteral("chrome"));
87
88
89
90
91

    runner.match(context);

    bool chromeFound = false;
    bool signalFound = false;
Alexander Lohnau's avatar
Alexander Lohnau committed
92
93
    const auto matches = context.matches();
    for (const auto &match : matches) {
94
        qDebug() << "matched" << match.text();
Laurent Montel's avatar
Laurent Montel committed
95
        if (!match.text().contains(QLatin1String("ServiceRunnerTest"))) {
96
97
98
            continue;
        }

Laurent Montel's avatar
Laurent Montel committed
99
        if (match.text() == QLatin1String("Google Chrome ServiceRunnerTest")) {
100
101
            QCOMPARE(match.relevance(), 0.8);
            chromeFound = true;
Laurent Montel's avatar
Laurent Montel committed
102
        } else if (match.text() == QLatin1String("Signal ServiceRunnerTest")) {
103
104
105
106
107
108
109
110
111
112
113
114
115
116
            // Rates lower because it doesn't have it in the name.
            QCOMPARE(match.relevance(), 0.7);
            signalFound = true;
        }
    }
    QVERIFY(chromeFound);
    QVERIFY(signalFound);
}

void ServiceRunnerTest::testKonsoleVsYakuakeComment()
{
    // Yakuake has konsole mentioned in comment, should be rated lower.
    ServiceRunner runner(this, QVariantList());
    Plasma::RunnerContext context;
117
    context.setQuery(QStringLiteral("kons"));
118
119
120
121
122

    runner.match(context);

    bool konsoleFound = false;
    bool yakuakeFound = false;
Alexander Lohnau's avatar
Alexander Lohnau committed
123
124
    const auto matches = context.matches();
    for (const auto &match : matches) {
125
        qDebug() << "matched" << match.text();
Laurent Montel's avatar
Laurent Montel committed
126
        if (!match.text().contains(QLatin1String("ServiceRunnerTest"))) {
127
128
129
            continue;
        }

Laurent Montel's avatar
Laurent Montel committed
130
        if (match.text() == QLatin1String("Konsole ServiceRunnerTest")) {
131
132
            QCOMPARE(match.relevance(), 0.99);
            konsoleFound = true;
Laurent Montel's avatar
Laurent Montel committed
133
        } else if (match.text() == QLatin1String("Yakuake ServiceRunnerTest")) {
134
135
136
137
138
139
140
141
142
            // Rates lower because it doesn't have it in the name.
            QCOMPARE(match.relevance(), 0.59);
            yakuakeFound = true;
        }
    }
    QVERIFY(konsoleFound);
    QVERIFY(yakuakeFound);
}

143
144
145
void ServiceRunnerTest::testSystemSettings()
{
    // In 5.9.0 'System Settings' suddenly didn't come back as a match for 'settings' anymore.
Yuri Chornoivan's avatar
Yuri Chornoivan committed
146
    // System Settings has a noKDE version and a KDE version, if the noKDE version is encountered
147
148
149
150
151
    // first it will be added to the seen cache, however disqualification of already seen items
    // may then also disqualify the KDE version of system settings on account of having already
    // seen it. This test makes sure we find the right version.
    ServiceRunner runner(this, QVariantList());
    Plasma::RunnerContext context;
152
    context.setQuery(QStringLiteral("settings"));
153
154
155
156
157

    runner.match(context);

    bool systemSettingsFound = false;
    bool foreignSystemSettingsFound = false;
Alexander Lohnau's avatar
Alexander Lohnau committed
158
159
    const auto matches = context.matches();
    for (const auto &match : matches) {
160
        qDebug() << "matched" << match.text();
Laurent Montel's avatar
Laurent Montel committed
161
        if (match.text() == QLatin1String("System Settings ServiceRunnerTest")) {
162
163
            systemSettingsFound = true;
        }
Laurent Montel's avatar
Laurent Montel committed
164
        if (match.text() == QLatin1String("KDE System Settings ServiceRunnerTest")) {
165
166
167
168
169
170
171
            foreignSystemSettingsFound = true;
        }
    }
    QVERIFY(systemSettingsFound);
    QVERIFY(!foreignSystemSettingsFound);
}

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
void ServiceRunnerTest::testForeignAppsOutscoreKCMs()
{
    // Our software outscores other things, but foreign applications should still
    // outscore our KCMs.
    ServiceRunner runner(this, QVariantList());
    Plasma::RunnerContext context;
    context.setQuery(QStringLiteral("virt"));

    runner.match(context);

    std::optional<qreal> virtManRelevance;
    std::optional<qreal> virtThingsRelevance;
    std::optional<qreal> kcmRelevance;
    const auto matches = context.matches();
    for (const auto &match : matches) {
        const QUrl url = match.data().toUrl();
        if (url == QUrl(QStringLiteral("applications:virt-manager.desktop"))) {
            virtManRelevance = match.relevance();
        } else if (url == QUrl(QStringLiteral("applications:kcm_kwin_virtualdesktops.desktop"))) {
            kcmRelevance = match.relevance();
        } else if (url == QUrl(QStringLiteral("applications:org.kde.virtthings.desktop"))) {
            virtThingsRelevance = match.relevance();
        }
    }
    QVERIFY(virtManRelevance.has_value());
    QVERIFY(virtThingsRelevance.has_value());
    QVERIFY(kcmRelevance.has_value());

    // KDE app should be >= non-KDE app
    QVERIFY2(virtThingsRelevance >= virtManRelevance,
202
             qPrintable(QStringLiteral("%1 >= %2").arg(virtThingsRelevance.value(), virtManRelevance.value())));
203
204
    // KDE app strictly greater KDE kcm
    QVERIFY2(virtThingsRelevance > kcmRelevance,
205
             qPrintable(QStringLiteral("%1 > %2").arg(virtThingsRelevance.value(), kcmRelevance.value())));
206
207
    // non-KDE app also strictly greater (because it is an app)
    QVERIFY2(virtManRelevance > kcmRelevance,
208
             qPrintable(QStringLiteral("%1 > %2").arg(virtManRelevance.value(), kcmRelevance.value())));
209
210
}

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
void ServiceRunnerTest::testINotifyUsage()
{
    auto inotifyCount = []() -> uint {
        uint count = 0;
        const QDir procDir(QStringLiteral("/proc/%1/fd").arg(getpid()));
        for (const auto &fileInfo : procDir.entryInfoList()) {
            if (fileInfo.symLinkTarget().endsWith(QStringLiteral("anon_inode:inotify"))) {
                ++count;
            }
        }
        return count;
    };

    const uint originalCount = inotifyCount();

    // We'll run this in a new thread so KDirWatch would be led to create a new thread-local watch instance.
    // The expectation here is that this KDW instance is not persistently claiming an inotify instance.
    bool inotifyCountCool = false;
    auto thread = QThread::create([&] {
        ServiceRunner runner(nullptr, QVariantList());
        Plasma::RunnerContext context;
        context.setQuery(QStringLiteral("settings"));

        runner.match(context);

        QCOMPARE(inotifyCount(), originalCount);
        inotifyCountCool = true;
    });
    thread->start();
    thread->wait();
    thread->deleteLater();

    QVERIFY(inotifyCountCool);
}

246
247
248
QTEST_MAIN(ServiceRunnerTest)

#include "servicerunnertest.moc"