File indexing completed on 2024-05-12 05:13:45

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "testhelper.h"
0008 #include "mocknetworkaccessmanager.h"
0009 
0010 #include "livedata.h"
0011 #include "livedatamanager.h"
0012 #include "applicationcontroller.h"
0013 #include "reservationmanager.h"
0014 
0015 #include <KItinerary/Reservation>
0016 #include <KItinerary/TrainTrip>
0017 
0018 #include <KPublicTransport/Manager>
0019 
0020 #include <QJsonDocument>
0021 #include <QJsonObject>
0022 #include <QtTest/qtest.h>
0023 #include <QSignalSpy>
0024 #include <QStandardPaths>
0025 #include <QTimeZone>
0026 
0027 #define s(x) QStringLiteral(x)
0028 
0029 using namespace KItinerary;
0030 
0031 static MockNetworkAccessManager s_nam;
0032 static QNetworkAccessManager* namFactory() { return &s_nam; }
0033 
0034 class LiveDataManagerTest : public QObject
0035 {
0036     Q_OBJECT
0037 private Q_SLOTS:
0038     void initTestCase()
0039     {
0040         qputenv("TZ", "UTC");
0041         QStandardPaths::setTestModeEnabled(true);
0042     }
0043 
0044     void testPersistence()
0045     {
0046         LiveData::clearStorage();
0047         QCOMPARE(LiveData::listAll(), std::vector<QString>());
0048 
0049         {
0050             LiveData ld;
0051             ld.departure.setScheduledDepartureTime({{2017, 9, 10}, {11, 0}});
0052             ld.departureTimestamp = {{ 2017, 1, 1} , {0, 0}};
0053             ld.store(s("testId"), LiveData::Departure);
0054         }
0055 
0056         QCOMPARE(LiveData::listAll(), std::vector<QString>({ s("testId") }));
0057 
0058         {
0059             auto ld = LiveData::load(s("testId"));
0060             QCOMPARE(ld.departure.scheduledDepartureTime(), QDateTime({2017, 9, 10}, {11, 0}));
0061             QCOMPARE(ld.departureTimestamp, QDateTime({2017, 1, 1}, {0, 0}));
0062             QVERIFY(!ld.arrivalTimestamp.isValid());
0063             ld.departure = {};
0064             ld.store(s("testId"), LiveData::AllTypes);
0065         }
0066 
0067         QCOMPARE(LiveData::listAll(), std::vector<QString>());
0068     }
0069 
0070     void testLiveData()
0071     {
0072         ReservationManager resMgr;
0073         PkPassManager pkPassMgr;
0074         Test::clearAll(&resMgr);
0075         QSignalSpy resChangeSpy(&resMgr, &ReservationManager::batchContentChanged);
0076         LiveData::clearStorage();
0077 
0078         LiveDataManager ldm;
0079         ldm.setPkPassManager(&pkPassMgr);
0080         QSignalSpy arrivalUpdateSpy(&ldm, &LiveDataManager::arrivalUpdated);
0081         QSignalSpy departureUpdateSpy(&ldm, &LiveDataManager::departureUpdated);
0082         ldm.setPollingEnabled(false); // we don't want to trigger network requests here
0083         QVERIFY(ldm.publicTransportManager());
0084         ldm.m_unitTestTime = QDateTime({2017, 9, 10}, {12, 0}, QTimeZone("Europe/Zurich")); // that's in the middle of the first train leg
0085         ldm.setReservationManager(&resMgr);
0086 
0087         auto ctrl = Test::makeAppController();
0088         ctrl->setReservationManager(&resMgr);
0089         ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/../tests/randa2017.json")));
0090         QCOMPARE(resMgr.batches().size(), 11);
0091 
0092         const auto flight = resMgr.batches()[0];
0093         QVERIFY(!ldm.isRelevant(flight));
0094         QVERIFY(ldm.hasDeparted(flight, resMgr.reservation(flight)));
0095         QVERIFY(ldm.hasArrived(flight, resMgr.reservation(flight)));
0096 
0097         const auto trainLeg1 = resMgr.batches()[1];
0098         QVERIFY(ldm.isRelevant(trainLeg1));
0099         QVERIFY(ldm.hasDeparted(trainLeg1, resMgr.reservation(trainLeg1)));
0100         QVERIFY(!ldm.hasArrived(trainLeg1, resMgr.reservation(trainLeg1)));
0101 
0102         const auto trainLeg2 = resMgr.batches()[2];
0103         QVERIFY(ldm.isRelevant(trainLeg2));
0104         QVERIFY(!ldm.hasDeparted(trainLeg2, resMgr.reservation(trainLeg2)));
0105         QVERIFY(!ldm.hasArrived(trainLeg2, resMgr.reservation(trainLeg2)));
0106 
0107         QCOMPARE(ldm.nextPollTimeForReservation(flight), std::numeric_limits<int>::max());
0108         QCOMPARE(ldm.nextPollTimeForReservation(trainLeg1), 0); // no current data available, so we want to poll ASAP
0109         QCOMPARE(ldm.nextPollTimeForReservation(trainLeg2), 0);
0110         QTest::qWait(0);
0111         QCOMPARE(ldm.nextPollTime(), 0);
0112         QCOMPARE(resMgr.reservation(trainLeg1).value<TrainReservation>().reservationFor().value<TrainTrip>().arrivalStation().address().addressLocality(), QString());
0113 
0114         const auto leg1Arr = KPublicTransport::Stopover::fromJson(QJsonDocument::fromJson(Test::readFile(s(SOURCE_DIR "/data/livedata/randa2017-leg1-arrival.json"))).object());
0115         ldm.stopoverQueryFinished({ leg1Arr }, LiveData::Arrival, trainLeg1);
0116         QCOMPARE(arrivalUpdateSpy.size(), 1);
0117         QCOMPARE(arrivalUpdateSpy.at(0).at(0).toString(), trainLeg1);
0118         QCOMPARE(departureUpdateSpy.size(), 0);
0119         QCOMPARE(ldm.arrival(trainLeg1).arrivalDelay(), 2);
0120         QCOMPARE(ldm.nextPollTimeForReservation(trainLeg1), 15 * 60 * 1000); // 15 min in msecs
0121         // reservation was updated with additional location data
0122         QCOMPARE(resChangeSpy.size(), 1);
0123         QCOMPARE(resChangeSpy.at(0).at(0).toString(), trainLeg1);
0124         QCOMPARE(resMgr.reservation(trainLeg1).value<TrainReservation>().reservationFor().value<TrainTrip>().arrivalStation().address().addressLocality(), QLatin1StringView("Visp"));
0125 
0126         // verify this was persisted
0127         {
0128             LiveDataManager ldm2;
0129             QCOMPARE(ldm.arrival(trainLeg1).arrivalDelay(), 2);
0130         }
0131 
0132         // failed lookups are recorded to avoid a polling loop
0133         ldm.stopoverQueryFinished({ leg1Arr }, LiveData::Departure, trainLeg2);
0134         ldm.stopoverQueryFinished({ leg1Arr }, LiveData::Arrival, trainLeg2);
0135         QCOMPARE(ldm.departure(trainLeg2).stopPoint().isEmpty(), true);
0136         QCOMPARE(ldm.nextPollTimeForReservation(trainLeg2), 15 * 60 * 1000);
0137     }
0138 
0139     void testPkPassUpdate()
0140     {
0141         PkPassManager pkPassMgr;
0142         QSignalSpy passUpdateSpy(&pkPassMgr, &PkPassManager::passUpdated);
0143         pkPassMgr.setNetworkAccessManagerFactory(namFactory);
0144         Test::clearAll(&pkPassMgr);
0145         ReservationManager resMgr;
0146         Test::clearAll(&resMgr);
0147 
0148         LiveData::clearStorage();
0149         LiveDataManager ldm;
0150         ldm.setPkPassManager(&pkPassMgr);
0151         ldm.setPollingEnabled(true);
0152         ldm.m_unitTestTime = QDateTime({2023, 7, 14}, {15, 0, 0}, QTimeZone("Europe/Berlin"));
0153         ldm.setReservationManager(&resMgr);
0154 
0155         auto ctrl = Test::makeAppController();
0156         ctrl->setPkPassManager(&pkPassMgr);
0157         ctrl->setReservationManager(&resMgr);
0158         ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/updateable-boardingpass.pkpass")));
0159 
0160         QCOMPARE(resMgr.batches().size(), 1);
0161         const auto resId = resMgr.batches()[0];
0162         QCOMPARE(ldm.isRelevant(resId), true);
0163         QCOMPARE(ldm.nextPollTimeForReservation(resId), 0);
0164         QTest::qWait(0);
0165 
0166         QCOMPARE(pkPassMgr.passes().size(), 1);
0167         const auto pass = pkPassMgr.pass(pkPassMgr.passes()[0]);
0168         QVERIFY(pass);
0169         QVERIFY(PkPassManager::canUpdate(pass));
0170 
0171         QCOMPARE(s_nam.requests.size(), 1);
0172         QTest::qWait(0); // download failed
0173         QCOMPARE(passUpdateSpy.size(), 0);
0174         QVERIFY(ldm.nextPollTimeForReservation(resId) > 0);
0175         QVERIFY(ldm.nextPollTimeForReservation(resId) <= 30000);
0176         QVERIFY(ldm.pollCooldown(resId) > 0);
0177         QVERIFY(ldm.pollCooldown(resId) <= 30000);
0178         QVERIFY(ldm.nextPollTime() > 0);
0179         QVERIFY(ldm.nextPollTime() <= 30000);
0180 
0181         ldm.m_unitTestTime = QDateTime({2023, 7, 14}, {15, 5, 0}, QTimeZone("Europe/Berlin"));
0182         QCOMPARE(ldm.nextPollTimeForReservation(resId), 0);
0183         QCOMPARE(ldm.pollCooldown(resId), 0);
0184         QCOMPARE(ldm.nextPollTime(), 0);
0185     }
0186 };
0187 
0188 QTEST_GUILESS_MAIN(LiveDataManagerTest)
0189 
0190 #include "livedatamanagertest.moc"