From a02e62f17f7b51c489e209ab6937ad717fbcfb07 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 14 Dec 2013 16:02:51 +0100 Subject: Tests for parsing of channel lists in UpdateChecker --- logic/updater/UpdateChecker.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'logic/updater/UpdateChecker.h') diff --git a/logic/updater/UpdateChecker.h b/logic/updater/UpdateChecker.h index 59fb8e47..131f49a2 100644 --- a/logic/updater/UpdateChecker.h +++ b/logic/updater/UpdateChecker.h @@ -27,6 +27,9 @@ public: UpdateChecker(); void checkForUpdate(); + void setCurrentChannel(const QString &channel) { m_currentChannel = channel; } + void setChannelListUrl(const QString &url) { m_channelListUrl = url; } + /*! * Causes the update checker to download the channel list from the URL specified in config.h (generated by CMake). * If this isn't called before checkForUpdate(), it will automatically be called. -- cgit From f273334212274b1f1c7da376ef186314de8c4428 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Sat, 14 Dec 2013 19:19:14 +0100 Subject: More tests for the UpdateChecker class. It should be done for now. --- MultiMC.h | 2 ++ logic/updater/UpdateChecker.h | 2 ++ tests/data/errorChannels.json | 23 ++++++++++++ tests/data/garbageChannels.json | 22 ++++++++++++ tests/data/index.json | 9 +++++ tests/tst_UpdateChecker.cpp | 77 ++++++++++++++++++++++++++++++++++++++--- 6 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 tests/data/errorChannels.json create mode 100644 tests/data/garbageChannels.json create mode 100644 tests/data/index.json (limited to 'logic/updater/UpdateChecker.h') diff --git a/MultiMC.h b/MultiMC.h index 7bfa0023..5723b2b0 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -124,6 +124,8 @@ private: void initTranslations(); private: + friend class UpdateCheckerTest; + std::shared_ptr m_qt_translator; std::shared_ptr m_mmc_translator; std::shared_ptr m_settings; diff --git a/logic/updater/UpdateChecker.h b/logic/updater/UpdateChecker.h index 131f49a2..5b7efc05 100644 --- a/logic/updater/UpdateChecker.h +++ b/logic/updater/UpdateChecker.h @@ -73,6 +73,8 @@ private slots: void chanListDownloadFailed(); private: + friend class UpdateCheckerTest; + NetJobPtr indexJob; NetJobPtr chanListJob; diff --git a/tests/data/errorChannels.json b/tests/data/errorChannels.json new file mode 100644 index 00000000..333cd445 --- /dev/null +++ b/tests/data/errorChannels.json @@ -0,0 +1,23 @@ +{ + "format_version": 0, + "channels": [ + { + "id": "", + "name": "Develop", + "description": "The channel called \"develop\"", + "url": "http://example.org/stuff" + }, + { + "id": "stable", + "name": "", + "description": "It's stable at least", + "url": "ftp://username@host/path/to/stuff" + }, + { + "id": "42", + "name": "The Channel", + "description": "This is the channel that is going to answer all of your questions", + "url": "" + } + ] +} diff --git a/tests/data/garbageChannels.json b/tests/data/garbageChannels.json new file mode 100644 index 00000000..1450fb9c --- /dev/null +++ b/tests/data/garbageChannels.json @@ -0,0 +1,22 @@ +{ + "format_version": 0, + "channels": [ + { + "id": "develop", + "name": "Develop", + "description": "The channel called \"develop\"", +aa "url": "http://example.org/stuff" + }, +a "id": "stable", + "name": "Stable", + "description": "It's stable at least", + "url": "ftp://username@host/path/to/stuff" + }, + { + "id": "42"f + "name": "The Channel", + "description": "This is the channel that is going to answer all of your questions", + "url": "https://dent.me/tea" + } + ] +} diff --git a/tests/data/index.json b/tests/data/index.json new file mode 100644 index 00000000..20ceb9f4 --- /dev/null +++ b/tests/data/index.json @@ -0,0 +1,9 @@ +{ + "ApiVersion": 0, + "Versions": [ + { "Id": 0, "Name": "1.0.0" }, + { "Id": 1, "Name": "1.0.1" }, + { "Id": 2, "Name": "1.0.2" }, + { "Id": 3, "Name": "1.0.3" } + ] +} diff --git a/tests/tst_UpdateChecker.cpp b/tests/tst_UpdateChecker.cpp index a73dc1fd..302473f7 100644 --- a/tests/tst_UpdateChecker.cpp +++ b/tests/tst_UpdateChecker.cpp @@ -37,22 +37,38 @@ slots: QTest::addColumn("channel"); QTest::addColumn("channelUrl"); QTest::addColumn("hasChannels"); + QTest::addColumn("valid"); QTest::addColumn >("result"); + QTest::newRow("garbage") + << QString() + << findTestDataUrl("tests/data/garbageChannels.json") + << false + << false + << QList(); + QTest::newRow("errors") + << QString() + << findTestDataUrl("tests/data/errorChannels.json") + << false + << true + << QList(); QTest::newRow("no channels") << QString() << findTestDataUrl("tests/data/noChannels.json") << false + << true << QList(); QTest::newRow("one channel") << QString("develop") << findTestDataUrl("tests/data/oneChannel.json") << true + << true << (QList() << UpdateChecker::ChannelListEntry{"develop", "Develop", "The channel called \"develop\"", "http://example.org/stuff"}); QTest::newRow("several channels") << QString("develop") << findTestDataUrl("tests/data/channels.json") << true + << true << (QList() << UpdateChecker::ChannelListEntry{"develop", "Develop", "The channel called \"develop\"", "http://example.org/stuff"} << UpdateChecker::ChannelListEntry{"stable", "Stable", "It's stable at least", "ftp://username@host/path/to/stuff"} @@ -63,25 +79,78 @@ slots: QFETCH(QString, channel); QFETCH(QString, channelUrl); QFETCH(bool, hasChannels); + QFETCH(bool, valid); QFETCH(QList, result); UpdateChecker checker; - QSignalSpy spy(&checker, SIGNAL(channelListLoaded())); - QVERIFY(spy.isValid()); + QSignalSpy channelListLoadedSpy(&checker, SIGNAL(channelListLoaded())); + QVERIFY(channelListLoadedSpy.isValid()); checker.setCurrentChannel(channel); checker.setChannelListUrl(channelUrl); checker.updateChanList(); - QVERIFY(spy.wait()); + if (valid) + { + QVERIFY(channelListLoadedSpy.wait()); + QCOMPARE(channelListLoadedSpy.size(), 1); + } + else + { + channelListLoadedSpy.wait(); + QCOMPARE(channelListLoadedSpy.size(), 0); + } - QCOMPARE(spy.size(), 1); QCOMPARE(checker.hasChannels(), hasChannels); QCOMPARE(checker.getChannelList(), result); } + + void tst_UpdateChecking_data() + { + QTest::addColumn("channel"); + QTest::addColumn("channelUrl"); + QTest::addColumn("currentBuild"); + QTest::addColumn >("result"); + + QTest::newRow("valid channel") + << "develop" << findTestDataUrl("tests/data/channels.json") + << 2 + << (QList() << QString() << "1.0.3" << 3); + } + + void tst_UpdateChecking() + { + QFETCH(QString, channel); + QFETCH(QString, channelUrl); + QFETCH(int, currentBuild); + QFETCH(QList, result); + + MMC->m_version.build = currentBuild; + + UpdateChecker checker; + checker.setCurrentChannel(channel); + checker.setChannelListUrl(channelUrl); + + QSignalSpy updateAvailableSpy(&checker, SIGNAL(updateAvailable(QString,QString,int))); + QVERIFY(updateAvailableSpy.isValid()); + QSignalSpy channelListLoadedSpy(&checker, SIGNAL(channelListLoaded())); + QVERIFY(channelListLoadedSpy.isValid()); + + checker.updateChanList(); + QVERIFY(channelListLoadedSpy.wait()); + + checker.m_channels[0].url = QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(); + + checker.checkForUpdate(); + + QVERIFY(updateAvailableSpy.wait()); + QList res = result; + res[0] = checker.m_channels[0].url; + QCOMPARE(updateAvailableSpy.first(), res); + } }; QTEST_GUILESS_MAIN_MULTIMC(UpdateCheckerTest) -- cgit From b1ec7841e04f2a60f54895e1646bc33486fd9fbf Mon Sep 17 00:00:00 2001 From: robotbrainify Date: Tue, 24 Dec 2013 16:00:07 -0500 Subject: Get the updater to display a no update found message. --- gui/MainWindow.cpp | 5 ++- logic/updater/UpdateChecker.cpp | 71 +++++++++++++++++++++++++---------------- logic/updater/UpdateChecker.h | 6 ++-- tests/tst_UpdateChecker.cpp | 2 +- 4 files changed, 53 insertions(+), 31 deletions(-) (limited to 'logic/updater/UpdateChecker.h') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 179f881f..7241f26b 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -681,7 +681,10 @@ void MainWindow::on_actionConfig_Folder_triggered() void MainWindow::on_actionCheckUpdate_triggered() { auto updater = MMC->updateChecker(); - updater->checkForUpdate(); + connect(updater.get(), &UpdateChecker::noUpdateFound, [this](){ + CustomMessageBox::selectable(this, "No update found.", "No MultiMC update was found!\nYou are using the latest version.")->exec(); + }); + updater->checkForUpdate(true); } void MainWindow::on_actionSettings_triggered() diff --git a/logic/updater/UpdateChecker.cpp b/logic/updater/UpdateChecker.cpp index af56288c..d0795c0d 100644 --- a/logic/updater/UpdateChecker.cpp +++ b/logic/updater/UpdateChecker.cpp @@ -47,14 +47,16 @@ bool UpdateChecker::hasChannels() const return !m_channels.isEmpty(); } -void UpdateChecker::checkForUpdate() +void UpdateChecker::checkForUpdate(bool notifyNoUpdate) { QLOG_DEBUG() << "Checking for updates."; - // If the channel list hasn't loaded yet, load it and defer checking for updates until later. + // If the channel list hasn't loaded yet, load it and defer checking for updates until + // later. if (!m_chanListLoaded) { - QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring update check."; + QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring " + "update check."; m_checkUpdateWaiting = true; updateChanList(); return; @@ -72,7 +74,8 @@ void UpdateChecker::checkForUpdate() // TODO: Allow user to select channels. For now, we'll just use the current channel. QString updateChannel = m_currentChannel; - // Find the desired channel within the channel list and get its repo URL. If if cannot be found, error. + // Find the desired channel within the channel list and get its repo URL. If if cannot be + // found, error. m_repoUrl = ""; for (ChannelListEntry entry : m_channels) { @@ -91,20 +94,22 @@ void UpdateChecker::checkForUpdate() auto job = new NetJob("GoUpdate Repository Index"); job->addNetAction(ByteArrayDownload::make(indexUrl)); - connect(job, SIGNAL(succeeded()), SLOT(updateCheckFinished())); + connect(job, &NetJob::succeeded, [this, notifyNoUpdate]() + { updateCheckFinished(notifyNoUpdate); }); connect(job, SIGNAL(failed()), SLOT(updateCheckFailed())); indexJob.reset(job); job->start(); } -void UpdateChecker::updateCheckFinished() +void UpdateChecker::updateCheckFinished(bool notifyNoUpdate) { QLOG_DEBUG() << "Finished downloading repo index. Checking for new versions."; QJsonParseError jsonError; QByteArray data; { - ByteArrayDownloadPtr dl = std::dynamic_pointer_cast(indexJob->first()); + ByteArrayDownloadPtr dl = + std::dynamic_pointer_cast(indexJob->first()); data = dl->m_data; indexJob.reset(); } @@ -112,7 +117,8 @@ void UpdateChecker::updateCheckFinished() QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); if (jsonError.error != QJsonParseError::NoError || !jsonDoc.isObject()) { - QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" << jsonError.errorString() << "at offset" << jsonError.offset; + QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" + << jsonError.errorString() << "at offset" << jsonError.offset; return; } @@ -122,7 +128,8 @@ void UpdateChecker::updateCheckFinished() int apiVersion = object.value("ApiVersion").toVariant().toInt(&success); if (apiVersion != API_VERSION || !success) { - QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" << API_VERSION << "server has" << apiVersion; + QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" + << API_VERSION << "server has" << apiVersion; return; } @@ -132,19 +139,27 @@ void UpdateChecker::updateCheckFinished() for (QJsonValue versionVal : versions) { QJsonObject version = versionVal.toObject(); - if (newestVersion.value("Id").toVariant().toInt() < version.value("Id").toVariant().toInt()) + if (newestVersion.value("Id").toVariant().toInt() < + version.value("Id").toVariant().toInt()) { - QLOG_DEBUG() << "Found newer version with ID" << version.value("Id").toVariant().toInt(); + QLOG_DEBUG() << "Found newer version with ID" + << version.value("Id").toVariant().toInt(); newestVersion = version; } } - // We've got the version with the greatest ID number. Now compare it to our current build number and update if they're different. + // We've got the version with the greatest ID number. Now compare it to our current build + // number and update if they're different. int newBuildNumber = newestVersion.value("Id").toVariant().toInt(); if (newBuildNumber != MMC->version().build) { // Update! - emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), newBuildNumber); + emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), + newBuildNumber); + } + else if (notifyNoUpdate) + { + emit noUpdateFound(); } m_updateChecking = false; @@ -163,12 +178,13 @@ void UpdateChecker::updateChanList() if (m_channelListUrl.isEmpty()) { QLOG_ERROR() << "Failed to update channel list. No channel list URL set." - << "If you'd like to use MultiMC's update system, please pass the channel list URL to CMake at compile time."; + << "If you'd like to use MultiMC's update system, please pass the channel " + "list URL to CMake at compile time."; return; } m_chanListLoading = true; - NetJob* job = new NetJob("Update System Channel List"); + NetJob *job = new NetJob("Update System Channel List"); job->addNetAction(ByteArrayDownload::make(QUrl(m_channelListUrl))); QObject::connect(job, &NetJob::succeeded, this, &UpdateChecker::chanListDownloadFinished); QObject::connect(job, &NetJob::failed, this, &UpdateChecker::chanListDownloadFailed); @@ -180,7 +196,8 @@ void UpdateChecker::chanListDownloadFinished() { QByteArray data; { - ByteArrayDownloadPtr dl = std::dynamic_pointer_cast(chanListJob->first()); + ByteArrayDownloadPtr dl = + std::dynamic_pointer_cast(chanListJob->first()); data = dl->m_data; chanListJob.reset(); } @@ -190,17 +207,20 @@ void UpdateChecker::chanListDownloadFinished() if (jsonError.error != QJsonParseError::NoError) { // TODO: Report errors to the user. - QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" << jsonError.offset; + QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" + << jsonError.offset; return; } - + QJsonObject object = jsonDoc.object(); bool success = false; int formatVersion = object.value("format_version").toVariant().toInt(&success); if (formatVersion != CHANLIST_FORMAT || !success) { - QLOG_ERROR() << "Failed to check for updates. Channel list format version mismatch. We're using" << CHANLIST_FORMAT << "server has" << formatVersion; + QLOG_ERROR() + << "Failed to check for updates. Channel list format version mismatch. We're using" + << CHANLIST_FORMAT << "server has" << formatVersion; return; } @@ -210,12 +230,10 @@ void UpdateChecker::chanListDownloadFinished() for (QJsonValue chanVal : channelArray) { QJsonObject channelObj = chanVal.toObject(); - ChannelListEntry entry{ - channelObj.value("id").toVariant().toString(), - channelObj.value("name").toVariant().toString(), - channelObj.value("description").toVariant().toString(), - channelObj.value("url").toVariant().toString() - }; + ChannelListEntry entry{channelObj.value("id").toVariant().toString(), + channelObj.value("name").toVariant().toString(), + channelObj.value("description").toVariant().toString(), + channelObj.value("url").toVariant().toString()}; if (entry.id.isEmpty() || entry.name.isEmpty() || entry.url.isEmpty()) { QLOG_ERROR() << "Channel list entry with empty ID, name, or URL. Skipping."; @@ -233,7 +251,7 @@ void UpdateChecker::chanListDownloadFinished() // If we're waiting to check for updates, do that now. if (m_checkUpdateWaiting) - checkForUpdate(); + checkForUpdate(false); emit channelListLoaded(); } @@ -244,4 +262,3 @@ void UpdateChecker::chanListDownloadFailed() QLOG_ERROR() << "Failed to download channel list."; emit channelListLoaded(); } - diff --git a/logic/updater/UpdateChecker.h b/logic/updater/UpdateChecker.h index 5b7efc05..a47e8903 100644 --- a/logic/updater/UpdateChecker.h +++ b/logic/updater/UpdateChecker.h @@ -25,7 +25,7 @@ class UpdateChecker : public QObject public: UpdateChecker(); - void checkForUpdate(); + void checkForUpdate(bool notifyNoUpdate); void setCurrentChannel(const QString &channel) { m_currentChannel = channel; } void setChannelListUrl(const QString &url) { m_channelListUrl = url; } @@ -65,8 +65,10 @@ signals: //! Signal emitted when the channel list finishes loading or fails to load. void channelListLoaded(); + void noUpdateFound(); + private slots: - void updateCheckFinished(); + void updateCheckFinished(bool notifyNoUpdate); void updateCheckFailed(); void chanListDownloadFinished(); diff --git a/tests/tst_UpdateChecker.cpp b/tests/tst_UpdateChecker.cpp index af3ae802..162d0009 100644 --- a/tests/tst_UpdateChecker.cpp +++ b/tests/tst_UpdateChecker.cpp @@ -149,7 +149,7 @@ slots: checker.m_channels[0].url = QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(); - checker.checkForUpdate(); + checker.checkForUpdate(false); QVERIFY(updateAvailableSpy.wait()); QList res = result; -- cgit