182 lines
6.9 KiB
C++
182 lines
6.9 KiB
C++
#include "testenv.h"
|
|
#include "fixtures.h"
|
|
#include "nettest.h"
|
|
|
|
#include "launcherpaths.h"
|
|
#include "localization.h"
|
|
#include "versionmanifestservice.h"
|
|
|
|
#include <QJsonArray>
|
|
#include <QSignalSpy>
|
|
|
|
namespace {
|
|
const QString kManifest = QStringLiteral("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json");
|
|
}
|
|
|
|
class TestVersionManifestService : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
FakeInternet m_net;
|
|
|
|
private slots:
|
|
void initTestCase() { BILAUNCHER_START_FAKE_INTERNET(m_net); }
|
|
|
|
void init()
|
|
{
|
|
TestEnv::resetLauncherRoot();
|
|
m_net.reset();
|
|
}
|
|
|
|
void loadsSortsAndFilters()
|
|
{
|
|
m_net.route(kManifest, FakeResponse::json(Fixtures::read("mojang/version_manifest_v2.json")));
|
|
VersionManifestService service;
|
|
QSignalSpy changed(&service, &VersionManifestService::versionsChanged);
|
|
QSignalSpy refreshing(&service, &VersionManifestService::refreshingChanged);
|
|
CallResult result;
|
|
service.ensureLoaded(result.callback());
|
|
QVERIFY(service.isRefreshing());
|
|
QTRY_COMPARE_WITH_TIMEOUT(result.calls, 1, 15000);
|
|
QVERIFY(result.ok);
|
|
QVERIFY(result.warning.isEmpty());
|
|
QVERIFY(!service.isRefreshing());
|
|
QCOMPARE(changed.count(), 1);
|
|
QCOMPARE(refreshing.count(), 2);
|
|
|
|
// Новые первыми; без id и с http-ссылкой — выброшены.
|
|
QStringList ids;
|
|
for (const RemoteVersionEntry &entry : service.versions())
|
|
ids << entry.id;
|
|
QCOMPARE(ids, QStringList({"25w33a", "1.21.8", "1.20.1", "b1.7.3"}));
|
|
|
|
const auto entry = service.find("1.20.1");
|
|
QVERIFY(entry.has_value());
|
|
QCOMPARE(entry->type, QStringLiteral("release"));
|
|
QCOMPARE(entry->sha1, QStringLiteral("aaaa"));
|
|
QCOMPARE(entry->url, QUrl("https://piston-meta.mojang.com/v1/packages/aaaa/1.20.1.json"));
|
|
QCOMPARE(entry->releaseTime, QDateTime(QDate(2023, 6, 12), QTime(13, 25, 51), QTimeZone::UTC));
|
|
QVERIFY(!service.find("insecure").has_value());
|
|
QVERIFY(service.fetchedAt().isValid());
|
|
|
|
// Кеш на диске записан.
|
|
const QJsonObject cache = Fixtures::readJsonFile(LauncherPaths::versionManifestFile());
|
|
QCOMPARE(cache.value("versions").toArray().size(), 4);
|
|
QVERIFY(!cache.value("fetchedAt").toString().isEmpty());
|
|
}
|
|
|
|
void freshCacheAvoidsNetwork()
|
|
{
|
|
m_net.route(kManifest, FakeResponse::json(Fixtures::read("mojang/version_manifest_v2.json")));
|
|
{
|
|
VersionManifestService first;
|
|
CallResult r;
|
|
first.ensureLoaded(r.callback());
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 15000);
|
|
}
|
|
QCOMPARE(m_net.hits(kManifest), 1);
|
|
|
|
// Новый экземпляр (как после перезапуска лаунчера) берёт свежий кеш.
|
|
VersionManifestService second;
|
|
CallResult r;
|
|
second.ensureLoaded(r.callback());
|
|
QVERIFY(second.hasData()); // данные из кеша уже доступны синхронно
|
|
QCOMPARE(r.calls, 0); // колбэк — только через цикл событий
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 5000);
|
|
QVERIFY(r.ok);
|
|
QCOMPARE(m_net.hits(kManifest), 1);
|
|
|
|
// forceRefresh идёт в сеть даже при свежем кеше.
|
|
CallResult forced;
|
|
second.ensureLoaded(forced.callback(), true);
|
|
QTRY_COMPARE_WITH_TIMEOUT(forced.calls, 1, 15000);
|
|
QCOMPARE(m_net.hits(kManifest), 2);
|
|
}
|
|
|
|
void staleCacheIsRefreshed()
|
|
{
|
|
QJsonObject cache = Fixtures::readJson("mojang/version_manifest_v2.json");
|
|
cache["fetchedAt"] = QDateTime::currentDateTimeUtc().addDays(-2).toString(Qt::ISODate);
|
|
Fixtures::writeJson(LauncherPaths::versionManifestFile(), cache);
|
|
|
|
m_net.route(kManifest, FakeResponse::json(Fixtures::read("mojang/version_manifest_v2.json")));
|
|
VersionManifestService service;
|
|
CallResult r;
|
|
service.ensureLoaded(r.callback());
|
|
QVERIFY(service.hasData());
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 15000);
|
|
QCOMPARE(m_net.hits(kManifest), 1);
|
|
}
|
|
|
|
void networkErrorWithoutCacheFails()
|
|
{
|
|
m_net.route(kManifest, FakeResponse::error(503));
|
|
VersionManifestService service;
|
|
CallResult r;
|
|
service.ensureLoaded(r.callback());
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 15000);
|
|
QVERIFY(!r.ok);
|
|
QVERIFY(r.warning.startsWith(Loc::text("version.error.manifestFetchFailed").section(u'%', 0, 0)));
|
|
QVERIFY(!service.hasData());
|
|
}
|
|
|
|
void networkErrorWithCacheSucceedsWithWarning()
|
|
{
|
|
QJsonObject cache = Fixtures::readJson("mojang/version_manifest_v2.json");
|
|
cache["fetchedAt"] = QDateTime::currentDateTimeUtc().addDays(-2).toString(Qt::ISODate);
|
|
Fixtures::writeJson(LauncherPaths::versionManifestFile(), cache);
|
|
m_net.route(kManifest, FakeResponse::error(500));
|
|
|
|
VersionManifestService service;
|
|
CallResult r;
|
|
service.ensureLoaded(r.callback());
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 15000);
|
|
QVERIFY(r.ok); // офлайн, но список есть
|
|
QVERIFY(!r.warning.isEmpty());
|
|
QCOMPARE(service.versions().size(), 4);
|
|
}
|
|
|
|
void garbageResponseIsRejected()
|
|
{
|
|
m_net.route(kManifest, FakeResponse::json("{\"versions\": []}"));
|
|
VersionManifestService service;
|
|
CallResult r;
|
|
service.ensureLoaded(r.callback());
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 15000);
|
|
QVERIFY(!r.ok);
|
|
QCOMPARE(r.warning, Loc::text("version.error.manifestUnparsable"));
|
|
QVERIFY(!QFile::exists(LauncherPaths::versionManifestFile()));
|
|
}
|
|
|
|
void concurrentCallersShareOneRequest()
|
|
{
|
|
FakeResponse slow = FakeResponse::json(Fixtures::read("mojang/version_manifest_v2.json"));
|
|
slow.delayMs = 300;
|
|
m_net.route(kManifest, slow);
|
|
VersionManifestService service;
|
|
CallResult a, b, c;
|
|
service.ensureLoaded(a.callback());
|
|
service.ensureLoaded(b.callback());
|
|
service.ensureLoaded(c.callback());
|
|
QTRY_VERIFY_WITH_TIMEOUT(a.calls == 1 && b.calls == 1 && c.calls == 1, 15000);
|
|
QVERIFY(a.ok && b.ok && c.ok);
|
|
QCOMPARE(m_net.hits(kManifest), 1);
|
|
}
|
|
|
|
void corruptCacheIsIgnored()
|
|
{
|
|
Fixtures::write(LauncherPaths::versionManifestFile(), "\x00\x01garbage");
|
|
m_net.route(kManifest, FakeResponse::json(Fixtures::read("mojang/version_manifest_v2.json")));
|
|
VersionManifestService service;
|
|
CallResult r;
|
|
service.ensureLoaded(r.callback());
|
|
QVERIFY(!service.hasData());
|
|
QTRY_COMPARE_WITH_TIMEOUT(r.calls, 1, 15000);
|
|
QVERIFY(r.ok);
|
|
QVERIFY(service.hasData());
|
|
}
|
|
};
|
|
|
|
BILAUNCHER_TEST_MAIN(TestVersionManifestService)
|
|
#include "tst_versionmanifestservice.moc"
|