mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-03-26 17:03:08 +00:00
767 lines
28 KiB
C++
767 lines
28 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// SPDX-FileCopyrightText: 2026 A-La-Karte Contributors
|
|
|
|
#include <QCoreApplication>
|
|
#include <QDBusArgument>
|
|
#include <QDBusConnection>
|
|
#include <QDBusConnectionInterface>
|
|
#include <QDBusInterface>
|
|
#include <QDBusReply>
|
|
#include <QDBusVariant>
|
|
#include <QDir>
|
|
#include <QElapsedTimer>
|
|
#include <QProcess>
|
|
#include <QProcessEnvironment>
|
|
#include <QSet>
|
|
#include <QSignalSpy>
|
|
#include <QStandardPaths>
|
|
#include <QStringList>
|
|
#include <QUuid>
|
|
#include <QtTest>
|
|
|
|
#include "gamecenter1interface.h"
|
|
#include "input1interface.h"
|
|
#include "runner1interface.h"
|
|
|
|
namespace
|
|
{
|
|
static QString takeArgValue(const QStringList &args, const QString &key)
|
|
{
|
|
const int idx = args.indexOf(key);
|
|
if (idx < 0) {
|
|
return {};
|
|
}
|
|
if (idx + 1 >= args.size()) {
|
|
return {};
|
|
}
|
|
return args.at(idx + 1);
|
|
}
|
|
|
|
static bool waitForService(QDBusConnection &bus, const QString &service, int timeoutMs)
|
|
{
|
|
if (!bus.isConnected() || !bus.interface()) {
|
|
return false;
|
|
}
|
|
|
|
QElapsedTimer t;
|
|
t.start();
|
|
while (t.elapsed() < timeoutMs) {
|
|
if (bus.interface()->isServiceRegistered(service)) {
|
|
return true;
|
|
}
|
|
QTest::qWait(50);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static QVariant unwrapDbusVariant(QVariant v)
|
|
{
|
|
if (v.metaType() == QMetaType::fromType<QDBusVariant>()) {
|
|
v = v.value<QDBusVariant>().variant();
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static QVariantMap unwrapVariantMap(QVariant v)
|
|
{
|
|
v = unwrapDbusVariant(v);
|
|
if (v.metaType() == QMetaType::fromType<QDBusArgument>()) {
|
|
const QDBusArgument arg = v.value<QDBusArgument>();
|
|
return qdbus_cast<QVariantMap>(arg);
|
|
}
|
|
if (v.canConvert<QVariantMap>()) {
|
|
return v.toMap();
|
|
}
|
|
return {};
|
|
}
|
|
}
|
|
|
|
class DbusSmokeTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private Q_SLOTS:
|
|
void initTestCase();
|
|
void cleanupTestCase();
|
|
|
|
void pingGameCenter();
|
|
void gameCenterUniqueness();
|
|
void gameCenterPolicyAndCapabilities();
|
|
void gameCenterLaunchFailureContract();
|
|
void pingRunner();
|
|
void runnerVersionAndListRunners();
|
|
void runnerResolveLaunchMissingProgram();
|
|
void runnerResolveLaunchUnknownRunnerId();
|
|
void runnerResolveLaunchWineMissingPrefixOrGameId();
|
|
void pingInput();
|
|
void inputVersionAndCapabilities();
|
|
void inputProfilesCrud();
|
|
void runnerResolveLaunchNative();
|
|
void runnerGameProfiles();
|
|
|
|
private:
|
|
QString m_gamecenterPath;
|
|
QString m_runnerdPath;
|
|
QString m_inputdPath;
|
|
|
|
QString m_dbusAddress;
|
|
QProcess m_dbusDaemon;
|
|
QProcess m_gamecenter;
|
|
QProcess m_runnerd;
|
|
QProcess m_inputd;
|
|
|
|
QString m_testXdgBase;
|
|
|
|
QDBusConnection m_bus = QDBusConnection::connectToBus(QString(), QStringLiteral("alakarte_test"));
|
|
|
|
bool startPrivateBus();
|
|
bool haveDbusDaemon() const;
|
|
void startDaemon(QProcess &p, const QString &program);
|
|
void stopProcess(QProcess &p);
|
|
};
|
|
|
|
bool DbusSmokeTest::haveDbusDaemon() const
|
|
{
|
|
return !QStandardPaths::findExecutable(QStringLiteral("dbus-daemon")).isEmpty();
|
|
}
|
|
|
|
bool DbusSmokeTest::startPrivateBus()
|
|
{
|
|
const QString dbusDaemon = QStandardPaths::findExecutable(QStringLiteral("dbus-daemon"));
|
|
if (dbusDaemon.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
m_dbusDaemon.setProgram(dbusDaemon);
|
|
m_dbusDaemon.setArguments({QStringLiteral("--session"), QStringLiteral("--nofork"), QStringLiteral("--print-address=1")});
|
|
m_dbusDaemon.setProcessChannelMode(QProcess::MergedChannels);
|
|
m_dbusDaemon.start();
|
|
if (!m_dbusDaemon.waitForStarted(5000)) {
|
|
return false;
|
|
}
|
|
|
|
if (!m_dbusDaemon.waitForReadyRead(5000)) {
|
|
return false;
|
|
}
|
|
|
|
m_dbusAddress = QString::fromUtf8(m_dbusDaemon.readLine()).trimmed();
|
|
if (m_dbusAddress.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
QDBusConnection::disconnectFromBus(QStringLiteral("alakarte_test"));
|
|
m_bus = QDBusConnection::connectToBus(m_dbusAddress, QStringLiteral("alakarte_test"));
|
|
return m_bus.isConnected();
|
|
}
|
|
|
|
void DbusSmokeTest::startDaemon(QProcess &p, const QString &program)
|
|
{
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
env.insert(QStringLiteral("DBUS_SESSION_BUS_ADDRESS"), m_dbusAddress);
|
|
if (!m_testXdgBase.isEmpty()) {
|
|
env.insert(QStringLiteral("XDG_DATA_HOME"), m_testXdgBase + QStringLiteral("/data"));
|
|
env.insert(QStringLiteral("XDG_CONFIG_HOME"), m_testXdgBase + QStringLiteral("/config"));
|
|
env.insert(QStringLiteral("XDG_CACHE_HOME"), m_testXdgBase + QStringLiteral("/cache"));
|
|
}
|
|
p.setProcessEnvironment(env);
|
|
p.setProgram(program);
|
|
p.setArguments({});
|
|
p.setProcessChannelMode(QProcess::MergedChannels);
|
|
p.start();
|
|
}
|
|
|
|
void DbusSmokeTest::stopProcess(QProcess &p)
|
|
{
|
|
if (p.state() == QProcess::NotRunning) {
|
|
return;
|
|
}
|
|
|
|
p.terminate();
|
|
if (!p.waitForFinished(3000)) {
|
|
p.kill();
|
|
p.waitForFinished(3000);
|
|
}
|
|
}
|
|
|
|
void DbusSmokeTest::initTestCase()
|
|
{
|
|
m_gamecenterPath = qApp ? qApp->property("alakarte_test_gamecenter").toString() : QString();
|
|
m_runnerdPath = qApp ? qApp->property("alakarte_test_runnerd").toString() : QString();
|
|
m_inputdPath = qApp ? qApp->property("alakarte_test_inputd").toString() : QString();
|
|
|
|
if (m_gamecenterPath.isEmpty() || m_runnerdPath.isEmpty() || m_inputdPath.isEmpty()) {
|
|
const QStringList args = QCoreApplication::arguments();
|
|
if (m_gamecenterPath.isEmpty()) {
|
|
m_gamecenterPath = takeArgValue(args, QStringLiteral("--gamecenter"));
|
|
}
|
|
if (m_runnerdPath.isEmpty()) {
|
|
m_runnerdPath = takeArgValue(args, QStringLiteral("--runnerd"));
|
|
}
|
|
if (m_inputdPath.isEmpty()) {
|
|
m_inputdPath = takeArgValue(args, QStringLiteral("--inputd"));
|
|
}
|
|
}
|
|
|
|
QVERIFY2(!m_gamecenterPath.isEmpty(), "--gamecenter is required");
|
|
QVERIFY2(!m_runnerdPath.isEmpty(), "--runnerd is required");
|
|
QVERIFY2(!m_inputdPath.isEmpty(), "--inputd is required");
|
|
|
|
if (!haveDbusDaemon()) {
|
|
QSKIP("dbus-daemon not found");
|
|
}
|
|
|
|
if (!startPrivateBus()) {
|
|
QSKIP("failed to start private dbus session");
|
|
}
|
|
|
|
m_testXdgBase = QDir::tempPath() + QStringLiteral("/alakarte-test-xdg-") + QUuid::createUuid().toString(QUuid::WithoutBraces);
|
|
QVERIFY(QDir().mkpath(m_testXdgBase + QStringLiteral("/data")));
|
|
QVERIFY(QDir().mkpath(m_testXdgBase + QStringLiteral("/config")));
|
|
QVERIFY(QDir().mkpath(m_testXdgBase + QStringLiteral("/cache")));
|
|
|
|
startDaemon(m_runnerd, m_runnerdPath);
|
|
QVERIFY(m_runnerd.waitForStarted(5000));
|
|
|
|
startDaemon(m_inputd, m_inputdPath);
|
|
QVERIFY(m_inputd.waitForStarted(5000));
|
|
|
|
startDaemon(m_gamecenter, m_gamecenterPath);
|
|
QVERIFY(m_gamecenter.waitForStarted(5000));
|
|
|
|
QVERIFY2(waitForService(m_bus, QStringLiteral("org.kde.ALaKarte.Runner1"), 5000), "Runner1 service did not appear on the bus");
|
|
QVERIFY2(waitForService(m_bus, QStringLiteral("org.kde.ALaKarte.Input1"), 5000), "Input1 service did not appear on the bus");
|
|
QVERIFY2(waitForService(m_bus, QStringLiteral("org.kde.GameCenter1"), 5000), "GameCenter1 service did not appear on the bus");
|
|
}
|
|
|
|
void DbusSmokeTest::cleanupTestCase()
|
|
{
|
|
stopProcess(m_gamecenter);
|
|
stopProcess(m_inputd);
|
|
stopProcess(m_runnerd);
|
|
stopProcess(m_dbusDaemon);
|
|
QDBusConnection::disconnectFromBus(QStringLiteral("alakarte_test"));
|
|
|
|
if (!m_testXdgBase.isEmpty()) {
|
|
QDir(m_testXdgBase).removeRecursively();
|
|
m_testXdgBase.clear();
|
|
}
|
|
}
|
|
|
|
void DbusSmokeTest::pingGameCenter()
|
|
{
|
|
org::kde::GameCenter1 iface(QStringLiteral("org.kde.GameCenter1"), QStringLiteral("/org/kde/ALaKarte/GameCenter1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QDBusPendingReply<QString> reply = iface.Ping();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.value(), QStringLiteral("ok"));
|
|
}
|
|
|
|
void DbusSmokeTest::gameCenterUniqueness()
|
|
{
|
|
pingGameCenter();
|
|
|
|
QVERIFY(m_bus.interface());
|
|
const QDBusReply<QString> ownerBeforeReply = m_bus.interface()->serviceOwner(QStringLiteral("org.kde.GameCenter1"));
|
|
QVERIFY(ownerBeforeReply.isValid());
|
|
const QString ownerBefore = ownerBeforeReply.value();
|
|
QVERIFY(!ownerBefore.isEmpty());
|
|
|
|
QProcess second;
|
|
startDaemon(second, m_gamecenterPath);
|
|
QVERIFY(second.waitForStarted(5000));
|
|
|
|
const bool finished = second.waitForFinished(5000);
|
|
if (!finished) {
|
|
stopProcess(second);
|
|
}
|
|
QVERIFY(finished);
|
|
QCOMPARE(second.exitStatus(), QProcess::NormalExit);
|
|
|
|
const QDBusReply<QString> ownerAfterReply = m_bus.interface()->serviceOwner(QStringLiteral("org.kde.GameCenter1"));
|
|
QVERIFY(ownerAfterReply.isValid());
|
|
QCOMPARE(ownerAfterReply.value(), ownerBefore);
|
|
|
|
pingGameCenter();
|
|
}
|
|
|
|
void DbusSmokeTest::gameCenterPolicyAndCapabilities()
|
|
{
|
|
org::kde::GameCenter1 iface(QStringLiteral("org.kde.GameCenter1"), QStringLiteral("/org/kde/ALaKarte/GameCenter1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
{
|
|
QDBusPendingReply<uint, uint> reply = iface.Version();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.argumentAt<0>(), 1u);
|
|
QCOMPARE(reply.argumentAt<1>(), 0u);
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.GetCapabilities();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
const QVariantMap caps = reply.value();
|
|
QVERIFY(caps.contains(QStringLiteral("supportsSystemd")));
|
|
QVERIFY(caps.value(QStringLiteral("supportsSystemd")).canConvert<bool>());
|
|
QVERIFY(caps.contains(QStringLiteral("supportsSystemBus")));
|
|
QCOMPARE(caps.value(QStringLiteral("supportsSystemBus")).toBool(), false);
|
|
QVERIFY(caps.contains(QStringLiteral("supportsPowerProfiles")));
|
|
QVERIFY(caps.value(QStringLiteral("supportsPowerProfiles")).canConvert<bool>());
|
|
}
|
|
|
|
QVariantMap originalPolicy;
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.GetPolicy();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
originalPolicy = reply.value();
|
|
}
|
|
|
|
{
|
|
QVariantMap policy;
|
|
policy.insert(QStringLiteral("maxConcurrent"), 0);
|
|
QDBusPendingReply<> reply = iface.SetPolicy(policy);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.GetPolicy();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.value().value(QStringLiteral("maxConcurrent")).toInt(), 0);
|
|
}
|
|
|
|
{
|
|
const int originalMaxConcurrent = originalPolicy.value(QStringLiteral("maxConcurrent"), 0).toInt();
|
|
QVariantMap policy;
|
|
policy.insert(QStringLiteral("maxConcurrent"), originalMaxConcurrent);
|
|
QDBusPendingReply<> reply = iface.SetPolicy(policy);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantList> reply = iface.ListSessions();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<> reply = iface.StopByGameId(QStringLiteral("alakarte-test-nonexistent"));
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
}
|
|
}
|
|
|
|
void DbusSmokeTest::gameCenterLaunchFailureContract()
|
|
{
|
|
org::kde::GameCenter1 iface(QStringLiteral("org.kde.GameCenter1"), QStringLiteral("/org/kde/ALaKarte/GameCenter1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QSignalSpy launchFailedSpy(&iface, &org::kde::GameCenter1::LaunchFailed);
|
|
QVERIFY(launchFailedSpy.isValid());
|
|
|
|
QVariantMap launchSpec;
|
|
launchSpec.insert(QStringLiteral("gameId"), QStringLiteral("alakarte-test-game"));
|
|
launchSpec.insert(QStringLiteral("program"), QStringLiteral("/bin/true"));
|
|
launchSpec.insert(QStringLiteral("args"), QStringList{});
|
|
|
|
QDBusPendingReply<QString> reply = iface.Launch(launchSpec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QVERIFY(reply.value().isEmpty());
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(launchFailedSpy.count(), 1, 2000);
|
|
const QList<QVariant> args = launchFailedSpy.takeFirst();
|
|
QCOMPARE(args.size(), 1);
|
|
const QVariantMap error = unwrapVariantMap(args.first());
|
|
QVERIFY(error.contains(QStringLiteral("error")));
|
|
QVERIFY(error.value(QStringLiteral("error")).toString().contains(QStringLiteral("systemd"), Qt::CaseInsensitive));
|
|
QCOMPARE(error.value(QStringLiteral("gameId")).toString(), QStringLiteral("alakarte-test-game"));
|
|
}
|
|
|
|
void DbusSmokeTest::pingRunner()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QDBusPendingReply<QString> reply = iface.Ping();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.value(), QStringLiteral("ok"));
|
|
}
|
|
|
|
void DbusSmokeTest::runnerVersionAndListRunners()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(5000);
|
|
|
|
{
|
|
QDBusPendingReply<uint, uint> reply = iface.Version();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.argumentAt<0>(), 1u);
|
|
QCOMPARE(reply.argumentAt<1>(), 0u);
|
|
}
|
|
|
|
QDBusPendingReply<QVariantList> reply = iface.ListRunners();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
|
|
const QVariantList list = reply.value();
|
|
QSet<QString> ids;
|
|
for (const QVariant &v : list) {
|
|
const QVariantMap m = unwrapVariantMap(v);
|
|
const QString id = m.value(QStringLiteral("id")).toString();
|
|
const QString type = m.value(QStringLiteral("type")).toString();
|
|
const QString path = m.value(QStringLiteral("path")).toString();
|
|
|
|
QVERIFY2(!id.isEmpty(), "runner entry missing id");
|
|
QVERIFY2(!type.isEmpty(), qPrintable(QStringLiteral("runner '%1' missing type").arg(id)));
|
|
QVERIFY2(!path.isEmpty(), qPrintable(QStringLiteral("runner '%1' missing path").arg(id)));
|
|
QVERIFY2(!ids.contains(id), qPrintable(QStringLiteral("duplicate runner id '%1'").arg(id)));
|
|
ids.insert(id);
|
|
}
|
|
}
|
|
|
|
void DbusSmokeTest::pingInput()
|
|
{
|
|
org::kde::ALaKarte::Input1 iface(QStringLiteral("org.kde.ALaKarte.Input1"), QStringLiteral("/org/kde/ALaKarte/Input1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QDBusPendingReply<QString> reply = iface.Ping();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.value(), QStringLiteral("ok"));
|
|
}
|
|
|
|
void DbusSmokeTest::inputVersionAndCapabilities()
|
|
{
|
|
org::kde::ALaKarte::Input1 iface(QStringLiteral("org.kde.ALaKarte.Input1"), QStringLiteral("/org/kde/ALaKarte/Input1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
{
|
|
QDBusPendingReply<uint, uint> reply = iface.Version();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QCOMPARE(reply.argumentAt<0>(), 1u);
|
|
QCOMPARE(reply.argumentAt<1>(), 0u);
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.GetCapabilities();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
|
|
const QVariantMap caps = reply.value();
|
|
QVERIFY(caps.contains(QStringLiteral("supportsBattery")));
|
|
QVERIFY(caps.value(QStringLiteral("supportsBattery")).canConvert<bool>());
|
|
QCOMPARE(caps.value(QStringLiteral("supportsBattery")).toBool(), true);
|
|
|
|
QVERIFY(caps.contains(QStringLiteral("supportsHotplug")));
|
|
QVERIFY(caps.value(QStringLiteral("supportsHotplug")).canConvert<bool>());
|
|
QCOMPARE(caps.value(QStringLiteral("supportsHotplug")).toBool(), true);
|
|
|
|
QVERIFY(caps.contains(QStringLiteral("supportsProfiles")));
|
|
QVERIFY(caps.value(QStringLiteral("supportsProfiles")).canConvert<bool>());
|
|
QCOMPARE(caps.value(QStringLiteral("supportsProfiles")).toBool(), true);
|
|
}
|
|
}
|
|
|
|
void DbusSmokeTest::inputProfilesCrud()
|
|
{
|
|
org::kde::ALaKarte::Input1 iface(QStringLiteral("org.kde.ALaKarte.Input1"), QStringLiteral("/org/kde/ALaKarte/Input1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QDBusPendingReply<QString> createReply = iface.CreateProfile(QStringLiteral("Test Profile"));
|
|
createReply.waitForFinished();
|
|
QVERIFY2(!createReply.isError(), qPrintable(createReply.error().message()));
|
|
const QString profileId = createReply.value();
|
|
QVERIFY(!profileId.isEmpty());
|
|
|
|
{
|
|
QDBusPendingReply<QVariantList> listReply = iface.ListProfiles();
|
|
listReply.waitForFinished();
|
|
QVERIFY2(!listReply.isError(), qPrintable(listReply.error().message()));
|
|
const QVariantList list = listReply.value();
|
|
|
|
bool found = false;
|
|
for (const QVariant &v : list) {
|
|
const QVariantMap m = unwrapVariantMap(v);
|
|
if (m.value(QStringLiteral("id")).toString() == profileId) {
|
|
found = true;
|
|
QCOMPARE(m.value(QStringLiteral("name")).toString(), QStringLiteral("Test Profile"));
|
|
break;
|
|
}
|
|
}
|
|
QVERIFY(found);
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> getReply = iface.GetProfile(profileId);
|
|
getReply.waitForFinished();
|
|
QVERIFY2(!getReply.isError(), qPrintable(getReply.error().message()));
|
|
const QVariantMap m = getReply.value();
|
|
QCOMPARE(m.value(QStringLiteral("id")).toString(), profileId);
|
|
QCOMPARE(m.value(QStringLiteral("name")).toString(), QStringLiteral("Test Profile"));
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<bool> delReply = iface.DeleteProfile(profileId);
|
|
delReply.waitForFinished();
|
|
QVERIFY2(!delReply.isError(), qPrintable(delReply.error().message()));
|
|
QVERIFY(delReply.value());
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantList> listReply = iface.ListProfiles();
|
|
listReply.waitForFinished();
|
|
QVERIFY2(!listReply.isError(), qPrintable(listReply.error().message()));
|
|
const QVariantList list = listReply.value();
|
|
|
|
for (const QVariant &v : list) {
|
|
const QVariantMap m = unwrapVariantMap(v);
|
|
QVERIFY(m.value(QStringLiteral("id")).toString() != profileId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DbusSmokeTest::runnerResolveLaunchNative()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QVariantMap spec;
|
|
spec.insert(QStringLiteral("program"), QStringLiteral("/bin/true"));
|
|
spec.insert(QStringLiteral("args"), QStringList{});
|
|
|
|
QDBusPendingReply<QVariantMap> reply = iface.ResolveLaunch(spec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
|
|
const QVariantMap out = reply.value();
|
|
QVERIFY(out.value(QStringLiteral("ok")).toBool());
|
|
QCOMPARE(out.value(QStringLiteral("finalProgram")).toString(), QStringLiteral("/bin/true"));
|
|
QCOMPARE(out.value(QStringLiteral("finalArgs")).toStringList(), QStringList{});
|
|
}
|
|
|
|
void DbusSmokeTest::runnerResolveLaunchMissingProgram()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QVariantMap spec;
|
|
spec.insert(QStringLiteral("args"), QStringList{});
|
|
|
|
QDBusPendingReply<QVariantMap> reply = iface.ResolveLaunch(spec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
|
|
const QVariantMap out = reply.value();
|
|
QCOMPARE(out.value(QStringLiteral("ok")).toBool(), false);
|
|
QVERIFY(out.contains(QStringLiteral("error")));
|
|
QVERIFY(out.value(QStringLiteral("error")).toString().contains(QStringLiteral("missing program"), Qt::CaseInsensitive));
|
|
}
|
|
|
|
void DbusSmokeTest::runnerResolveLaunchUnknownRunnerId()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QVariantMap spec;
|
|
spec.insert(QStringLiteral("runnerId"), QStringLiteral("alakarte-test-nonexistent"));
|
|
spec.insert(QStringLiteral("program"), QStringLiteral("/bin/true"));
|
|
spec.insert(QStringLiteral("args"), QStringList{});
|
|
|
|
QDBusPendingReply<QVariantMap> reply = iface.ResolveLaunch(spec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
|
|
const QVariantMap out = reply.value();
|
|
QCOMPARE(out.value(QStringLiteral("ok")).toBool(), false);
|
|
QVERIFY(out.contains(QStringLiteral("error")));
|
|
QVERIFY(out.value(QStringLiteral("error")).toString().contains(QStringLiteral("unknown runnerId"), Qt::CaseInsensitive));
|
|
}
|
|
|
|
void DbusSmokeTest::runnerResolveLaunchWineMissingPrefixOrGameId()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
QVariantMap spec;
|
|
spec.insert(QStringLiteral("runner"), QStringLiteral("wine"));
|
|
spec.insert(QStringLiteral("program"), QStringLiteral("/bin/true"));
|
|
spec.insert(QStringLiteral("args"), QStringList{});
|
|
|
|
QDBusPendingReply<QVariantMap> reply = iface.ResolveLaunch(spec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
|
|
const QVariantMap out = reply.value();
|
|
QCOMPARE(out.value(QStringLiteral("ok")).toBool(), false);
|
|
QVERIFY(out.contains(QStringLiteral("error")));
|
|
QVERIFY(out.value(QStringLiteral("error")).toString().contains(QStringLiteral("missing prefixPath or gameId"), Qt::CaseInsensitive));
|
|
}
|
|
|
|
void DbusSmokeTest::runnerGameProfiles()
|
|
{
|
|
org::kde::ALaKarte::Runner1 iface(QStringLiteral("org.kde.ALaKarte.Runner1"), QStringLiteral("/org/kde/ALaKarte/Runner1"), m_bus);
|
|
QVERIFY(iface.isValid());
|
|
iface.setTimeout(2000);
|
|
|
|
const QString gameId = QStringLiteral("alakarte-test-game");
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.ClearGameProfile(gameId);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QVERIFY(reply.value().value(QStringLiteral("ok")).toBool());
|
|
}
|
|
|
|
{
|
|
QVariantMap spec;
|
|
spec.insert(QStringLiteral("gameId"), gameId);
|
|
spec.insert(QStringLiteral("runner"), QStringLiteral("wine"));
|
|
spec.insert(QStringLiteral("runnerPath"), QStringLiteral("/bin/true"));
|
|
spec.insert(QStringLiteral("envOverrides"), QVariantMap{{QStringLiteral("ALAKARTE_TEST_VAR"), QStringLiteral("1")}});
|
|
spec.insert(QStringLiteral("extraArgs"), QStringList{QStringLiteral("--profile-arg")});
|
|
spec.insert(QStringLiteral("dllOverrides"),
|
|
QVariantMap{{QStringLiteral("d3d11"), QStringLiteral("native,builtin")}, {QStringLiteral("dxgi"), QStringLiteral("native,builtin")}});
|
|
|
|
QDBusPendingReply<QVariantMap> reply = iface.SetGameProfile(spec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
const QVariantMap out = reply.value();
|
|
QVERIFY(out.value(QStringLiteral("ok")).toBool());
|
|
|
|
const QVariantMap profile = unwrapVariantMap(out.value(QStringLiteral("profile")));
|
|
QCOMPARE(profile.value(QStringLiteral("gameId")).toString(), gameId);
|
|
const QVariantMap env = unwrapVariantMap(profile.value(QStringLiteral("envOverrides")));
|
|
QCOMPARE(env.value(QStringLiteral("ALAKARTE_TEST_VAR")).toString(), QStringLiteral("1"));
|
|
|
|
QCOMPARE(profile.value(QStringLiteral("extraArgs")).toStringList(), QStringList{QStringLiteral("--profile-arg")});
|
|
|
|
const QVariantMap dll = unwrapVariantMap(profile.value(QStringLiteral("dllOverrides")));
|
|
QCOMPARE(dll.value(QStringLiteral("d3d11")).toString(), QStringLiteral("native,builtin"));
|
|
QCOMPARE(dll.value(QStringLiteral("dxgi")).toString(), QStringLiteral("native,builtin"));
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.GetGameProfile(gameId);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
const QVariantMap out = reply.value();
|
|
QVERIFY(out.value(QStringLiteral("ok")).toBool());
|
|
const QVariantMap profile = unwrapVariantMap(out.value(QStringLiteral("profile")));
|
|
QCOMPARE(profile.value(QStringLiteral("gameId")).toString(), gameId);
|
|
|
|
QCOMPARE(profile.value(QStringLiteral("extraArgs")).toStringList(), QStringList{QStringLiteral("--profile-arg")});
|
|
|
|
const QVariantMap dll = unwrapVariantMap(profile.value(QStringLiteral("dllOverrides")));
|
|
QCOMPARE(dll.value(QStringLiteral("d3d11")).toString(), QStringLiteral("native,builtin"));
|
|
QCOMPARE(dll.value(QStringLiteral("dxgi")).toString(), QStringLiteral("native,builtin"));
|
|
}
|
|
|
|
{
|
|
QVariantMap spec;
|
|
spec.insert(QStringLiteral("gameId"), gameId);
|
|
spec.insert(QStringLiteral("useGameProfile"), true);
|
|
spec.insert(QStringLiteral("program"), QStringLiteral("/bin/true"));
|
|
spec.insert(QStringLiteral("args"), QStringList{QStringLiteral("--base-arg")});
|
|
spec.insert(QStringLiteral("extraArgs"), QStringList{QStringLiteral("--spec-arg")});
|
|
|
|
QDBusPendingReply<QVariantMap> reply = iface.ResolveLaunch(spec);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
const QVariantMap out = reply.value();
|
|
QVERIFY(out.value(QStringLiteral("ok")).toBool());
|
|
QCOMPARE(out.value(QStringLiteral("finalProgram")).toString(), QStringLiteral("/bin/true"));
|
|
const QStringList expectedFinalArgs = QStringList({
|
|
QStringLiteral("/bin/true"),
|
|
QStringLiteral("--base-arg"),
|
|
QStringLiteral("--profile-arg"),
|
|
QStringLiteral("--spec-arg"),
|
|
});
|
|
QCOMPARE(out.value(QStringLiteral("finalArgs")).toStringList(), expectedFinalArgs);
|
|
|
|
const QVariantMap env = unwrapVariantMap(out.value(QStringLiteral("effectiveEnv")));
|
|
QCOMPARE(env.value(QStringLiteral("ALAKARTE_TEST_VAR")).toString(), QStringLiteral("1"));
|
|
QCOMPARE(env.value(QStringLiteral("WINEDLLOVERRIDES")).toString(), QStringLiteral("d3d11=native,builtin;dxgi=native,builtin"));
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantList> reply = iface.ListGameProfiles();
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
const QVariantList list = reply.value();
|
|
bool found = false;
|
|
for (const QVariant &v : list) {
|
|
const QVariantMap m = unwrapVariantMap(v);
|
|
if (m.value(QStringLiteral("gameId")).toString() == gameId) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
QVERIFY(found);
|
|
}
|
|
|
|
{
|
|
QDBusPendingReply<QVariantMap> reply = iface.ClearGameProfile(gameId);
|
|
reply.waitForFinished();
|
|
QVERIFY2(!reply.isError(), qPrintable(reply.error().message()));
|
|
QVERIFY(reply.value().value(QStringLiteral("ok")).toBool());
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
QCoreApplication app(argc, argv);
|
|
|
|
const QStringList args = app.arguments();
|
|
const QString gamecenterPath = takeArgValue(args, QStringLiteral("--gamecenter"));
|
|
const QString runnerdPath = takeArgValue(args, QStringLiteral("--runnerd"));
|
|
const QString inputdPath = takeArgValue(args, QStringLiteral("--inputd"));
|
|
|
|
app.setProperty("alakarte_test_gamecenter", gamecenterPath);
|
|
app.setProperty("alakarte_test_runnerd", runnerdPath);
|
|
app.setProperty("alakarte_test_inputd", inputdPath);
|
|
|
|
QStringList filtered;
|
|
filtered.reserve(args.size());
|
|
if (!args.isEmpty()) {
|
|
filtered.push_back(args.first());
|
|
}
|
|
for (int i = 1; i < args.size(); ++i) {
|
|
const QString a = args.at(i);
|
|
if (a == QLatin1String("--gamecenter") || a == QLatin1String("--runnerd")) {
|
|
++i;
|
|
continue;
|
|
}
|
|
if (a == QLatin1String("--inputd")) {
|
|
++i;
|
|
continue;
|
|
}
|
|
filtered.push_back(a);
|
|
}
|
|
|
|
DbusSmokeTest tc;
|
|
return QTest::qExec(&tc, filtered);
|
|
}
|
|
|
|
#include "dbus_smoketest.moc"
|