File indexing completed on 2024-11-10 04:40:21

0001 /*
0002     SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "aktest.h"
0008 
0009 #include "entities.h"
0010 #include "notificationsubscriber.h"
0011 
0012 #include <QObject>
0013 #include <QTest>
0014 
0015 using namespace Akonadi;
0016 using namespace Akonadi::Server;
0017 
0018 Q_DECLARE_METATYPE(QList<QString>)
0019 
0020 class TestableNotificationSubscriber : public NotificationSubscriber
0021 {
0022 public:
0023     TestableNotificationSubscriber()
0024     {
0025         mSubscriber = "TestSubscriber";
0026     }
0027 
0028     void setAllMonitored(bool allMonitored)
0029     {
0030         mAllMonitored = allMonitored;
0031     }
0032 
0033     void setMonitoredCollection(qint64 collection, bool monitored)
0034     {
0035         if (monitored) {
0036             mMonitoredCollections.insert(collection);
0037         } else {
0038             mMonitoredCollections.remove(collection);
0039         }
0040     }
0041 
0042     void setMonitoredItem(qint64 item, bool monitored)
0043     {
0044         if (monitored) {
0045             mMonitoredItems.insert(item);
0046         } else {
0047             mMonitoredItems.remove(item);
0048         }
0049     }
0050 
0051     void setMonitoredResource(const QByteArray &resource, bool monitored)
0052     {
0053         if (monitored) {
0054             mMonitoredResources.insert(resource);
0055         } else {
0056             mMonitoredResources.remove(resource);
0057         }
0058     }
0059 
0060     void setMonitoredMimeType(const QString &mimeType, bool monitored)
0061     {
0062         if (monitored) {
0063             mMonitoredMimeTypes.insert(mimeType);
0064         } else {
0065             mMonitoredMimeTypes.remove(mimeType);
0066         }
0067     }
0068 
0069     void setIgnoredSession(const QByteArray &session, bool ignored)
0070     {
0071         if (ignored) {
0072             mIgnoredSessions.insert(session);
0073         } else {
0074             mIgnoredSessions.remove(session);
0075         }
0076     }
0077 
0078     void writeNotification(const Protocol::ChangeNotificationPtr &notification) override
0079     {
0080         emittedNotifications << notification;
0081     }
0082 
0083     Protocol::ChangeNotificationList emittedNotifications;
0084 };
0085 
0086 class NotificationSubscriberTest : public QObject
0087 {
0088     Q_OBJECT
0089 
0090     using NSList = QList<NotificationSubscriber *>;
0091 
0092     Protocol::FetchItemsResponse itemResponse(qint64 id, const QString &rid, const QString &rrev, const QString &mt)
0093     {
0094         Protocol::FetchItemsResponse item;
0095         item.setId(id);
0096         item.setRemoteId(rid);
0097         item.setRemoteRevision(rrev);
0098         item.setMimeType(mt);
0099         return item;
0100     }
0101 
0102 private Q_SLOTS:
0103     void testSourceFilter_data()
0104     {
0105         qRegisterMetaType<Protocol::ChangeNotificationList>();
0106 
0107         QTest::addColumn<bool>("allMonitored");
0108         QTest::addColumn<QList<Entity::Id>>("monitoredCollections");
0109         QTest::addColumn<QList<Entity::Id>>("monitoredItems");
0110         QTest::addColumn<QList<QByteArray>>("monitoredResources");
0111         QTest::addColumn<QList<QString>>("monitoredMimeTypes");
0112         QTest::addColumn<QList<QByteArray>>("ignoredSessions");
0113         QTest::addColumn<Protocol::ChangeNotificationPtr>("notification");
0114         QTest::addColumn<bool>("accepted");
0115 
0116 #define EmptyList(T) (QList<T>())
0117 #define List(T, x) (QList<T>() << (x))
0118 
0119         auto itemMsg = Protocol::ItemChangeNotificationPtr::create();
0120         itemMsg->setOperation(Protocol::ItemChangeNotification::Add);
0121         itemMsg->setParentCollection(1);
0122         QTest::newRow("monitorAll vs notification without items")
0123             << true << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << EmptyList(QString) << EmptyList(QByteArray)
0124             << itemMsg.staticCast<Protocol::ChangeNotification>() << false;
0125 
0126         itemMsg = Protocol::ItemChangeNotificationPtr::create(*itemMsg);
0127         itemMsg->setItems({itemResponse(1, QString(), QString(), QStringLiteral("message/rfc822"))});
0128         QTest::newRow("monitorAll vs notification with one item")
0129             << true << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << EmptyList(QString) << EmptyList(QByteArray)
0130             << itemMsg.staticCast<Protocol::ChangeNotification>() << true;
0131 
0132         QTest::newRow("item monitored but different mimetype")
0133             << false << EmptyList(Entity::Id) << List(Entity::Id, 1 << 2) << EmptyList(QByteArray) << List(QString, QStringLiteral("random/mimetype"))
0134             << EmptyList(QByteArray) << Protocol::ItemChangeNotificationPtr::create(*itemMsg).staticCast<Protocol::ChangeNotification>() << false;
0135 
0136         QTest::newRow("item not monitored, but mimetype matches")
0137             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << List(QString, QStringLiteral("message/rfc822"))
0138             << EmptyList(QByteArray) << Protocol::ItemChangeNotificationPtr::create(*itemMsg).staticCast<Protocol::ChangeNotification>() << true;
0139 
0140         itemMsg = Protocol::ItemChangeNotificationPtr::create(*itemMsg);
0141         itemMsg->setSessionId("testSession");
0142         QTest::newRow("item monitored but session ignored")
0143             << false << EmptyList(Entity::Id) << List(Entity::Id, 1) << EmptyList(QByteArray) << EmptyList(QString) << List(QByteArray, "testSession")
0144             << itemMsg.staticCast<Protocol::ChangeNotification>() << false;
0145 
0146         // Simulate adding a new resource
0147         auto colMsg = Protocol::CollectionChangeNotificationPtr::create();
0148         colMsg->setOperation(Protocol::CollectionChangeNotification::Add);
0149         Protocol::FetchCollectionsResponse col;
0150         col.setId(1);
0151         col.setRemoteId(QStringLiteral("imap://user@some.domain/"));
0152         colMsg->setCollection(std::move(col));
0153         colMsg->setParentCollection(0);
0154         colMsg->setSessionId("akonadi_imap_resource_0");
0155         colMsg->setResource("akonadi_imap_resource_0");
0156         QTest::newRow("new root collection in non-monitored resource")
0157             << false << List(Entity::Id, 0) << EmptyList(Entity::Id) << List(QByteArray, "akonadi_search_resource")
0158             << List(QString, QStringLiteral("message/rfc822")) << EmptyList(QByteArray) << colMsg.staticCast<Protocol::ChangeNotification>() << true;
0159 
0160         itemMsg = Protocol::ItemChangeNotificationPtr::create();
0161         itemMsg->setOperation(Protocol::ItemChangeNotification::Move);
0162         itemMsg->setResource("akonadi_resource_1");
0163         itemMsg->setDestinationResource("akonadi_resource_2");
0164         itemMsg->setParentCollection(1);
0165         itemMsg->setParentDestCollection(2);
0166         itemMsg->setSessionId("kmail");
0167         itemMsg->setItems({itemResponse(10, QStringLiteral("123"), QStringLiteral("1"), QStringLiteral("message/rfc822"))});
0168         QTest::newRow("inter-resource move, source source") << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << List(QByteArray, "akonadi_resource_1")
0169                                                             << List(QString, QStringLiteral("message/rfc822")) << List(QByteArray, "akonadi_resource_1")
0170                                                             << itemMsg.staticCast<Protocol::ChangeNotification>() << true;
0171 
0172         QTest::newRow("inter-resource move, destination source")
0173             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << List(QByteArray, "akonadi_resource_2")
0174             << List(QString, QStringLiteral("message/rfc822")) << List(QByteArray, "akonadi_resource_2") << itemMsg.staticCast<Protocol::ChangeNotification>()
0175             << true;
0176 
0177         QTest::newRow("inter-resource move, uninterested party")
0178             << false << List(Entity::Id, 12) << EmptyList(Entity::Id) << EmptyList(QByteArray) << List(QString, QStringLiteral("inode/directory"))
0179             << EmptyList(QByteArray) << itemMsg.staticCast<Protocol::ChangeNotification>() << false;
0180 
0181         itemMsg = Protocol::ItemChangeNotificationPtr::create();
0182         itemMsg->setOperation(Protocol::ItemChangeNotification::Move);
0183         itemMsg->setResource("akonadi_resource_0");
0184         itemMsg->setDestinationResource("akonadi_resource_0");
0185         itemMsg->setParentCollection(1);
0186         itemMsg->setParentDestCollection(2);
0187         itemMsg->setSessionId("kmail");
0188         itemMsg->setItems({itemResponse(10, QStringLiteral("123"), QStringLiteral("1"), QStringLiteral("message/rfc822")),
0189                            itemResponse(11, QStringLiteral("456"), QStringLiteral("1"), QStringLiteral("message/rfc822"))});
0190         QTest::newRow("intra-resource move, owning resource")
0191             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << List(QByteArray, "akonadi_imap_resource_0")
0192             << List(QString, QStringLiteral("message/rfc822")) << List(QByteArray, "akonadi_imap_resource_0")
0193             << itemMsg.staticCast<Protocol::ChangeNotification>() << true;
0194 
0195         colMsg = Protocol::CollectionChangeNotificationPtr::create();
0196         colMsg->setOperation(Protocol::CollectionChangeNotification::Add);
0197         colMsg->setSessionId("kmail");
0198         colMsg->setResource("akonadi_resource_1");
0199         colMsg->setParentCollection(1);
0200         QTest::newRow("new subfolder") << false << List(Entity::Id, 0) << EmptyList(Entity::Id) << EmptyList(QByteArray)
0201                                        << List(QString, QStringLiteral("message/rfc822")) << EmptyList(QByteArray)
0202                                        << colMsg.staticCast<Protocol::ChangeNotification>() << false;
0203 
0204         itemMsg = Protocol::ItemChangeNotificationPtr::create();
0205         itemMsg->setOperation(Protocol::ItemChangeNotification::Add);
0206         itemMsg->setSessionId("randomSession");
0207         itemMsg->setResource("randomResource");
0208         itemMsg->setParentCollection(1);
0209         itemMsg->setItems({itemResponse(10, QString(), QString(), QStringLiteral("message/rfc822"))});
0210         QTest::newRow("new mail for mailfilter or maildispatcher")
0211             << false << List(Entity::Id, 0) << EmptyList(Entity::Id) << EmptyList(QByteArray) << List(QString, QStringLiteral("message/rfc822"))
0212             << EmptyList(QByteArray) << itemMsg.staticCast<Protocol::ChangeNotification>() << true;
0213 
0214         auto tagMsg = Protocol::TagChangeNotificationPtr::create();
0215         tagMsg->setOperation(Protocol::TagChangeNotification::Remove);
0216         tagMsg->setSessionId("randomSession");
0217         tagMsg->setResource("akonadi_random_resource_0");
0218         {
0219             Protocol::FetchTagsResponse tagMsgTag;
0220             tagMsgTag.setId(1);
0221             tagMsgTag.setRemoteId("TAG");
0222             tagMsg->setTag(std::move(tagMsgTag));
0223         }
0224         QTest::newRow("Tag removal - resource notification - matching resource source")
0225             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << EmptyList(QString)
0226             << List(QByteArray, "akonadi_random_resource_0") << tagMsg.staticCast<Protocol::ChangeNotification>() << true;
0227 
0228         QTest::newRow("Tag removal - resource notification - wrong resource source")
0229             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << EmptyList(QString)
0230             << List(QByteArray, "akonadi_another_resource_1") << tagMsg.staticCast<Protocol::ChangeNotification>() << false;
0231 
0232         tagMsg = Protocol::TagChangeNotificationPtr::create();
0233         tagMsg->setOperation(Protocol::TagChangeNotification::Remove);
0234         tagMsg->setSessionId("randomSession");
0235         {
0236             Protocol::FetchTagsResponse tagMsgTag;
0237             tagMsgTag.setId(1);
0238             tagMsgTag.setRemoteId("TAG");
0239             tagMsg->setTag(std::move(tagMsgTag));
0240         }
0241         QTest::newRow("Tag removal - client notification - client source")
0242             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << EmptyList(QString) << EmptyList(QByteArray)
0243             << tagMsg.staticCast<Protocol::ChangeNotification>() << true;
0244 
0245         QTest::newRow("Tag removal - client notification - resource source")
0246             << false << EmptyList(Entity::Id) << EmptyList(Entity::Id) << EmptyList(QByteArray) << EmptyList(QString)
0247             << List(QByteArray, "akonadi_some_resource_0") << tagMsg.staticCast<Protocol::ChangeNotification>() << false;
0248     }
0249 
0250     void testSourceFilter()
0251     {
0252         QFETCH(bool, allMonitored);
0253         QFETCH(QList<Entity::Id>, monitoredCollections);
0254         QFETCH(QList<Entity::Id>, monitoredItems);
0255         QFETCH(QList<QByteArray>, monitoredResources);
0256         QFETCH(QList<QString>, monitoredMimeTypes);
0257         QFETCH(QList<QByteArray>, ignoredSessions);
0258         QFETCH(Protocol::ChangeNotificationPtr, notification);
0259         QFETCH(bool, accepted);
0260 
0261         TestableNotificationSubscriber subscriber;
0262 
0263         subscriber.setAllMonitored(allMonitored);
0264         for (Entity::Id id : monitoredCollections) {
0265             subscriber.setMonitoredCollection(id, true);
0266         }
0267         for (Entity::Id id : monitoredItems) {
0268             subscriber.setMonitoredItem(id, true);
0269         }
0270         for (const QByteArray &res : monitoredResources) {
0271             subscriber.setMonitoredResource(res, true);
0272         }
0273         for (const QString &mimeType : monitoredMimeTypes) {
0274             subscriber.setMonitoredMimeType(mimeType, true);
0275         }
0276         for (const QByteArray &session : ignoredSessions) {
0277             subscriber.setIgnoredSession(session, true);
0278         }
0279 
0280         subscriber.notify({notification});
0281 
0282         QTRY_COMPARE(subscriber.emittedNotifications.count(), accepted ? 1 : 0);
0283 
0284         if (accepted) {
0285             const Protocol::ChangeNotificationPtr ntf = subscriber.emittedNotifications.at(0);
0286             QVERIFY(ntf->isValid());
0287         }
0288     }
0289 };
0290 
0291 AKTEST_MAIN(NotificationSubscriberTest)
0292 
0293 #include "notificationsubscribertest.moc"