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

0001 /*
0002     SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "monitortest.h"
0008 #include "agentinstance.h"
0009 #include "agentmanager.h"
0010 #include "collectioncreatejob.h"
0011 #include "collectiondeletejob.h"
0012 #include "collectionfetchjob.h"
0013 #include "collectionmodifyjob.h"
0014 #include "collectionmovejob.h"
0015 #include "collectionstatistics.h"
0016 #include "control.h"
0017 #include "itemcreatejob.h"
0018 #include "itemdeletejob.h"
0019 #include "itemfetchjob.h"
0020 #include "itemfetchscope.h"
0021 #include "itemmodifyjob.h"
0022 #include "itemmovejob.h"
0023 #include "monitor.h"
0024 #include "qtest_akonadi.h"
0025 #include "searchcreatejob.h"
0026 #include "searchquery.h"
0027 #include "subscriptionjob_p.h"
0028 
0029 #include <QSignalSpy>
0030 #include <QVariant>
0031 
0032 using namespace Akonadi;
0033 
0034 QTEST_AKONADIMAIN(MonitorTest)
0035 
0036 static Collection res3;
0037 
0038 Q_DECLARE_METATYPE(Akonadi::Collection::Id)
0039 Q_DECLARE_METATYPE(QSet<QByteArray>)
0040 
0041 void MonitorTest::initTestCase()
0042 {
0043     AkonadiTest::checkTestIsIsolated();
0044     Control::start();
0045 
0046     res3 = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res3")));
0047 
0048     AkonadiTest::setAllResourcesOffline();
0049 }
0050 
0051 void MonitorTest::testMonitor_data()
0052 {
0053     QTest::addColumn<bool>("fetchCol");
0054     QTest::newRow("with collection fetching") << true;
0055     QTest::newRow("without collection fetching") << false;
0056 }
0057 
0058 void MonitorTest::testMonitor()
0059 {
0060     QFETCH(bool, fetchCol);
0061 
0062     Monitor monitor;
0063     monitor.setCollectionMonitored(Collection::root());
0064     monitor.fetchCollection(fetchCol);
0065     monitor.itemFetchScope().fetchFullPayload();
0066     monitor.itemFetchScope().setCacheOnly(true);
0067     QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady));
0068 
0069     // monitor signals
0070     qRegisterMetaType<Akonadi::Collection>();
0071     /*
0072        qRegisterMetaType<Akonadi::Collection::Id>() registers the type with a
0073        name of "qlonglong".  Doing
0074        qRegisterMetaType<Akonadi::Collection::Id>( "Akonadi::Collection::Id" )
0075        doesn't help. (works now , see QTBUG-937 and QTBUG-6833, -- dvratil)
0076 
0077        The problem here is that Akonadi::Collection::Id is a typedef to qlonglong,
0078        and qlonglong is already a registered meta type.  So the signal spy will
0079        give us a QVariant of type Akonadi::Collection::Id, but calling
0080        .value<Akonadi::Collection::Id>() on that variant will in fact end up
0081        calling qvariant_cast<qlonglong>.  From the point of view of QMetaType,
0082        Akonadi::Collection::Id and qlonglong are different types, so QVariant
0083        can't convert, and returns a default-constructed qlonglong, zero.
0084 
0085        When connecting to a real slot (without QSignalSpy), this problem is
0086        avoided, because the casting is done differently (via a lot of void
0087        pointers).
0088 
0089        The docs say nothing about qRegisterMetaType -ing a typedef, so I'm not
0090        sure if this is a bug or not. (cberzan)
0091      */
0092     qRegisterMetaType<Akonadi::Collection::Id>("Akonadi::Collection::Id");
0093     qRegisterMetaType<Akonadi::Item>();
0094     qRegisterMetaType<Akonadi::CollectionStatistics>();
0095     qRegisterMetaType<QSet<QByteArray>>();
0096     QSignalSpy caddspy(&monitor, &Monitor::collectionAdded);
0097     QSignalSpy cmodspy(&monitor, SIGNAL(collectionChanged(Akonadi::Collection, QSet<QByteArray>)));
0098     QSignalSpy cmvspy(&monitor, &Monitor::collectionMoved);
0099     QSignalSpy crmspy(&monitor, &Monitor::collectionRemoved);
0100     QSignalSpy cstatspy(&monitor, &Monitor::collectionStatisticsChanged);
0101     QSignalSpy cSubscribedSpy(&monitor, &Monitor::collectionSubscribed);
0102     QSignalSpy cUnsubscribedSpy(&monitor, &Monitor::collectionUnsubscribed);
0103     QSignalSpy iaddspy(&monitor, &Monitor::itemAdded);
0104     QSignalSpy imodspy(&monitor, &Monitor::itemChanged);
0105     QSignalSpy imvspy(&monitor, &Monitor::itemMoved);
0106     QSignalSpy irmspy(&monitor, &Monitor::itemRemoved);
0107 
0108     QVERIFY(caddspy.isValid());
0109     QVERIFY(cmodspy.isValid());
0110     QVERIFY(cmvspy.isValid());
0111     QVERIFY(crmspy.isValid());
0112     QVERIFY(cstatspy.isValid());
0113     QVERIFY(cSubscribedSpy.isEmpty());
0114     QVERIFY(cUnsubscribedSpy.isEmpty());
0115     QVERIFY(iaddspy.isValid());
0116     QVERIFY(imodspy.isValid());
0117     QVERIFY(imvspy.isValid());
0118     QVERIFY(irmspy.isValid());
0119 
0120     // create a collection
0121     Collection monitorCol;
0122     monitorCol.setParentCollection(res3);
0123     monitorCol.setName(QStringLiteral("monitor"));
0124     auto create = new CollectionCreateJob(monitorCol, this);
0125     AKVERIFYEXEC(create);
0126     monitorCol = create->collection();
0127     QVERIFY(monitorCol.isValid());
0128 
0129     QTRY_COMPARE(caddspy.count(), 1);
0130     QList<QVariant> arg = caddspy.takeFirst();
0131     auto col = arg.at(0).value<Collection>();
0132     QCOMPARE(col, monitorCol);
0133     if (fetchCol) {
0134         QCOMPARE(col.name(), QStringLiteral("monitor"));
0135     }
0136     auto parent = arg.at(1).value<Collection>();
0137     QCOMPARE(parent, res3);
0138 
0139     QVERIFY(cmodspy.isEmpty());
0140     QVERIFY(cmvspy.isEmpty());
0141     QVERIFY(crmspy.isEmpty());
0142     QVERIFY(cstatspy.isEmpty());
0143     QVERIFY(cSubscribedSpy.isEmpty());
0144     QVERIFY(cUnsubscribedSpy.isEmpty());
0145     QVERIFY(iaddspy.isEmpty());
0146     QVERIFY(imodspy.isEmpty());
0147     QVERIFY(imvspy.isEmpty());
0148     QVERIFY(irmspy.isEmpty());
0149 
0150     // add an item
0151     Item newItem;
0152     newItem.setMimeType(QStringLiteral("application/octet-stream"));
0153     auto append = new ItemCreateJob(newItem, monitorCol, this);
0154     AKVERIFYEXEC(append);
0155     Item monitorRef = append->item();
0156     QVERIFY(monitorRef.isValid());
0157 
0158     QTRY_COMPARE(cstatspy.count(), 1);
0159     arg = cstatspy.takeFirst();
0160     QCOMPARE(arg.at(0).value<Akonadi::Collection::Id>(), monitorCol.id());
0161 
0162     QCOMPARE(iaddspy.count(), 1);
0163     arg = iaddspy.takeFirst();
0164     Item item = arg.at(0).value<Item>();
0165     QCOMPARE(item, monitorRef);
0166     QCOMPARE(item.mimeType(), QString::fromLatin1("application/octet-stream"));
0167     auto collection = arg.at(1).value<Collection>();
0168     QCOMPARE(collection.id(), monitorCol.id());
0169 
0170     QVERIFY(caddspy.isEmpty());
0171     QVERIFY(cmodspy.isEmpty());
0172     QVERIFY(cmvspy.isEmpty());
0173     QVERIFY(crmspy.isEmpty());
0174     QVERIFY(cSubscribedSpy.isEmpty());
0175     QVERIFY(cUnsubscribedSpy.isEmpty());
0176     QVERIFY(imodspy.isEmpty());
0177     QVERIFY(imvspy.isEmpty());
0178     QVERIFY(irmspy.isEmpty());
0179 
0180     // modify an item
0181     item.setPayload<QByteArray>("some new content");
0182     auto store = new ItemModifyJob(item, this);
0183     AKVERIFYEXEC(store);
0184 
0185     QTRY_COMPARE(cstatspy.count(), 1);
0186     arg = cstatspy.takeFirst();
0187     QCOMPARE(arg.at(0).value<Collection::Id>(), monitorCol.id());
0188 
0189     QCOMPARE(imodspy.count(), 1);
0190     arg = imodspy.takeFirst();
0191     item = arg.at(0).value<Item>();
0192     QCOMPARE(monitorRef, item);
0193     QVERIFY(item.hasPayload<QByteArray>());
0194     QCOMPARE(item.payload<QByteArray>(), QByteArray("some new content"));
0195     auto parts = arg.at(1).value<QSet<QByteArray>>();
0196     QCOMPARE(parts, QSet<QByteArray>() << "PLD:RFC822");
0197 
0198     QVERIFY(caddspy.isEmpty());
0199     QVERIFY(cmodspy.isEmpty());
0200     QVERIFY(cmvspy.isEmpty());
0201     QVERIFY(crmspy.isEmpty());
0202     QVERIFY(cSubscribedSpy.isEmpty());
0203     QVERIFY(cUnsubscribedSpy.isEmpty());
0204     QVERIFY(iaddspy.isEmpty());
0205     QVERIFY(imvspy.isEmpty());
0206     QVERIFY(irmspy.isEmpty());
0207 
0208     // move an item
0209     auto move = new ItemMoveJob(item, res3);
0210     AKVERIFYEXEC(move);
0211     QTRY_COMPARE(cstatspy.count(), 2);
0212     // NOTE: We don't make any assumptions about the order of the collectionStatisticsChanged
0213     // signals, they seem to arrive in random order
0214     QList<Collection::Id> notifiedCols;
0215     notifiedCols << cstatspy.takeFirst().at(0).value<Collection::Id>() << cstatspy.takeFirst().at(0).value<Collection::Id>();
0216     QVERIFY(notifiedCols.contains(res3.id())); // destination
0217     QVERIFY(notifiedCols.contains(monitorCol.id())); // source
0218 
0219     QCOMPARE(imvspy.count(), 1);
0220     arg = imvspy.takeFirst();
0221     item = arg.at(0).value<Item>(); // the item
0222     QCOMPARE(monitorRef, item);
0223     col = arg.at(1).value<Collection>(); // the source collection
0224     QCOMPARE(col.id(), monitorCol.id());
0225     col = arg.at(2).value<Collection>(); // the destination collection
0226     QCOMPARE(col.id(), res3.id());
0227 
0228     QVERIFY(caddspy.isEmpty());
0229     QVERIFY(cmodspy.isEmpty());
0230     QVERIFY(cmvspy.isEmpty());
0231     QVERIFY(crmspy.isEmpty());
0232     QVERIFY(cSubscribedSpy.isEmpty());
0233     QVERIFY(cUnsubscribedSpy.isEmpty());
0234     QVERIFY(iaddspy.isEmpty());
0235     QVERIFY(imodspy.isEmpty());
0236     QVERIFY(irmspy.isEmpty());
0237 
0238     // delete an item
0239     auto del = new ItemDeleteJob(monitorRef, this);
0240     AKVERIFYEXEC(del);
0241 
0242     QTRY_COMPARE(cstatspy.count(), 1);
0243     arg = cstatspy.takeFirst();
0244     QCOMPARE(arg.at(0).value<Collection::Id>(), res3.id());
0245     cmodspy.clear();
0246 
0247     QCOMPARE(irmspy.count(), 1);
0248     arg = irmspy.takeFirst();
0249     Item ref = qvariant_cast<Item>(arg.at(0));
0250     QCOMPARE(monitorRef, ref);
0251     QCOMPARE(ref.parentCollection(), res3);
0252 
0253     QVERIFY(caddspy.isEmpty());
0254     QVERIFY(cmodspy.isEmpty());
0255     QVERIFY(cmvspy.isEmpty());
0256     QVERIFY(crmspy.isEmpty());
0257     QVERIFY(cSubscribedSpy.isEmpty());
0258     QVERIFY(cUnsubscribedSpy.isEmpty());
0259     QVERIFY(iaddspy.isEmpty());
0260     QVERIFY(imodspy.isEmpty());
0261     QVERIFY(imvspy.isEmpty());
0262     imvspy.clear();
0263 
0264     // Unsubscribe and re-subscribed a collection that existed before the monitor was created.
0265     Collection subCollection = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res2/foo2")));
0266     subCollection.setName(QStringLiteral("foo2"));
0267     QVERIFY(subCollection.isValid());
0268 
0269     auto subscribeJob = new SubscriptionJob(this);
0270     subscribeJob->unsubscribe(Collection::List() << subCollection);
0271     AKVERIFYEXEC(subscribeJob);
0272     // Wait for unsubscribed signal, it goes after changed, so we can check for both
0273     QTRY_COMPARE(cmodspy.size(), 1);
0274     arg = cmodspy.takeFirst();
0275     col = arg.at(0).value<Collection>();
0276     QCOMPARE(col.id(), subCollection.id());
0277 
0278     QVERIFY(cSubscribedSpy.isEmpty());
0279     QTRY_COMPARE(cUnsubscribedSpy.size(), 1);
0280     arg = cUnsubscribedSpy.takeFirst();
0281     col = arg.at(0).value<Collection>();
0282     QCOMPARE(col.id(), subCollection.id());
0283 
0284     subscribeJob = new SubscriptionJob(this);
0285     subscribeJob->subscribe(Collection::List() << subCollection);
0286     AKVERIFYEXEC(subscribeJob);
0287     // Wait for subscribed signal, it goes after changed, so we can check for both
0288     QTRY_COMPARE(cmodspy.size(), 1);
0289     arg = cmodspy.takeFirst();
0290     col = arg.at(0).value<Collection>();
0291     QCOMPARE(col.id(), subCollection.id());
0292 
0293     QVERIFY(cUnsubscribedSpy.isEmpty());
0294     QTRY_COMPARE(cSubscribedSpy.size(), 1);
0295     arg = cSubscribedSpy.takeFirst();
0296     col = arg.at(0).value<Collection>();
0297     QCOMPARE(col.id(), subCollection.id());
0298     if (fetchCol) {
0299         QVERIFY(!col.name().isEmpty());
0300         QCOMPARE(col.name(), subCollection.name());
0301     }
0302 
0303     QVERIFY(caddspy.isEmpty());
0304     QVERIFY(cmodspy.isEmpty());
0305     QVERIFY(cmvspy.isEmpty());
0306     QVERIFY(crmspy.isEmpty());
0307     QVERIFY(cstatspy.isEmpty());
0308     QVERIFY(iaddspy.isEmpty());
0309     QVERIFY(imodspy.isEmpty());
0310     QVERIFY(imvspy.isEmpty());
0311     QVERIFY(irmspy.isEmpty());
0312 
0313     // modify a collection
0314     monitorCol.setName(QStringLiteral("changed name"));
0315     auto mod = new CollectionModifyJob(monitorCol, this);
0316     AKVERIFYEXEC(mod);
0317 
0318     QTRY_COMPARE(cmodspy.count(), 1);
0319     arg = cmodspy.takeFirst();
0320     col = arg.at(0).value<Collection>();
0321     QCOMPARE(col, monitorCol);
0322     if (fetchCol) {
0323         QCOMPARE(col.name(), QStringLiteral("changed name"));
0324     }
0325 
0326     QVERIFY(caddspy.isEmpty());
0327     QVERIFY(cmvspy.isEmpty());
0328     QVERIFY(crmspy.isEmpty());
0329     QVERIFY(cstatspy.isEmpty());
0330     QVERIFY(cSubscribedSpy.isEmpty());
0331     QVERIFY(cUnsubscribedSpy.isEmpty());
0332     QVERIFY(iaddspy.isEmpty());
0333     QVERIFY(imodspy.isEmpty());
0334     QVERIFY(imvspy.isEmpty());
0335     QVERIFY(irmspy.isEmpty());
0336 
0337     // move a collection
0338     Collection dest = Collection(AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo")));
0339     auto cmove = new CollectionMoveJob(monitorCol, dest, this);
0340     AKVERIFYEXEC(cmove);
0341 
0342     QTRY_COMPARE(cmvspy.count(), 1);
0343     arg = cmvspy.takeFirst();
0344     col = arg.at(0).value<Collection>();
0345     QCOMPARE(col, monitorCol);
0346     QCOMPARE(col.parentCollection(), dest);
0347     if (fetchCol) {
0348         QCOMPARE(col.name(), monitorCol.name());
0349     }
0350     col = arg.at(1).value<Collection>();
0351     QCOMPARE(col, res3);
0352     col = arg.at(2).value<Collection>();
0353     QCOMPARE(col, dest);
0354 
0355     QVERIFY(caddspy.isEmpty());
0356     QVERIFY(cmodspy.isEmpty());
0357     QVERIFY(crmspy.isEmpty());
0358     QVERIFY(cstatspy.isEmpty());
0359     QVERIFY(cSubscribedSpy.isEmpty());
0360     QVERIFY(cUnsubscribedSpy.isEmpty());
0361     QVERIFY(iaddspy.isEmpty());
0362     QVERIFY(imodspy.isEmpty());
0363     QVERIFY(imvspy.isEmpty());
0364     QVERIFY(irmspy.isEmpty());
0365 
0366     // delete a collection
0367     auto cdel = new CollectionDeleteJob(monitorCol, this);
0368     AKVERIFYEXEC(cdel);
0369 
0370     QTRY_COMPARE(crmspy.count(), 1);
0371     arg = crmspy.takeFirst();
0372     col = arg.at(0).value<Collection>();
0373     QCOMPARE(col.id(), monitorCol.id());
0374     QCOMPARE(col.parentCollection(), dest);
0375 
0376     QVERIFY(caddspy.isEmpty());
0377     QVERIFY(cmodspy.isEmpty());
0378     QVERIFY(cmvspy.isEmpty());
0379     QVERIFY(cstatspy.isEmpty());
0380     QVERIFY(cSubscribedSpy.isEmpty());
0381     QVERIFY(cUnsubscribedSpy.isEmpty());
0382     QVERIFY(iaddspy.isEmpty());
0383     QVERIFY(imodspy.isEmpty());
0384     QVERIFY(imvspy.isEmpty());
0385     QVERIFY(irmspy.isEmpty());
0386 }
0387 
0388 void MonitorTest::testVirtualCollectionsMonitoring()
0389 {
0390     Monitor monitor;
0391     monitor.setCollectionMonitored(Collection(1)); // top-level 'Search' collection
0392     QVERIFY(AkonadiTest::akWaitForSignal(&monitor, &Monitor::monitorReady));
0393 
0394     QSignalSpy caddspy(&monitor, &Monitor::collectionAdded);
0395 
0396     auto job = new SearchCreateJob(QStringLiteral("Test search collection"), Akonadi::SearchQuery(), this);
0397     AKVERIFYEXEC(job);
0398     QTRY_COMPARE(caddspy.count(), 1);
0399 }
0400 
0401 #include "moc_monitortest.cpp"