File indexing completed on 2024-05-12 05:26:24

0001 #include <QTest>
0002 
0003 #include <QString>
0004 #include <QSignalSpy>
0005 
0006 #include "store.h"
0007 #include "resourceconfig.h"
0008 #include "resourcecontrol.h"
0009 #include "modelresult.h"
0010 #include "log.h"
0011 #include "test.h"
0012 #include "notifier.h"
0013 #include "notification.h"
0014 
0015 using namespace Sink;
0016 using namespace Sink::ApplicationDomain;
0017 
0018 /**
0019  * Test of complete system using the dummy resource.
0020  *
0021  * This test requires the dummy resource installed.
0022  */
0023 class NotificationTest : public QObject
0024 {
0025     Q_OBJECT
0026 
0027 private slots:
0028     void initTestCase()
0029     {
0030         Sink::Test::initTest();
0031         ResourceConfig::addResource("sink.dummy.instance1", "sink.dummy");
0032         ResourceConfig::configureResource("sink.dummy.instance1", {{"populate", true}});
0033     }
0034 
0035     void cleanup()
0036     {
0037         VERIFYEXEC(Sink::Store::removeDataFromDisk("sink.dummy.instance1"));
0038     }
0039 
0040     void testSyncNotifications()
0041     {
0042         auto query = Query().resourceFilter("sink.dummy.instance1");
0043         query.setType<ApplicationDomain::Mail>();
0044         query.filter("id1");
0045         query.filter("id2");
0046 
0047         QList<Sink::Notification> statusNotifications;
0048         QList<Sink::Notification> infoNotifications;
0049         Sink::Notifier notifier("sink.dummy.instance1");
0050         notifier.registerHandler([&] (const Sink::Notification &n){
0051             SinkLogCtx(Sink::Log::Context{"dummyresourcetest"}) << "Received notification " << n;
0052             if (n.type == Notification::Status) {
0053                 if (n.id == "changereplay") {
0054                     //We filter all changereplay notifications.
0055                     //Not the best way but otherwise the test becomes unstable and we currently
0056                     //only have the id to detect changereplay notifications.
0057                     return;
0058                 }
0059                 statusNotifications << n;
0060             }
0061             if (n.type == Notification::Info) {
0062                 infoNotifications << n;
0063             }
0064         });
0065 
0066         // Ensure all local data is processed
0067         VERIFYEXEC(Sink::Store::synchronize(query));
0068         VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1"));
0069 
0070         using namespace Sink::ApplicationDomain;
0071         {
0072             QList<Status> expected = {
0073                 Status::ConnectedStatus,
0074                 Status::BusyStatus,
0075                 Status::ConnectedStatus,
0076             };
0077             qInfo() << "Received notifications " << statusNotifications;
0078             QVERIFY2(statusNotifications.size() <= expected.size(), "More notifications than expected.");
0079             QTRY_COMPARE(statusNotifications.size(), expected.size());
0080             qInfo() << "All received notifications " << statusNotifications;
0081             for (auto i = 0; i < statusNotifications.size(); i++) {
0082                 QCOMPARE(statusNotifications.at(i).code, static_cast<int>(expected.at(i)));
0083             }
0084         }
0085         //Changereplay
0086         // It can happen that we get a changereplay notification pair first and then a second one at the end,
0087         // we therefore currently filter all changereplay notifications (see above).
0088         // QCOMPARE(statusNotifications.at(3).code, static_cast<int>(Sink::ApplicationDomain::Status::BusyStatus));
0089         // QCOMPARE(statusNotifications.at(4).code, static_cast<int>(Sink::ApplicationDomain::Status::ConnectedStatus));
0090 
0091         QTRY_COMPARE(infoNotifications.size(), 2);
0092         QCOMPARE(infoNotifications.at(0).code, static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress));
0093         QCOMPARE(infoNotifications.at(0).entities, QList<QByteArray>{} << "id1" << "id2");
0094         QCOMPARE(infoNotifications.at(1).code, static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess));
0095         QCOMPARE(infoNotifications.at(1).entities, QList<QByteArray>{} << "id1" << "id2");
0096 
0097         QCOMPARE(infoNotifications.at(1).code, static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess));
0098     }
0099 
0100     void testModelNotifications()
0101     {
0102         auto query = Query().resourceFilter("sink.dummy.instance1");
0103         query.setType<ApplicationDomain::Mail>();
0104         query.setFlags(Query::LiveQuery | Query::UpdateStatus);
0105 
0106         VERIFYEXEC(Sink::Store::synchronize(query));
0107         VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1"));
0108 
0109         auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
0110         QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
0111         QVERIFY(model->rowCount() >= 1);
0112 
0113         QSignalSpy changedSpy(model.data(), &QAbstractItemModel::dataChanged);
0114         auto mail = model->index(0, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).value<Mail::Ptr>();
0115         auto newQuery = query;
0116         newQuery.filter(mail->identifier());
0117 
0118         //We can make no assumptions about the amount of notifications because we collect on every dataChanged signal, even if the status did not change.
0119         QSet<int> status;
0120         QObject::connect(model.data(), &QAbstractItemModel::dataChanged, [&] (const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles) {
0121             QVERIFY(begin.row() == end.row());
0122             if (begin.row() == 0) {
0123                 status << model->data(begin, Store::StatusRole).value<int>();
0124                 // qWarning() << "New status: " << status.last() << roles;
0125             }
0126         });
0127 
0128         //This will trigger a modification of all previous items as well.
0129         VERIFYEXEC(Sink::Store::synchronize(newQuery));
0130         VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1"));
0131 
0132         QTRY_VERIFY(status.contains(static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)) && static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess));
0133     }
0134 
0135     void testNotifier()
0136     {
0137         QList<int> status;
0138         Sink::Notifier notifier{Sink::Query{Sink::Query::LiveQuery}.resourceFilter("sink.dummy.instance2")};
0139         notifier.registerHandler([&] (const Sink::Notification &notification) {
0140             if (notification.type == Notification::Info) {
0141                 status << notification.code;
0142             }
0143         });
0144 
0145         auto query = Query().resourceFilter("sink.dummy.instance2");
0146         query.setType<ApplicationDomain::Mail>();
0147         query.setFlags(Query::LiveQuery | Query::UpdateStatus);
0148 
0149         auto resource = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::SinkResource>("", "sink.dummy.instance2");
0150         resource.setResourceType("sink.dummy");
0151         VERIFYEXEC(Store::create(resource));
0152 
0153         VERIFYEXEC(Sink::Store::synchronize(query));
0154         VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance2"));
0155 
0156         QTRY_COMPARE(status.size(), 2);
0157         //Sync progress of item
0158         QCOMPARE(status.at(0), static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress));
0159         QCOMPARE(status.at(1), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess));
0160     }
0161 
0162 };
0163 
0164 QTEST_MAIN(NotificationTest)
0165 #include "notificationtest.moc"