Files
bearwave/tests/radiobrowser_race_test.cpp
Sebastian Palencsar 722f417c53 fix(ci): run Qt tests headless in Docker/CI
Use QCoreApplication for the race test, set QT_QPA_PLATFORM=offscreen
and QT_MEDIA_BACKEND=ffmpeg for playback tests, and export the same vars
in CI before ctest to avoid subprocess aborts without a display.
2026-06-21 08:56:03 +02:00

110 lines
3.7 KiB
C++

// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QtTest>
#include <QCoreApplication>
#include <QSignalSpy>
#include <QTemporaryDir>
#include <QDir>
#include <QFile>
#include <QCryptographicHash>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QEventLoop>
#include <QTimer>
#include "radiobrowser.h"
class RadioBrowserRaceTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void latest_request_wins_after_rapid_category_switch();
};
namespace {
QTemporaryDir *s_tempHome = nullptr;
QString cachePathForEndpoint(const QString &endpoint)
{
const QString cacheDir = QDir::homePath() + QStringLiteral("/.cache/bearwave/api_cache");
const QString hash = QString(QCryptographicHash::hash(endpoint.toUtf8(), QCryptographicHash::Md5).toHex());
return cacheDir + QStringLiteral("/") + hash + QStringLiteral(".json");
}
void writeStationCache(const QString &endpoint, const QString &name, const QString &country)
{
QDir().mkpath(QDir::homePath() + QStringLiteral("/.cache/bearwave/api_cache"));
QJsonObject station;
station.insert(QStringLiteral("name"), name);
station.insert(QStringLiteral("url_resolved"), QStringLiteral("http://example.com/") + name);
station.insert(QStringLiteral("country"), country);
station.insert(QStringLiteral("stationuuid"), name);
QJsonArray array;
array.append(station);
QFile file(cachePathForEndpoint(endpoint));
QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Truncate));
file.write(QJsonDocument(array).toJson());
file.close();
}
}
void RadioBrowserRaceTest::initTestCase()
{
s_tempHome = new QTemporaryDir();
QVERIFY(s_tempHome->isValid());
qputenv("HOME", s_tempHome->path().toUtf8());
writeStationCache(QStringLiteral("/stations/topvote/5"), QStringLiteral("Top Station"), QStringLiteral("Global"));
writeStationCache(QStringLiteral("/stations/bycountrycodeexact/DE?limit=50&order=votes&reverse=true"),
QStringLiteral("DE Station"), QStringLiteral("Germany"));
writeStationCache(QStringLiteral("/stations/bycountrycodeexact/NL?limit=50&order=votes&reverse=true"),
QStringLiteral("NL Station"), QStringLiteral("The Netherlands"));
}
void RadioBrowserRaceTest::latest_request_wins_after_rapid_category_switch()
{
RadioBrowser browser;
QSignalSpy stationsSpy(&browser, &RadioBrowser::stationsLoaded);
browser.getTopStations(5);
browser.getGermanStations();
browser.getDutchStations();
QCOMPARE(stationsSpy.count(), 3);
const auto lastVariant = stationsSpy.at(2).at(0);
const QList<RadioStation*> lastStations = lastVariant.value<QList<RadioStation*>>();
QVERIFY(!lastStations.isEmpty());
QCOMPARE(lastStations.first()->name(), QStringLiteral("NL Station"));
QEventLoop loop;
QTimer::singleShot(2000, &loop, &QEventLoop::quit);
loop.exec();
const auto finalVariant = stationsSpy.takeLast().at(0);
const QList<RadioStation*> finalStations = finalVariant.value<QList<RadioStation*>>();
QVERIFY(!finalStations.isEmpty());
const QString finalName = finalStations.first()->name();
const QString finalCountry = finalStations.first()->country();
QVERIFY(finalName != QStringLiteral("Top Station"));
QVERIFY(finalName != QStringLiteral("DE Station"));
QVERIFY(finalCountry.contains(QStringLiteral("Netherlands"), Qt::CaseInsensitive)
|| finalName == QStringLiteral("NL Station"));
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
RadioBrowserRaceTest test;
return QTest::qExec(&test, argc, argv);
}
#include "radiobrowser_race_test.moc"