tests: recover sessions after gamecenter restart

This commit is contained in:
Marco Allegretti 2026-02-14 13:34:10 +01:00
parent 57d1e6e130
commit 8891e85dbc

View file

@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2026 A-La-Karte Contributors
#include <QCoreApplication>
#include <QDBusArgument>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusInterface>
@ -53,6 +54,27 @@ static bool waitForService(QDBusConnection &bus, const QString &service, int tim
return false;
}
static QVariant unwrapDbusVariant(QVariant v)
{
if (v.canConvert<QDBusVariant>()) {
v = v.value<QDBusVariant>().variant();
}
return v;
}
static QVariantMap unwrapVariantMap(QVariant v)
{
v = unwrapDbusVariant(v);
if (v.canConvert<QDBusArgument>()) {
const QDBusArgument arg = v.value<QDBusArgument>();
return qdbus_cast<QVariantMap>(arg);
}
if (v.canConvert<QVariantMap>()) {
return v.toMap();
}
return {};
}
static QByteArray readProcFile(const QString &path, qint64 maxSize = 65536)
{
QFile f(path);
@ -226,6 +248,8 @@ private Q_SLOTS:
void stopDirectLaunch();
void stopByGameIdDirectLaunch();
void recoverSessionsAfterDaemonRestart();
private:
QString m_gamecenterPath;
QProcess m_gamecenter;
@ -351,6 +375,78 @@ void StopLaunchingRegressionTest::cleanupTestCase()
}
}
void StopLaunchingRegressionTest::recoverSessionsAfterDaemonRestart()
{
QDBusConnection bus = QDBusConnection::sessionBus();
if (!bus.isConnected()) {
QSKIP("session bus not available");
}
QDBusInterface iface(QStringLiteral("org.kde.GameCenter1"), QStringLiteral("/org/kde/ALaKarte/GameCenter1"), QStringLiteral("org.kde.GameCenter1"), bus);
QVERIFY2(iface.isValid(), "GameCenter1 DBus interface not valid");
const QByteArray markerNeedle = (QStringLiteral("ALAKARTE_TEST_MARKER=") + m_markerValue).toUtf8();
killPids(pidsWithEnvironEntry(markerNeedle));
const QString envExe = QStandardPaths::findExecutable(QStringLiteral("env"));
if (envExe.isEmpty()) {
QSKIP("env executable not found");
}
const QString gameId = QStringLiteral("test-reattach-%1").arg(QUuid::createUuid().toString(QUuid::WithoutBraces));
QVariantMap spec;
spec.insert(QStringLiteral("provider"), QStringLiteral("manual"));
spec.insert(QStringLiteral("program"), envExe);
spec.insert(QStringLiteral("args"),
QStringList{QStringLiteral("ALAKARTE_TEST_MARKER=%1").arg(m_markerValue), QStringLiteral("/bin/sleep"), QStringLiteral("60")});
spec.insert(QStringLiteral("gameId"), gameId);
const QDBusReply<QString> launchReply = iface.call(QStringLiteral("Launch"), spec);
QVERIFY2(launchReply.isValid(), qPrintable(launchReply.error().message()));
const QString sessionId = launchReply.value();
QVERIFY2(!sessionId.isEmpty(), "Launch returned empty sessionId");
const QString unitName = QStringLiteral("alakarte-game-%1.scope").arg(sessionId);
QVERIFY2(waitForAnyEnvironEntry(markerNeedle, 5000), "direct launch marker process did not appear");
m_gamecenter.kill();
QVERIFY(m_gamecenter.waitForFinished(5000));
QVERIFY2(waitForNoEnvironEntry(markerNeedle, 1000) == false, "marker process unexpectedly disappeared after daemon kill");
m_gamecenter.start();
QVERIFY(m_gamecenter.waitForStarted(5000));
QVERIFY2(waitForService(bus, QStringLiteral("org.kde.GameCenter1"), 5000), "GameCenter1 service did not re-appear after restart");
QDBusInterface iface2(QStringLiteral("org.kde.GameCenter1"), QStringLiteral("/org/kde/ALaKarte/GameCenter1"), QStringLiteral("org.kde.GameCenter1"), bus);
QVERIFY2(iface2.isValid(), "GameCenter1 DBus interface not valid after restart");
const QDBusReply<QVariantList> listReply = iface2.call(QStringLiteral("ListSessions"));
QVERIFY2(listReply.isValid(), qPrintable(listReply.error().message()));
bool found = false;
for (const QVariant &v : listReply.value()) {
const QVariantMap m = unwrapVariantMap(v);
if (m.value(QStringLiteral("sessionId")).toString() == sessionId) {
found = true;
QCOMPARE(m.value(QStringLiteral("gameId")).toString(), gameId);
QCOMPARE(m.value(QStringLiteral("state")).toString(), QStringLiteral("Running"));
break;
}
}
QVERIFY2(found, "expected recovered session not found in ListSessions() after restart");
const QDBusReply<void> stopReply = iface2.call(QStringLiteral("Stop"), sessionId);
QVERIFY2(stopReply.isValid(), qPrintable(stopReply.error().message()));
const bool cleaned = waitForNoEnvironEntry(markerNeedle, 15000);
if (!cleaned) {
killPids(pidsWithEnvironEntry(markerNeedle));
}
QVERIFY2(cleaned, "marker process still alive after Stop() on recovered session");
QVERIFY2(waitForUnitNotActive(unitName, 15000), "systemd unit still active after Stop() on recovered session");
}
void StopLaunchingRegressionTest::stopWhileLaunchingSteam()
{
QDBusConnection bus = QDBusConnection::sessionBus();